From 97ee488392b3a5d13de677f73f55800327ae8653 Mon Sep 17 00:00:00 2001 From: ashargorodsk Date: Sat, 9 Apr 2022 18:25:32 +0300 Subject: [PATCH 01/46] Failed to save the output of query in csv file when there are commas in file name Description: added "output_file" to excluded flags in function verifying number of args Tested OS: Linux Tested devices: cables connected to a Quantum switch Tested flows: flint query output to csv Known gaps (with RM ticket): N/A Issue: 2972263 Change-Id: I9ab88262a6b3df3902bf95435f338fdba77eadf1 Signed-off-by: Matan Eliyahu --- flint/cmd_line_parser.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/flint/cmd_line_parser.cpp b/flint/cmd_line_parser.cpp index 5f508e8f..2d0881fb 100644 --- a/flint/cmd_line_parser.cpp +++ b/flint/cmd_line_parser.cpp @@ -318,6 +318,9 @@ bool verifyNumOfArgs(string name, string value) if (name == "vsd") { return true; } + if (name == "output_file") { + return true; + } int expected = FlagMetaData().getNumOfArgs(name); if (expected < 0) { From 8f2cf0b4cbf877870c93b0fa94c808c2c3c4f0d2 Mon Sep 17 00:00:00 2001 From: ashargorodsk Date: Thu, 14 Apr 2022 17:19:11 +0300 Subject: [PATCH 02/46] Wrong default value for '--activate_delay_sec' in help menu Description: changed the default value in flint help menu Tested OS: Linux Tested devices: N/A Tested flows: flint --help Known gaps (with RM ticket): N/A Issue: 2691148 Change-Id: I42df02367997456c99a7173c0bfceb3cad301fd2 Signed-off-by: Matan Eliyahu --- flint/cmd_line_parser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flint/cmd_line_parser.cpp b/flint/cmd_line_parser.cpp index 2d0881fb..b765d79c 100644 --- a/flint/cmd_line_parser.cpp +++ b/flint/cmd_line_parser.cpp @@ -878,7 +878,7 @@ void Flint::initCmdParser() AddOptions("activate_delay_sec", ' ', "", - "Use this flag to activate all cable devices connected to host with delay, acceptable values are between 0 and 255 (default - 0, immediately). Important: 'activate' flag must be set. This flag is relevant only for cable components.", + "Use this flag to activate all cable devices connected to host with delay, acceptable values are between 0 and 255 (default - 1). Important: 'activate' flag must be set. This flag is relevant only for cable components.", false, false, 1); From 46067a36fe55bcfb5be939626dde511ff32e7b61 Mon Sep 17 00:00:00 2001 From: Matan Eliyahu Date: Sun, 17 Apr 2022 14:18:40 +0300 Subject: [PATCH 03/46] In case of switch device determine if dev-secure based on new 'dev_sc' field in MGIR Description: Since switches used MGIR's 'dev' field to indicate dev-branch (instead of dev-secure) a new field added to MGIR called 'dev_sc' to indicate the device is dev-secure. For NICs both fields are the same Tested OS: N/A Tested devices: N/A Tested flows: N/A Known gaps (with RM ticket): N/A Issue: 2858050 Change-Id: I7159d699644389fe056cfaa18220ffd9aa6672be Signed-off-by: Matan Eliyahu --- fw_comps_mgr/Makefile.am | 3 ++- fw_comps_mgr/fw_comps_mgr.cpp | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/fw_comps_mgr/Makefile.am b/fw_comps_mgr/Makefile.am index ccd1fe58..1e7449ca 100755 --- a/fw_comps_mgr/Makefile.am +++ b/fw_comps_mgr/Makefile.am @@ -41,9 +41,10 @@ LAYOUTS_DIR = $(USER_DIR)/tools_layouts UTILS_DIR = $(USER_DIR)/mft_utils MAD_IFC_DIR = $(USER_DIR)/mad_ifc TOOLS_RES_MGMT_DIR = $(USER_DIR)/tools_res_mgmt +DEV_MGT_DIR = $(USER_DIR)/dev_mgt INCLUDES = -I. -I$(USER_DIR) -I$(MTCR_INC_DIR) -I$(MTCR_DIR) -I$(REG_ACCESS_DIR) -I$(CMDIF_DIR) \ - -I$(COMMON_DIR) -I $(LAYOUTS_DIR) -I $(UTILS_DIR) -I$(TOOLS_RES_MGMT_DIR) + -I$(COMMON_DIR) -I $(LAYOUTS_DIR) -I $(UTILS_DIR) -I$(TOOLS_RES_MGMT_DIR) -I$(DEV_MGT_DIR) FWCOMPS_VERSION = 1 diff --git a/fw_comps_mgr/fw_comps_mgr.cpp b/fw_comps_mgr/fw_comps_mgr.cpp index e77af115..f541f7b2 100644 --- a/fw_comps_mgr/fw_comps_mgr.cpp +++ b/fw_comps_mgr/fw_comps_mgr.cpp @@ -44,6 +44,7 @@ #include #include "mflash/mflash_access_layer.h" +#include "dev_mgt/tools_dev_types.h" #ifndef UEFI_BUILD #include #include "mad_ifc/mad_ifc.h" @@ -1786,6 +1787,19 @@ bool FwCompsMgr::queryFwInfo(fwInfoT *query, bool next_boot_fw_ver) query->encryption = mgir.fw_info.encryption; query->signed_fw = _compsQueryMap[FwComponent::COMPID_BOOT_IMG].comp_cap.signed_updates_only; + // Since in switches MGIR 'dev' field is used to indicate dev-branch instead of the original purpose for dev-secure, + // we now read from a new field called 'dev_sc' to determine if the switch is dev-secure + dm_dev_id_t dm_device_id = DeviceUnknown; + if (dm_get_device_id_offline(query->hw_dev_id, query->rev_id, &dm_device_id) == ME_OK) { + if (dm_dev_is_switch(dm_device_id)) { + query->security_type.dev_fw = mgir.fw_info.dev_sc; + } + } + else { + _lastError = FWCOMPS_UNSUPPORTED_DEVICE; + return false; + } + query->base_mac_orig.uid = ((u_int64_t)mgir.hw_info.manufacturing_base_mac_47_32 << 32 | mgir.hw_info.manufacturing_base_mac_31_0); if (!extractMacsGuids(query)) { /* From 6865c41f807c5d64ef02791b7efbd8f483bf8163 Mon Sep 17 00:00:00 2001 From: Roei Yitzhak Date: Tue, 19 Apr 2022 10:30:36 +0300 Subject: [PATCH 04/46] Bug fix: dynamic loading of mtcr in mtcr.py on Windows Description: Due to an update of Python version for Pyinstaller the .dll loading should get full path instead of relative path Tested OS:Windows Tested devices: Tested flows:mlxfwreset reset Known gaps (with RM ticket): Issue: 3044246 Change-Id: I48170c9184a27460c8619f88c13016a5b409a03c Signed-off-by: Matan Eliyahu --- mtcr_py/mtcr.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mtcr_py/mtcr.py b/mtcr_py/mtcr.py index 423e6a8c..bd8cd646 100644 --- a/mtcr_py/mtcr.py +++ b/mtcr_py/mtcr.py @@ -58,7 +58,10 @@ class CmdIfException(Exception): from ctypes import * ctypes.CDLL._func_restype_ = ctypes.c_ulonglong if platform.system() == "Windows" or os.name == "nt": - CMTCR = CDLL(".\\libmtcr-1.dll", use_errno=True) + try: + CMTCR = CDLL("libmtcr-1.dll", use_errno=True) + except: + CMTCR = CDLL(os.path.join(os.path.dirname(os.path.realpath(__file__)), "libmtcr-1.dll"), use_errno=True) else: try: CMTCR = CDLL("cmtcr.so", use_errno=True) From 040eae785ac0ad226f2c41397a90cfe8f1ac371b Mon Sep 17 00:00:00 2001 From: Matan Eliyahu Date: Wed, 29 Jun 2022 12:18:34 +0300 Subject: [PATCH 05/46] [mlxfwreset] bug fix - prevent running only `reset` command in secure boot Description: The tool will allow running query in case of secure boot host Tested OS:Linux Tested devices: Tested flows:mlxfwreset Known gaps (with RM ticket): Issue:3049307 --- small_utils/mstfwreset.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/small_utils/mstfwreset.py b/small_utils/mstfwreset.py index 3849b2fd..ee93b513 100644 --- a/small_utils/mstfwreset.py +++ b/small_utils/mstfwreset.py @@ -1649,8 +1649,8 @@ def check_positive_float(val): global DevDBDF global FWResetStatusChecker - if args.reset_sync == SyncOwner.TOOL and is_uefi_secureboot(): # The tool is using sysfs to access PCI config and it's - raise RuntimeError("The tool is not supported on UEFI Secure Boot") # restricted on UEFI secure boot + if args.reset_sync == SyncOwner.TOOL and command == "reset" and is_uefi_secureboot(): # The tool is using sysfs to access PCI config + raise RuntimeError("The tool is not supported on UEFI Secure Boot") # and it's restricted on UEFI secure boot # Exit in case of virtual-machine (not implemented for FreeBSD and Windows) if command == "reset" and platform.system() == "Linux" and "ppc64" not in platform.machine(): From 581ca47f5917f307ce57de87071ca047a74a57da Mon Sep 17 00:00:00 2001 From: ashargorodsk Date: Sun, 8 May 2022 11:13:03 +0300 Subject: [PATCH 06/46] Coverity issues- subcommands_linkx.cpp Description: resource leak issues and double free Tested OS: linux Tested devices: linkx cables Tested flows: build + query Known gaps (with RM ticket): N/A Issue: None Change-Id: I7888c1b0513581da6b6fd183853f7d67a6d9874d Signed-off-by: Matan Eliyahu --- flint/subcommands_linkx.cpp | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/flint/subcommands_linkx.cpp b/flint/subcommands_linkx.cpp index c79cd4df..5c9ef8aa 100644 --- a/flint/subcommands_linkx.cpp +++ b/flint/subcommands_linkx.cpp @@ -206,11 +206,6 @@ FlintStatus QuerySubCommand::QueryLinkX(string deviceName, string outputFile, st reportErr(true, LINKX_QUERY_DEVICE_NOT_SUPPORTED, deviceName.c_str()); return FLINT_FAILED; } - mfile * mfile = mopen_adv((const char *)deviceName.c_str(), (MType)(MST_DEFAULT)); - if (!mfile) { - reportErr(true, "-E- Failed to open device.\n"); - return FLINT_FAILED; - } FwComponent bootImageComponent; std::vector compsToBurn; for (unsigned int i = 0; i < deviceIds.size(); i++) { @@ -219,6 +214,11 @@ FlintStatus QuerySubCommand::QueryLinkX(string deviceName, string outputFile, st return FLINT_FAILED; } } + mfile * mfile = mopen_adv((const char *)deviceName.c_str(), (MType)(MST_DEFAULT)); + if (!mfile) { + reportErr(true, "-E- Failed to open device.\n"); + return FLINT_FAILED; + } string outPutString; bool isCSV = false; @@ -230,10 +230,10 @@ FlintStatus QuerySubCommand::QueryLinkX(string deviceName, string outputFile, st AddTableHeaderForCSVFormat(outPutString); } + FwCompsMgr fwCompsAccess(mfile, FwCompsMgr::DEVICE_HCA_SWITCH, 0); for (unsigned int i = 0; i < deviceIds.size(); i++) { int deviceIndex = deviceIds[i] + 1; - FwCompsMgr fwCompsAccess(mfile, FwCompsMgr::DEVICE_HCA_SWITCH, deviceIndex); fwCompsAccess.SetIndexAndSize(deviceIndex, 1); comp_status_st ComponentStatus; if (!fwCompsAccess.RefreshComponentsStatus(&ComponentStatus)) { @@ -295,16 +295,17 @@ FlintStatus BurnSubCommand::BurnLinkX(string deviceName, int deviceIndex, int de } if (linkx_auto_update && activationNeeded && activate_delay_sec == 0 && (mfile->flags & MDEVS_IB) != 0) {//IB device if (!askUser("The autoupdate activation process may cause a disconnection from the InBand connection, do you want to continue?")) { + mclose(mfile); return FLINT_FAILED; } } FwComponent bootImageComponent; std::vector compsToBurn; - fwCompsAccess = new FwCompsMgr(mfile, FwCompsMgr::DEVICE_HCA_SWITCH, 0); - fwCompsAccess->GenerateHandle(); - fwCompsAccess->SetIndexAndSize(deviceIndex + 1, deviceSize, linkx_auto_update, activationNeeded, downloadTransferNeeded, activate_delay_sec); - if (!fwCompsAccess->RefreshComponentsStatus()) { - printf("-E- Refresh components failed, error is %s.\n", fwCompsAccess->getLastErrMsg()); + FwCompsMgr fwCompsAccess(mfile, FwCompsMgr::DEVICE_HCA_SWITCH, 0); + fwCompsAccess.GenerateHandle(); + fwCompsAccess.SetIndexAndSize(deviceIndex + 1, deviceSize, linkx_auto_update, activationNeeded, downloadTransferNeeded, activate_delay_sec); + if (!fwCompsAccess.RefreshComponentsStatus()) { + printf("-E- Refresh components failed, error is %s.\n", fwCompsAccess.getLastErrMsg()); return FLINT_FAILED; } @@ -312,24 +313,24 @@ FlintStatus BurnSubCommand::BurnLinkX(string deviceName, int deviceIndex, int de compsToBurn.push_back(bootImageComponent); if (downloadTransferNeeded) { printf("-I- Downloading FW ...\n"); - if (fwCompsAccess->isMCDDSupported()) { + if (fwCompsAccess.isMCDDSupported()) { // Checking if BME is disabled to print indication to user - bool isBmeSet = DMAComponentAccess::isBMESet(fwCompsAccess->getMfileObj()); + bool isBmeSet = DMAComponentAccess::isBMESet(fwCompsAccess.getMfileObj()); if (!isBmeSet) { printf("-W- DMA burning is not supported due to BME is unset (Bus Master Enable).\n"); } } } - if (!fwCompsAccess->burnComponents(compsToBurn, funcAdv)) { - char* err_msg = (char*)fwCompsAccess->getLastErrMsg(); + if (!fwCompsAccess.burnComponents(compsToBurn, funcAdv)) { + char* err_msg = (char*)fwCompsAccess.getLastErrMsg(); bool IbError = (strcmp("Unknown MAD error", err_msg) == 0); if (linkx_auto_update && activationNeeded && activate_delay_sec == 0 && ((mfile->flags & MDEVS_IB) != 0) && IbError) {//IB device - printf("-W- The activation process caused a disconnection from the InBand connection for a few minutes, please wait for reconnection. The error is %s \n", fwCompsAccess->getLastErrMsg()); + printf("-W- The activation process caused a disconnection from the InBand connection for a few minutes, please wait for reconnection. The error is %s \n", fwCompsAccess.getLastErrMsg()); return FLINT_SUCCESS; } else { - printf("-E- Cable burn failed, error is %s.\n", fwCompsAccess->getLastErrMsg()); + printf("-E- Cable burn failed, error is %s.\n", fwCompsAccess.getLastErrMsg()); return FLINT_FAILED; } } From 76137f648040d611401910f30bc640f35b4ac77c Mon Sep 17 00:00:00 2001 From: Matan Eliyahu Date: Wed, 29 Jun 2022 17:25:01 +0300 Subject: [PATCH 07/46] [mlxfwops] Creating SecuredSwitchSignatureManager object in case of SPEC4 instead of RavenSwitchSignatureManager object Description: Since SPEC4 is secured device we need to create the correct object to presents its capabilities Tested OS: N/A Tested devices: N/A Tested flows: N/A Known gaps (with RM ticket): N/A Issue: 3048157 --- mlxfwops/lib/signature_manager_factory.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mlxfwops/lib/signature_manager_factory.h b/mlxfwops/lib/signature_manager_factory.h index a7401a32..a7807496 100644 --- a/mlxfwops/lib/signature_manager_factory.h +++ b/mlxfwops/lib/signature_manager_factory.h @@ -71,10 +71,10 @@ class SignatureManagerFactory else if (deviceId == DeviceConnectX6LX) { return new ConnectX6LXFwOperationsSignatureManager(); } - else if (deviceId == DeviceSpectrum || deviceId == DeviceSpectrum2 || deviceId == DeviceSpectrum3 || deviceId == DeviceSpectrum4 || deviceId == DeviceQuantum) { + else if (deviceId == DeviceSpectrum || deviceId == DeviceSpectrum2 || deviceId == DeviceSpectrum3 || deviceId == DeviceQuantum) { return new RavenSwitchSignatureManager(); } - else if (deviceId == DeviceQuantum2) { + else if (deviceId == DeviceQuantum2 || deviceId == DeviceSpectrum4) { return new SecuredSwitchSignatureManager(); } else { @@ -107,10 +107,10 @@ class SignatureManagerFactory else if (chip == CT_GEARBOX) { return new GearBoxSignatureManager(); } - else if(chip == CT_QUANTUM || chip == CT_SPECTRUM || chip == CT_SPECTRUM2 || chip == CT_SPECTRUM3 || chip == CT_SPECTRUM4) { + else if(chip == CT_QUANTUM || chip == CT_SPECTRUM || chip == CT_SPECTRUM2 || chip == CT_SPECTRUM3) { return new RavenSwitchSignatureManager(); } - else if (chip == CT_QUANTUM2) { + else if (chip == CT_QUANTUM2 || chip == CT_SPECTRUM4) { return new SecuredSwitchSignatureManager(); } else { From da02a119860f0eaac36429ef7a52908c0b4a9b95 Mon Sep 17 00:00:00 2001 From: Mustafa Dalloul Date: Thu, 30 Jun 2022 14:18:10 +0300 Subject: [PATCH 08/46] [mstlink] Fixing cable control params issues Description: -> Fixing negative arguments check -> Fixing rx amplitude configuration -> More validation over arguments Issue: 3067085 Issue: 3042144 Issue: 3038403 Issue: 3066878 Signed-off-by: Mustafa Dalloul --- mlxlink/modules/mlxlink_cables_commander.cpp | 38 ++++++++++++-------- mlxlink/modules/mlxlink_cables_commander.h | 2 +- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/mlxlink/modules/mlxlink_cables_commander.cpp b/mlxlink/modules/mlxlink_cables_commander.cpp index f8ccd8a9..782081d2 100644 --- a/mlxlink/modules/mlxlink_cables_commander.cpp +++ b/mlxlink/modules/mlxlink_cables_commander.cpp @@ -1535,7 +1535,7 @@ void MlxlinkCablesCommander::showControlParams() cout << controlParamsOutput; } -u_int32_t MlxlinkCablesCommander::getPMCRValue(ControlParam paramId, const string& value) +u_int32_t MlxlinkCablesCommander::pmcrStrToValue(ControlParam paramId, const string& value) { double valueToSet = 0; bool invalidConfiguration = false; @@ -1556,9 +1556,7 @@ u_int32_t MlxlinkCablesCommander::getPMCRValue(ControlParam paramId, const strin if (isDecemal && !isCmis && paramId == CABLE_CONTROL_PARAMETERS_SET_RX_EMPH) { - throw MlxRegException("The requested RX Emphasis configuration value is valid for " - "CMIS modules only (pre-emphasis): %s", - value.c_str()); + invalidConfiguration = true; } if (isCmis && paramId == CABLE_CONTROL_PARAMETERS_SET_RX_EMPH) @@ -1571,15 +1569,24 @@ u_int32_t MlxlinkCablesCommander::getPMCRValue(ControlParam paramId, const strin } } - if (valueStr == "0" || valueToSet > MAX_SFF_CODE_VALUE || - (isDecemal && paramId != CABLE_CONTROL_PARAMETERS_SET_RX_EMPH)) + if ((valueToSet < 0) || (valueStr == "0" && paramId != CABLE_CONTROL_PARAMETERS_SET_RX_AMP) || + (valueToSet > MAX_SFF_CODE_VALUE) || (isDecemal && paramId != CABLE_CONTROL_PARAMETERS_SET_RX_EMPH)) { invalidConfiguration = true; } if (invalidConfiguration) { - throw MlxRegException("Invalid %s configuration: %s", _modulePMCRParams[paramId].first.c_str(), value.c_str()); + u_int32_t capVal = getFieldValue(_modulePMCRParams[paramId].second + "_value_cap"); + string capStr = ""; + if (capVal) + { + capStr = "\nSupported configuration values are ["; + capStr += getPMCRCapValueStr(capVal, paramId); + capStr += "]"; + } + throw MlxRegException("Invalid %s configuration: %s %s", _modulePMCRParams[paramId].first.c_str(), + value.c_str(), capStr.c_str()); } return (u_int32_t)valueToSet; @@ -1598,7 +1605,11 @@ string MlxlinkCablesCommander::getPMCRCapValueStr(u_int32_t valueCap, ControlPar char tmpFmt[64]; for (u_int32_t val = 0; val <= valueCap; val++) { - if (_cableIdentifier >= IDENTIFIER_SFP_DD && paramId == CABLE_CONTROL_PARAMETERS_SET_RX_EMPH) + if (val == 0) + { + capStr += "NE,"; + } + else if (_cableIdentifier >= IDENTIFIER_SFP_DD && paramId == CABLE_CONTROL_PARAMETERS_SET_RX_EMPH) { sprintf(tmpFmt, "%.1f,", ((float)val / 2.0)); capStr += string(tmpFmt); @@ -1644,9 +1655,8 @@ void MlxlinkCablesCommander::checkPMCRFieldsCap(vectorfirst].second; - valueToSet = getPMCRValue(it->first, it->second); + valueToSet = pmcrStrToValue(it->first, it->second); valueCap = getFieldValue(fieldName + "_value_cap"); - ; // if (it->first == CABLE_CONTROL_PARAMETERS_SET_RX_AMP) { valueToSet = (u_int32_t)pow(2.0, (double)valueToSet); @@ -1663,19 +1673,19 @@ void MlxlinkCablesCommander::checkPMCRFieldsCap(vectorfirst); validCapStr += "]"; } - throw MlxRegException("Invalid %s configuration value: %s %s", _modulePMCRParams[it->first].first.c_str(), - it->second.c_str(), validCapStr.c_str()); + throw MlxRegException("Not supported %s configuration value: %s %s", + _modulePMCRParams[it->first].first.c_str(), it->second.c_str(), validCapStr.c_str()); } } } void MlxlinkCablesCommander::buildPMCRRequest(ControlParam paramId, const string& value) { - u_int32_t valueToSet = getPMCRValue(paramId, value); + u_int32_t valueToSet = pmcrStrToValue(paramId, value); updateField(_modulePMCRParams[paramId].second + "_cntl", 2); updateField(_modulePMCRParams[paramId].second + "_value", (u_int32_t)valueToSet); diff --git a/mlxlink/modules/mlxlink_cables_commander.h b/mlxlink/modules/mlxlink_cables_commander.h index 569a6028..36f7e7fa 100644 --- a/mlxlink/modules/mlxlink_cables_commander.h +++ b/mlxlink/modules/mlxlink_cables_commander.h @@ -197,7 +197,7 @@ class MlxlinkCablesCommander : public MlxlinkRegParser void enablePMPT(ModuleAccess_t moduleAccess); void disablePMPT(); - u_int32_t getPMCRValue(ControlParam paramId, const string& value); + u_int32_t pmcrStrToValue(ControlParam paramId, const string& value); string getPMCRCapValueStr(u_int32_t valueCap, ControlParam paramId); void checkPMCRFieldsCap(vector>& params); void buildPMCRRequest(ControlParam paramId, const string& value); From e56bb671ce8d54bacccec9c6d66475e2a8416f6f Mon Sep 17 00:00:00 2001 From: Mustafa Dalloul Date: Thu, 30 Jun 2022 14:59:12 +0300 Subject: [PATCH 09/46] [mstlink][Module PRBS] Fixing module prbs issues Description: -> Fixing enabling the PRBS with 10.3125G and 14.0625G rates -> Fixing SNR invalid values -> Fixing invalid flag options combination Issue: 3093445 Issue: 3093462 Issue: 3088639 Signed-off-by: Mustafa Dalloul --- mlxlink/modules/mlxlink_cables_commander.cpp | 4 +- mlxlink/modules/mlxlink_enums.h | 2 +- mlxlink/modules/mlxlink_ui.cpp | 117 +++++++++++-------- 3 files changed, 72 insertions(+), 51 deletions(-) diff --git a/mlxlink/modules/mlxlink_cables_commander.cpp b/mlxlink/modules/mlxlink_cables_commander.cpp index f8ccd8a9..ed6a954b 100644 --- a/mlxlink/modules/mlxlink_cables_commander.cpp +++ b/mlxlink/modules/mlxlink_cables_commander.cpp @@ -1418,7 +1418,7 @@ void MlxlinkCablesCommander::getPMPDInfo(vector& traffic, traficStr = to_string(add32BitTo64(getFieldValue("prbs_bits_high"), getFieldValue("prbs_bits_low"))); errorsStr = to_string(add32BitTo64(getFieldValue("prbs_errors_high"), getFieldValue("prbs_errors_low"))); berStr = to_string(getFieldValue("ber_coef")) + "E-" + to_string(getFieldValue("ber_magnitude")); - snrStr = to_string(getFieldValue("measured_snr")) + " dB"; + snrStr = getFieldValue("measured_snr") ? (to_string(getFieldValue("measured_snr")) + " dB") : "N/A"; traffic.push_back(MlxlinkRecord::addSpaceForModulePrbs(traficStr)); @@ -1435,7 +1435,7 @@ void MlxlinkCablesCommander::getPMPDInfo(vector& traffic, { snr.push_back(MlxlinkRecord::addSpaceForModulePrbs(getFieldValue("snr_cap") ? snrStr : "Not Supported")); } - // Print only one indecation for each cap if it's not supported + // Print only one indication for each cap if it's not supported if (getFieldValue("errors_cap") == 0) { skipErrorCap = true; diff --git a/mlxlink/modules/mlxlink_enums.h b/mlxlink/modules/mlxlink_enums.h index d2f73ab7..ee2eb76c 100644 --- a/mlxlink/modules/mlxlink_enums.h +++ b/mlxlink/modules/mlxlink_enums.h @@ -395,7 +395,7 @@ #define MAX_SBYTE 127 #define MIN_SBYTE -128 -#define MAX_INPUT_LENGTH 7 +#define MAX_INPUT_LENGTH 10 #define SECOND_LEVEL_PORT_ACCESS 2 #define THIRD_LEVEL_PORT_ACCESS 3 diff --git a/mlxlink/modules/mlxlink_ui.cpp b/mlxlink/modules/mlxlink_ui.cpp index 095a5b0d..ca86a43b 100644 --- a/mlxlink/modules/mlxlink_ui.cpp +++ b/mlxlink/modules/mlxlink_ui.cpp @@ -99,23 +99,31 @@ void MlxlinkUi::printSynopsisCommands() "Configure Port State [UP(up)/DN(down)/TG(toggle)]"); MlxlinkRecord::printFlagLine( PTYS_FLAG_SHORT, PTYS_FLAG, "speeds", - "Configure Speeds [NDR,HDR,EDR,FDR10,FDR,QDR,DDR,SDR,400G_8X,200G_4X,100G_2X,50G_1X,100G,100G_4X,50G,50G_2X,25G,40X,10G,2.5G,1G]"); + "Configure Speeds " + "[NDR,HDR,EDR,FDR10,FDR,QDR,DDR,SDR,800G_8X,400G_4X,200G_2X,100G_1X,400G_8X,200G_4X,100G_2X," + "50G_1X,100G,100G_4X,50G,50G_2X,25G,40X,10G,2.5G,1G]"); printf(IDENT); MlxlinkRecord::printFlagLine(PTYS_LINK_MODE_FORCE_FLAG_SHORT, PTYS_LINK_MODE_FORCE_FLAG, "", "Configure Link Mode Force (Disable AN)"); MlxlinkRecord::printFlagLine( PPLR_FLAG_SHORT, PPLR_FLAG, "loopback", - "Configure Loopback Mode [NO(no loopback)/RM(phy remote Rx-to-Tx loopback)/PH(internal phy Tx-to-Rx loopback)/EX(external loopback connector needed)/EX(external Tx-to-Rx loopback)]"); + "Configure Loopback Mode [NO(no loopback)/RM(phy remote Rx-to-Tx loopback)/PH(internal phy Tx-to-Rx " + "loopback)/EX(external loopback connector needed)/EX(external Tx-to-Rx loopback)]"); MlxlinkRecord::printFlagLine( PPLM_FLAG_SHORT, PPLM_FLAG, "fec_override", - "Configure FEC [AU(Auto)/NF(No-FEC)/FC(FireCode FEC)/RS(RS-FEC)/LL(LL-RS-FEC)/DF-RS(Interleaved_RS-FEC)/DF-LL(Interleaved_LL_RS-FEC)]"); + "Configure FEC [AU(Auto)/NF(No-FEC)/FC(FireCode " + "FEC)/RS(RS-FEC)/LL(LL-RS-FEC)/DF-RS(Interleaved_RS-FEC)/DF-LL(Interleaved_LL_RS-FEC)]"); printf(IDENT); - MlxlinkRecord::printFlagLine( - FEC_SPEED_FLAG_SHORT, FEC_SPEED_FLAG, "fec_speed", - "Speed to Configure FEC [100G,56G,50G,40G,25G,10G,800G_8X,400G_4x,400G_8X,200G_2X,200G_4X,100G_2X,50G_1X,100G_4X] (Default is Active Speed)"); - MlxlinkRecord::printFlagLine( - SLTP_SET_FLAG_SHORT, SLTP_SET_FLAG, "params", - "Configure Transmitter Parameters For 16nm devices: [pre2Tap,preTap,mainTap,postTap,m2lp,amp] For 28nm devices: [Pol,tap0,tap1,tap2,bias,preemp_mode]"); + MlxlinkRecord::printFlagLine(FEC_SPEED_FLAG_SHORT, FEC_SPEED_FLAG, "fec_speed", + "Speed to Configure FEC " + "[100G,56G,50G,40G,25G,10G,800G_8X,400G_4x,400G_8X,200G_2X,200G_4X,100G_2X,50G_1X," + "100G_4X] (Default is Active Speed)"); + MlxlinkRecord::printFlagLine(SLTP_SET_FLAG_SHORT, SLTP_SET_FLAG, "params", + "Configure Transmitter Parameters. " + "For 7nm devices (lane rate specifies the valid Parameters): " + "[fir_pre3,fir_pre2,fir_pre1,fir_main,fir_post1], " + "For 16nm devices: [pre2Tap,preTap,mainTap,postTap,m2lp,amp], " + "For 28nm devices: [Pol,tap0,tap1,tap2,bias,preemp_mode]"); printf(IDENT); MlxlinkRecord::printFlagLine(LANE_FLAG_SHORT, LANE_FLAG, "transmitter_lane", "Transmitter Lane to Set (Optional - Default All Lanes)"); @@ -125,7 +133,8 @@ void MlxlinkUi::printSynopsisCommands() printf(IDENT); MlxlinkRecord::printFlagLine( SLTP_TX_POLICY_FLAG_SHORT, SLTP_TX_POLICY_FLAG, "", - "Set the parameters according to Data Base only, otherwise it will be set according to the best possible configuration chosen by the system (e.g. KR-startup) (Optional)"); + "Set the parameters according to Data Base only, otherwise it will be set according to the best possible " + "configuration chosen by the system (e.g. KR-startup) (Optional)"); MlxlinkRecord::printFlagLine(SET_TX_GROUP_MAP_FLAG_SHORT, SET_TX_GROUP_MAP_FLAG, "group_num", "Map ports to group (for Spectrum-2 and Quantum devices)"); printf(IDENT); @@ -134,21 +143,28 @@ void MlxlinkUi::printSynopsisCommands() MlxlinkRecord::printFlagLine(PRBS_MODE_FLAG_SHORT, PRBS_MODE_FLAG, "prbs_mode", "Physical Test Mode Configuration [EN(enable)/DS(disable)/TU(perform tuning)]"); printf(IDENT); - MlxlinkRecord::printFlagLine( - PPRT_PRBS_FLAG_SHORT, PPRT_PRBS_FLAG, "rx_prbs_mode", - "RX PRBS Mode [PRBS31/PRBS23A/PRBS23B/PRBS23C/PRBS23D/PRBS7/PRBS11/PRBS11A/PRBS11B/PRBS11C/PRBS11D/PRBS9/IDLE/SQUARE_WAVEA/SQUARE_WAVEB/SQUARE_WAVEC/SQUARE_WAVED/PRBS13A/PRBS13B/PRBS13C/PRBS13D/SSPR/SSPRQ/LT_frames/PRBS15/PRBS28] (Optional - Default PRBS31)"); + MlxlinkRecord::printFlagLine(PPRT_PRBS_FLAG_SHORT, PPRT_PRBS_FLAG, "rx_prbs_mode", + "RX PRBS Mode " + "[PRBS31/PRBS23A/PRBS23B/PRBS23C/PRBS23D/PRBS7/PRBS11/PRBS11A/PRBS11B/PRBS11C/PRBS11D/" + "PRBS9/IDLE/SQUARE_WAVEA/SQUARE_WAVEB/SQUARE_WAVEC/SQUARE_WAVED/PRBS13A/PRBS13B/" + "PRBS13C/PRBS13D/SSPR/SSPRQ/LT_frames/PRBS15/PRBS28] (Optional - Default PRBS31)"); printf(IDENT); MlxlinkRecord::printFlagLine( PPTT_PRBS_FLAG_SHORT, PPTT_PRBS_FLAG, "tx_prbs_mode", - "TX PRBS Mode [PRBS31/PRBS23A/PRBS23B/PRBS23C/PRBS23D/PRBS7/PRBS11/PRBS11A/PRBS11B/PRBS11C/PRBS11D/PRBS9/IDLE/SQUARE_WAVEA/SQUARE_WAVEB/SQUARE_WAVEC/SQUARE_WAVED/PRBS13A/PRBS13B/PRBS13C/PRBS13D/SSPR/SSPRQ/LT_frames/PRBS15/PRBS28/SQUARE_WAVE3,SQUARE_WAVE13,SQUARE_WAVE30] (Optional - Default PRBS31] (Optional - Default PRBS31)"); + "TX PRBS Mode " + "[PRBS31/PRBS23A/PRBS23B/PRBS23C/PRBS23D/PRBS7/PRBS11/PRBS11A/PRBS11B/PRBS11C/PRBS11D/PRBS9/IDLE/SQUARE_WAVEA/" + "SQUARE_WAVEB/SQUARE_WAVEC/SQUARE_WAVED/PRBS13A/PRBS13B/PRBS13C/PRBS13D/SSPR/SSPRQ/LT_frames/PRBS15/PRBS28/" + "SQUARE_WAVE3,SQUARE_WAVE13,SQUARE_WAVE30] (Optional - Default PRBS31] (Optional - Default PRBS31)"); printf(IDENT); - MlxlinkRecord::printFlagLine( - PPRT_RATE_FLAG_SHORT, PPRT_RATE_FLAG, "rx_lane_rate", - "RX Lane Rate [HDR,EDR,FDR10,FDR,QDR,DDR,SDR,400G_8X,200G_4X,100G_2X,50G_1X,100G,100G_4X,50G,50G_2X,25G,40X,10G,2.5G,1G] (Optional - Default 25G)"); + MlxlinkRecord::printFlagLine(PPRT_RATE_FLAG_SHORT, PPRT_RATE_FLAG, "rx_lane_rate", + "RX Lane Rate " + "[HDR,EDR,FDR10,FDR,QDR,DDR,SDR,400G_8X,200G_4X,100G_2X,50G_1X,100G,100G_4X,50G,50G_" + "2X,25G,40X,10G,2.5G,1G] (Optional - Default 25G)"); printf(IDENT); - MlxlinkRecord::printFlagLine( - PPTT_RATE_FLAG_SHORT, PPTT_RATE_FLAG, "tx_lane_rate", - "TX Lane Rate [HDR,EDR,FDR10,FDR,QDR,DDR,SDR,400G_8X,200G_4X,100G_2X,50G_1X,100G,100G_4X,50G,50G_2X,25G,40X,10G,2.5G,1G] (Optional - Default 25G)"); + MlxlinkRecord::printFlagLine(PPTT_RATE_FLAG_SHORT, PPTT_RATE_FLAG, "tx_lane_rate", + "TX Lane Rate " + "[HDR,EDR,FDR10,FDR,QDR,DDR,SDR,400G_8X,200G_4X,100G_2X,50G_1X,100G,100G_4X,50G,50G_" + "2X,25G,40X,10G,2.5G,1G] (Optional - Default 25G)"); printf(IDENT); MlxlinkRecord::printFlagLine(PRBS_INVERT_TX_POL_FLAG_SHORT, PRBS_INVERT_TX_POL_FLAG, "", "PRBS TX polarity inversion (Optional - Default No Inversion)"); @@ -220,9 +236,9 @@ void MlxlinkUi::printSynopsisCommands() MlxlinkRecord::printFlagLine(CABLE_PRBS_GEN_INV_SHORT, CABLE_PRBS_GEN_INV, "", "Enable PRBS generator inversion (Optional)"); printf(IDENT3); - MlxlinkRecord::printFlagLine( - CABLE_PRBS_GEN_LANES_SHORT, CABLE_PRBS_GEN_LANES, "lanes", - "PRBS generator lanes to set (one or more lane separated by comma)[0,1,2,3,4,5,6,7] (Optional - Default all lanes)"); + MlxlinkRecord::printFlagLine(CABLE_PRBS_GEN_LANES_SHORT, CABLE_PRBS_GEN_LANES, "lanes", + "PRBS generator lanes to set (one or more lane separated by comma)[0,1,2,3,4,5,6,7] " + "(Optional - Default all lanes)"); printf(IDENT3); MlxlinkRecord::printFlagLine( CABLE_PRBS_CH_PAT_SHORT, CABLE_PRBS_CH_PAT, "pattern", @@ -234,13 +250,13 @@ void MlxlinkUi::printSynopsisCommands() MlxlinkRecord::printFlagLine(CABLE_PRBS_CH_INV_SHORT, CABLE_PRBS_CH_INV, "", "Enable PRBS checker inversion (Optional)"); printf(IDENT3); - MlxlinkRecord::printFlagLine( - CABLE_PRBS_CH_LANES_SHORT, CABLE_PRBS_CH_LANES, "lanes", - "PRBS checker lanes to set (one or more lane separated by comma)[0,1,2,3,4,5,6,7] (Optional - Default all lanes)"); + MlxlinkRecord::printFlagLine(CABLE_PRBS_CH_LANES_SHORT, CABLE_PRBS_CH_LANES, "lanes", + "PRBS checker lanes to set (one or more lane separated by comma)[0,1,2,3,4,5,6,7] " + "(Optional - Default all lanes)"); printf(IDENT3); - MlxlinkRecord::printFlagLine( - CABLE_PRBS_LANE_RATE_SHORT, CABLE_PRBS_LANE_RATE, "rate", - "Set PRBS checker and generator lane rate [HDR(50G)(default),1.25G,SDR(2.5G),10.3125G,FDR(14G),EDR(25G),NDR(100G)]"); + MlxlinkRecord::printFlagLine(CABLE_PRBS_LANE_RATE_SHORT, CABLE_PRBS_LANE_RATE, "rate", + "Set PRBS checker and generator lane rate " + "[HDR(50G)(default),1.25G,SDR(2.5G),10.3125G,FDR(14G),EDR(25G),NDR(100G)]"); printf(IDENT2); MlxlinkRecord::printFlagLine(CABLE_PRBS_SHOW_DIAG_SHORT, CABLE_PRBS_SHOW_DIAG, "", "Show PRBS diagnostic counters information"); @@ -252,7 +268,7 @@ void MlxlinkUi::printSynopsisCommands() printf(IDENT2); MlxlinkRecord::printFlagLine( CTRL_PARAM_TX_EQ_FLAG_SHORT, CTRL_PARAM_TX_EQ_FLAG, "value", - "Set Module Tx Input Equalization in dB [NE(No Equalization),1,2,3,4,5,6,7,9,10,11,12]"); + "Set Module Tx Input Equalization in dB [NE(No Equalization),1,2,3,4,5,6,7,8,9,10,11,12]"); printf(IDENT2); MlxlinkRecord::printFlagLine(CTRL_PARAM_RX_EMPH_FLAG_SHORT, CTRL_PARAM_RX_EMPH_FLAG, "value", "Set Module RX Output Emphasis in dB. for CMIS, pre-emphasis value will be set " @@ -267,9 +283,9 @@ void MlxlinkUi::printSynopsisCommands() MlxlinkRecord::printFlagLine(MARGIN_SCAN_FLAG_SHORT, MARGIN_SCAN_FLAG, "", "Read the SerDes eye margins per lane"); printf(IDENT); - MlxlinkRecord::printFlagLine( - EYE_MEASURE_TIME_FLAG_SHORT, EYE_MEASURE_TIME_FLAG, "time", - "Measure time in seconds for single eye [10/30/60/90/120/240/480/600/900] (Optional - Default 60 for PCIe and 30 for Network ports)"); + MlxlinkRecord::printFlagLine(EYE_MEASURE_TIME_FLAG_SHORT, EYE_MEASURE_TIME_FLAG, "time", + "Measure time in seconds for single eye [10/30/60/90/120/240/480/600/900] (Optional - " + "Default 60 for PCIe and 30 for Network ports)"); printf(IDENT); MlxlinkRecord::printFlagLine(EYE_SEL_FLAG_SHORT, EYE_SEL_FLAG, "eye_sel", "Eye selection for PAM4 [UP/MID/DOWN/ALL] (Optional - Default ALL)"); @@ -330,10 +346,9 @@ void MlxlinkUi::printHelp() printf(IDENT2 "%-40s: \n" IDENT3 "%s\n", "Configure Port Speeds", MLXLINK_EXEC " -d -p --speeds 25G,50G,100G"); printf(IDENT2 "%-40s: \n" IDENT3 "%s\n", "Configure FEC", MLXLINK_EXEC " -d -p --fec RS"); - printf( - IDENT2 "%-40s: \n" IDENT3 "%s\n", "Configure Port for Physical Test Mode", - MLXLINK_EXEC - " -d -p --test_mode EN (--rx_prbs PRBS31 --rx_rate 25G --tx_prbs PRBS7 --tx_rate 10G)"); + printf(IDENT2 "%-40s: \n" IDENT3 "%s\n", "Configure Port for Physical Test Mode", + MLXLINK_EXEC " -d -p --test_mode EN (--rx_prbs PRBS31 --rx_rate 25G --tx_prbs PRBS7 " + "--tx_rate 10G)"); printf(IDENT2 "%-40s: \n" IDENT3 "%s\n", "Perform PRBS Tuning", MLXLINK_EXEC " -d -p --test_mode TU"); printf(IDENT2 "%-40s: \n" IDENT3 "%s\n", "Cable operations", MLXLINK_EXEC " -d --cable options"); @@ -347,17 +362,17 @@ void MlxlinkUi::printHelp() " -d --cable --write --page --offset "); if (_mlxlinkCommander->_userInput._advancedMode) { - printf( - IDENT2 "%-40s: \n" IDENT3 "%s\n", "Configure Transmitter Parameters (on lane, to database)", - MLXLINK_EXEC - " -d -p --serdes_tx ,,,,,,, (--serdes_tx_lane ) (--database)"); + printf(IDENT2 "%-40s: \n" IDENT3 "%s\n", "Configure Transmitter Parameters (on lane, to database)", + MLXLINK_EXEC " -d -p --serdes_tx " + ",,,,,,, " + "(--serdes_tx_lane ) (--database)"); } else { - printf( - IDENT2 "%-40s: \n" IDENT3 "%s\n", "Configure Transmitter Parameters (on lane, to database)", - MLXLINK_EXEC - " -d -p --serdes_tx ,,,,, (--serdes_tx_lane ) (--database)"); + printf(IDENT2 "%-40s: \n" IDENT3 "%s\n", "Configure Transmitter Parameters (on lane, to database)", + MLXLINK_EXEC " -d -p --serdes_tx " + ",,,,, (--serdes_tx_lane " + ") (--database)"); } printf(IDENT2 "%-40s: \n" IDENT3 "%s\n", "Configure Transmitter Parameters for 16nm devices", MLXLINK_EXEC @@ -421,8 +436,8 @@ void MlxlinkUi::validatePCIeParams() { if (dpnFlags) { - throw MlxRegException( - "For PCIE port, either port flag or depth, pcie_index and node flags should be specified"); + throw MlxRegException("For PCIE port, either port flag or depth, pcie_index and node flags should be " + "specified"); } } } @@ -504,11 +519,17 @@ void MlxlinkUi::validateModulePRBSParams() { throw MlxRegException("--" CABLE_PRBS_MODE " flag should be provided!"); } + if (_mlxlinkCommander->_userInput.modulePrbsParams[MODULE_PRBS_MODE] == "DS" && + _mlxlinkCommander->_userInput.modulePrbsParams.size() > 2) + { + throw MlxRegException("PRBS module parameters flags are valid only with PRBS enable mode (--prbs_mode EN)"); + } if (_mlxlinkCommander->_userInput.isPrbsModeProvided && (_mlxlinkCommander->_userInput.isPrbsShowDiagProvided || _mlxlinkCommander->_userInput.isPrbsClearDiagProvided)) { - throw MlxRegException("PRBS Module Diagnostic info flags are not working while configuring the PRBS test mode!"); + throw MlxRegException("PRBS Module Diagnostic info flags are not working while configuring the PRBS test " + "mode!"); } if (_mlxlinkCommander->_userInput.isPrbsShowDiagProvided && _mlxlinkCommander->_userInput.isPrbsClearDiagProvided) From 907154b6c7e881672099ff93d0332df37f17e8f8 Mon Sep 17 00:00:00 2001 From: Mustafa Dalloul Date: Sun, 3 Jul 2022 10:01:56 +0300 Subject: [PATCH 10/46] [mstlink] Loopback code alignment Description: Loopback code alignment Issue: 3088101 Signed-off-by: Mustafa Dalloul --- mlxlink/modules/mlxlink_amBER_collector.cpp | 2 +- mlxlink/modules/mlxlink_commander.cpp | 50 +++++++++------------ mlxlink/modules/mlxlink_enums.h | 10 +++-- mlxlink/modules/mlxlink_maps.cpp | 19 ++++---- mlxlink/modules/mlxlink_maps.h | 2 +- mlxlink/modules/mlxlink_utils.cpp | 10 +++-- 6 files changed, 45 insertions(+), 48 deletions(-) diff --git a/mlxlink/modules/mlxlink_amBER_collector.cpp b/mlxlink/modules/mlxlink_amBER_collector.cpp index 3e448e94..f01d872b 100644 --- a/mlxlink/modules/mlxlink_amBER_collector.cpp +++ b/mlxlink/modules/mlxlink_amBER_collector.cpp @@ -559,7 +559,7 @@ vector MlxlinkAmBerCollector::getPhyOperationInfo() fields.push_back(AmberField("cable_proto_cap", cableProtoCapStr)); u_int32_t phyMngrFsmState = getFieldValue("phy_mngr_fsm_state"); string loopbackMode = (phyMngrFsmState != PHY_MNGR_DISABLED) ? - _mlxlinkMaps->_loopbackModeList[getFieldValue("loopback_mode")] : + _mlxlinkMaps->_loopbackModeList[getFieldValue("loopback_mode")].second : "-1"; u_int32_t fecModeRequest = (u_int32_t)log2((float)getFieldValue("fec_mode_request")); fields.push_back(AmberField("loopback_mode", loopbackMode)); diff --git a/mlxlink/modules/mlxlink_commander.cpp b/mlxlink/modules/mlxlink_commander.cpp index 69aea420..dec2699b 100644 --- a/mlxlink/modules/mlxlink_commander.cpp +++ b/mlxlink/modules/mlxlink_commander.cpp @@ -1848,7 +1848,7 @@ void MlxlinkCommander::operatingInfoPage() setPrintVal(_operatingInfoCmd, "FEC", fec_mode_str == "" ? "N/A" : fec_mode_str, fec_mode_str == "" ? MlxlinkRecord::state2Color(0) : color, !_prbsTestMode, _linkUP); - setPrintVal(_operatingInfoCmd, "Loopback Mode", _mlxlinkMaps->_loopbackModeList[loopbackMode], + setPrintVal(_operatingInfoCmd, "Loopback Mode", _mlxlinkMaps->_loopbackModeList[loopbackMode].second, getLoopbackColor(loopbackMode), true, !_prbsTestMode && loopbackMode != -1); setPrintVal(_operatingInfoCmd, "Auto Negotiation", _mlxlinkMaps->_anDisableList[_anDisable] + _speedForce, getAnDisableColor(_anDisable), true, !_prbsTestMode); @@ -4769,14 +4769,13 @@ void MlxlinkCommander::sendSltp() string MlxlinkCommander::getLoopbackStr(u_int32_t loopbackCapMask) { - string loopbackStr = ""; - for (map::iterator it = _mlxlinkMaps->_loopbackModeList.begin(); - it != _mlxlinkMaps->_loopbackModeList.end(); - it++) + string loopbackStr = _mlxlinkMaps->_loopbackModeList[LOOPBACK_MODE_NO].first + "(" + + _mlxlinkMaps->_loopbackModeList[LOOPBACK_MODE_NO].second + ")/"; + for (const auto& lbConf : _mlxlinkMaps->_loopbackModeList) { - if ((it->first != PHY_REMOTE_LOOPBACK) && (it->first & loopbackCapMask) && !it->second.empty()) + if ((lbConf.first & loopbackCapMask) && !lbConf.second.second.empty()) { - loopbackStr += it->second + ","; + loopbackStr += lbConf.second.first + "(" + lbConf.second.second + ")/"; } } return deleteLastChar(loopbackStr); @@ -4792,17 +4791,17 @@ void MlxlinkCommander::checkPplrCap() genBuffSendRegister(regName, MACCESS_REG_METHOD_GET); u_int32_t loopBackCap = getFieldValue("lb_cap"); u_int32_t loopBackVal = getLoopbackMode(_userInput._pplrLB); - if (loopBackVal != PHY_NO_LOOPBACK) + if (loopBackVal != LOOPBACK_MODE_NO) { if (!(loopBackCap & getLoopbackMode(_userInput._pplrLB))) { string supportedLoopbacks = getLoopbackStr(loopBackCap); - throw MlxRegException("selected loopback not supported\n" - "Supported Loopback modes for the device: [%s]", - supportedLoopbacks.c_str()); + throw MlxRegException( + "\n%s Loopback configuration is not supported, supported Loopback configurations are [%s]", + _userInput._pplrLB.c_str(), supportedLoopbacks.c_str()); } } - if (loopBackVal == PHY_REMOTE_LOOPBACK && _productTechnology < PRODUCT_7NM) + if (loopBackVal == LOOPBACK_MODE_REMOTE && _productTechnology < PRODUCT_7NM) { string warMsg = "Remote loopback mode pre-request (all should be satisfied):\n"; warMsg += "1. Remote loopback is supported only in force mode.\n"; @@ -4820,14 +4819,13 @@ void MlxlinkCommander::sendPplr() MlxlinkRecord::printCmdLine("Configuring Port Loopback", _jsonRoot); checkPplrCap(); - string regName = "PPLR"; - resetParser(regName); + resetParser(ACCESS_REG_PPLR); updatePortType(); updateField("local_port", _localPort); updateField("lb_en", getLoopbackMode(_userInput._pplrLB)); - genBuffSendRegister(regName, MACCESS_REG_METHOD_SET); + genBuffSendRegister(ACCESS_REG_PPLR, MACCESS_REG_METHOD_SET); } catch (const std::exception& exc) { @@ -4838,23 +4836,15 @@ void MlxlinkCommander::sendPplr() u_int32_t MlxlinkCommander::getLoopbackMode(const string& lb) { - if (lb == "NO") - { - return PHY_NO_LOOPBACK; - } - if (lb == "RM") - { - return PHY_REMOTE_LOOPBACK; - } - if (lb == "PH") - { - return PHY_LOCAL_LOOPBACK; - } - if (lb == "EX") + auto it = find_if(_mlxlinkMaps->_loopbackModeList.begin(), _mlxlinkMaps->_loopbackModeList.end(), + [lb](pair> lpConf) { return lb == lpConf.second.first; }); + + if (it == _mlxlinkMaps->_loopbackModeList.end()) { - return EXTERNAL_LOCAL_LOOPBACK; + throw MlxRegException("Invalid loopback option: %s, see tool usage \"%s --help\"", lb.c_str(), MLXLINK_EXEC); } - throw MlxRegException("Invalid loopback option: %s, see tool usage \"%s --help\"", lb.c_str(), MLXLINK_EXEC); + + return it->first; } void MlxlinkCommander::sendPepc() diff --git a/mlxlink/modules/mlxlink_enums.h b/mlxlink/modules/mlxlink_enums.h index d2f73ab7..33d9ae8b 100644 --- a/mlxlink/modules/mlxlink_enums.h +++ b/mlxlink/modules/mlxlink_enums.h @@ -75,6 +75,7 @@ #define ACCESS_REG_PMPT "PMPT" #define ACCESS_REG_PMPD "PMPD" #define ACCESS_REG_PMTM "PMTM" +#define ACCESS_REG_PPLR "PPLR" // define all used regs above this line #define QSFP_CHANNELS 4 @@ -1282,10 +1283,11 @@ enum PORT_STATE enum LOOPBACK_MODE { - PHY_NO_LOOPBACK = 0, - PHY_REMOTE_LOOPBACK = 1, - PHY_LOCAL_LOOPBACK = 2, - EXTERNAL_LOCAL_LOOPBACK = 4 + LOOPBACK_MODE_NO = 0x0, + LOOPBACK_MODE_REMOTE = 0x1, + LOOPBACK_MODE_LOCAL = 0x2, + LOOPBACK_MODE_EXTERNAL = 0x4, + LOOPBACK_MODE_LL = 0x40 }; enum AN_DISABLE diff --git a/mlxlink/modules/mlxlink_maps.cpp b/mlxlink/modules/mlxlink_maps.cpp index f94caaac..ba0069a1 100644 --- a/mlxlink/modules/mlxlink_maps.cpp +++ b/mlxlink/modules/mlxlink_maps.cpp @@ -48,10 +48,12 @@ MlxlinkMaps* MlxlinkMaps::getInstance() void MlxlinkMaps::initPublicStrings() { _berCollectTitle = - "Test Mode (Nominal/Corner/Drift),Protocol,Speed [Gb/s],Active FEC,Iteration Number,Device PN,FW Version,Device ID,Port Number,Media,Cable PN,Length [m],Attenuation [dB]," - "Test time [Min],Raw Errors Lane 0,Raw Errors Lane 1,Raw Errors Lane 2,Raw Errors Lane 3,Raw Errors Lane 4,Raw Errors Lane 5,Raw Errors Lane 6,Raw Errors Lane 7,Link Down,Total Raw BER,Raw BER limit," - "Effective Errors,Effective BER,Result,System Voltage,Chip Start Temp,Chip End Temp,Module Start Temp,Module End Temp,Active RTN,Device SN,Cable SN,RX End BW [Gb/s]"; - _sltpHeader = ""; + "Test Mode (Nominal/Corner/Drift),Protocol,Speed [Gb/s],Active FEC,Iteration Number,Device PN,FW Version,Device " + "ID,Port Number,Media,Cable PN,Length [m],Attenuation [dB]," + "Test time [Min],Raw Errors Lane 0,Raw Errors Lane 1,Raw Errors Lane 2,Raw Errors Lane 3,Raw Errors Lane 4,Raw " + "Errors Lane 5,Raw Errors Lane 6,Raw Errors Lane 7,Link Down,Total Raw BER,Raw BER limit," + "Effective Errors,Effective BER,Result,System Voltage,Chip Start Temp,Chip End Temp,Module Start Temp,Module End " + "Temp,Active RTN,Device SN,Cable SN,RX End BW [Gb/s]"; _showErrorsTitle = "Errors"; } @@ -177,10 +179,11 @@ void MlxlinkMaps::initFecAndLoopbackMapping() _fecPerSpeed.push_back(make_pair("25G", "")); _fecPerSpeed.push_back(make_pair("10G", "")); - _loopbackModeList[PHY_NO_LOOPBACK] = "No Loopback"; - _loopbackModeList[PHY_REMOTE_LOOPBACK] = "PHY Remote Loopback"; - _loopbackModeList[PHY_LOCAL_LOOPBACK] = "PHY Local Loopback"; - _loopbackModeList[EXTERNAL_LOCAL_LOOPBACK] = "External Local Loopback"; + _loopbackModeList[LOOPBACK_MODE_NO] = make_pair("NO", "No Loopback"); + _loopbackModeList[LOOPBACK_MODE_REMOTE] = make_pair("RM", "PHY Remote Loopback"); + _loopbackModeList[LOOPBACK_MODE_LOCAL] = make_pair("PH", "PHY Local Loopback"); + _loopbackModeList[LOOPBACK_MODE_EXTERNAL] = make_pair("EX", "External Local Loopback"); + _loopbackModeList[LOOPBACK_MODE_LL] = make_pair("LL", "Link Layer Local Loopback"); } void MlxlinkMaps::ethSpeedMapping() diff --git a/mlxlink/modules/mlxlink_maps.h b/mlxlink/modules/mlxlink_maps.h index a38f1eb6..141c2d21 100644 --- a/mlxlink/modules/mlxlink_maps.h +++ b/mlxlink/modules/mlxlink_maps.h @@ -204,7 +204,7 @@ class MlxlinkMaps std::map _fecModeActive; std::map> _fecModeMask; std::vector> _fecPerSpeed; - std::map _loopbackModeList; + std::map> _loopbackModeList; std::map _anDisableList; std::map _tech; std::map _cableComplianceSfp; diff --git a/mlxlink/modules/mlxlink_utils.cpp b/mlxlink/modules/mlxlink_utils.cpp index 78571a8a..031593b2 100644 --- a/mlxlink/modules/mlxlink_utils.cpp +++ b/mlxlink/modules/mlxlink_utils.cpp @@ -134,21 +134,23 @@ string getLoopbackColor(u_int32_t loopbackMode) { switch (loopbackMode) { - case PHY_NO_LOOPBACK: + case LOOPBACK_MODE_NO: return ANSI_COLOR_GREEN; break; - case PHY_REMOTE_LOOPBACK: + case LOOPBACK_MODE_REMOTE: return ANSI_COLOR_CYAN; break; - case PHY_LOCAL_LOOPBACK: + case LOOPBACK_MODE_LOCAL: return ANSI_COLOR_BLUE; break; - case EXTERNAL_LOCAL_LOOPBACK: + case LOOPBACK_MODE_EXTERNAL: return ANSI_COLOR_MAGENTA; + case LOOPBACK_MODE_LL: + return ANSI_COLOR_YELLOW; default: return ANSI_COLOR_RED; } From 283ae1662de7ce327373b80ef0a03fd331ef56bf Mon Sep 17 00:00:00 2001 From: Mustafa Dalloul Date: Sun, 3 Jul 2022 11:46:13 +0300 Subject: [PATCH 11/46] [mstlink] Amber collection code alignment Description: Amber collection code alignment Issue: 3088117 Signed-off-by: Mustafa Dalloul --- mlxlink/modules/amber_field.cpp | 2 +- mlxlink/modules/amber_field.h | 2 +- mlxlink/modules/mlxlink_amBER_collector.cpp | 152 +++++++++++++++----- mlxlink/modules/mlxlink_amBER_collector.h | 6 +- mlxlink/modules/mlxlink_enums.h | 3 +- 5 files changed, 122 insertions(+), 43 deletions(-) diff --git a/mlxlink/modules/amber_field.cpp b/mlxlink/modules/amber_field.cpp index b9246dc9..28000076 100644 --- a/mlxlink/modules/amber_field.cpp +++ b/mlxlink/modules/amber_field.cpp @@ -133,7 +133,7 @@ u_int64_t AmberField::getPrmValue() const return _prmValue; } -bool AmberField::isVisible() +bool AmberField::isVisible() const { return _visible; } diff --git a/mlxlink/modules/amber_field.h b/mlxlink/modules/amber_field.h index 8d96fe8f..c5388fb3 100644 --- a/mlxlink/modules/amber_field.h +++ b/mlxlink/modules/amber_field.h @@ -52,7 +52,7 @@ class AmberField string getUiField() const; string getUiValue() const; u_int64_t getPrmValue() const; - bool isVisible(); + bool isVisible() const; u_int32_t getFieldIndex() const; static void reset(); static string getValueFromFields(const vector& fields, const string& uiField, bool matchUiField = true); diff --git a/mlxlink/modules/mlxlink_amBER_collector.cpp b/mlxlink/modules/mlxlink_amBER_collector.cpp index f01d872b..39d497f3 100644 --- a/mlxlink/modules/mlxlink_amBER_collector.cpp +++ b/mlxlink/modules/mlxlink_amBER_collector.cpp @@ -73,6 +73,26 @@ MlxlinkAmBerCollector::MlxlinkAmBerCollector(Json::Value& jsonRoot) : _jsonRoot( _invalidate = false; _mlxlinkMaps = NULL; + + _baseSheetsList[AMBER_SHEET_GENERAL] = FIELDS_COUNT{4, 4, 4}; + _baseSheetsList[AMBER_SHEET_INDEXES] = FIELDS_COUNT{2, 2, 4}; + _baseSheetsList[AMBER_SHEET_LINK_STATUS] = FIELDS_COUNT{48, 139, 6}; + _baseSheetsList[AMBER_SHEET_MODULE_STATUS] = FIELDS_COUNT{111, 111, 0}; + _baseSheetsList[AMBER_SHEET_SYSTEM] = FIELDS_COUNT{16, 21, 11}; + _baseSheetsList[AMBER_SHEET_SERDES_16NM] = FIELDS_COUNT{376, 736, 0}; + _baseSheetsList[AMBER_SHEET_SERDES_7NM] = FIELDS_COUNT{203, 323, 499}; + _baseSheetsList[AMBER_SHEET_PORT_COUNTERS] = FIELDS_COUNT{35, 0, 35}; + _baseSheetsList[AMBER_SHEET_TROUBLESHOOTING] = FIELDS_COUNT{2, 2, 0}; + _baseSheetsList[AMBER_SHEET_PHY_OPERATION_INFO] = FIELDS_COUNT{18, 18, 15}; + _baseSheetsList[AMBER_SHEET_LINK_UP_INFO] = FIELDS_COUNT{9, 9, 0}; + _baseSheetsList[AMBER_SHEET_LINK_DOWN_INFO] = FIELDS_COUNT{5, 5, 0}; + _baseSheetsList[AMBER_SHEET_TEST_MODE_INFO] = FIELDS_COUNT{68, 136, 0}; + _baseSheetsList[AMBER_SHEET_TEST_MODE_MODULE_INFO] = FIELDS_COUNT{58, 110, 0}; + _baseSheetsList[AMBER_SHEET_PHY_DEBUG_INFO] = FIELDS_COUNT{4, 4, 0}; + + for_each(_baseSheetsList.begin(), _baseSheetsList.end(), [&](pair sheet) { + _sheetsList.push_back({sheet.first, sheet.second}); + }); } MlxlinkAmBerCollector::~MlxlinkAmBerCollector() {} @@ -268,27 +288,25 @@ void MlxlinkAmBerCollector::init() _maxLanes = MAX_PCIE_LANES; } - _sheetsList[AMBER_SHEET_GENERAL] = FIELDS_COUNT{4, 4, 4}; - _sheetsList[AMBER_SHEET_INDEXES] = FIELDS_COUNT{2, 2, 4}; - _sheetsList[AMBER_SHEET_LINK_STATUS] = FIELDS_COUNT{48, 139, 6}; - _sheetsList[AMBER_SHEET_MODULE_STATUS] = FIELDS_COUNT{111, 111, 0}; - _sheetsList[AMBER_SHEET_SYSTEM] = FIELDS_COUNT{16, 21, 11}; - _sheetsList[AMBER_SHEET_SERDES_16NM] = FIELDS_COUNT{376, 736, 0}; - _sheetsList[AMBER_SHEET_SERDES_7NM] = FIELDS_COUNT{203, 323, 65}; - _sheetsList[AMBER_SHEET_PORT_COUNTERS] = FIELDS_COUNT{35, 0, 35}; - _sheetsList[AMBER_SHEET_TROUBLESHOOTING] = FIELDS_COUNT{2, 2, 0}; - _sheetsList[AMBER_SHEET_PHY_OPERATION_INFO] = FIELDS_COUNT{18, 18, 15}; - _sheetsList[AMBER_SHEET_LINK_UP_INFO] = FIELDS_COUNT{9, 9, 0}; - _sheetsList[AMBER_SHEET_LINK_DOWN_INFO] = FIELDS_COUNT{5, 5, 0}; - _sheetsList[AMBER_SHEET_TEST_MODE_INFO] = FIELDS_COUNT{68, 136, 0}; - _sheetsList[AMBER_SHEET_TEST_MODE_MODULE_INFO] = FIELDS_COUNT{58, 110, 0}; - _sheetsList[AMBER_SHEET_PHY_DEBUG_INFO] = FIELDS_COUNT{4, 4, 0}; + initAmberSheetsToDump(); } catch (...) { } } +void MlxlinkAmBerCollector::initAmberSheetsToDump() +{ + // Custom sheet\s dump + if (!_sheetsToDump.empty()) + { + _sheetsList.clear(); + for_each(_sheetsToDump.begin(), _sheetsToDump.end(), [&](AMBER_SHEET& sheet) { + _sheetsList.push_back({sheet, _baseSheetsList[sheet]}); + }); + } +} + bool MlxlinkAmBerCollector::isGBValid() { return _isGBSysValid; @@ -914,7 +932,7 @@ vector MlxlinkAmBerCollector::getSerdesNDR() vector> sltpParams(PARAMS_7NM_LAST + 1, vector(_maxLanes, "")); u_int32_t lane = 0; // Getting 7nm SLRG information for all lanes - for (; lane < _maxLanes; lane++) + for (; lane < _numOfLanes; lane++) { resetLocalParser(ACCESS_REG_SLRG); updateField("local_port", _localPort); @@ -943,7 +961,7 @@ vector MlxlinkAmBerCollector::getSerdesNDR() if (!_isPortPCIE) { // Getting 7nm SLTP information for all lanes - for (lane = 0; lane < _maxLanes; lane++) + for (lane = 0; lane < _numOfLanes; lane++) { resetLocalParser(ACCESS_REG_SLTP); updateField("local_port", _localPort); @@ -1763,7 +1781,7 @@ void MlxlinkAmBerCollector::getTestModePrpsInfo(const string& prbsReg, vector& fields, st void MlxlinkAmBerCollector::getTestModeModulePMPD(vector& fields, string moduleSide) { - vector> pmpdParams(PMPD_PARAM_LAST, vector(_numOfLanes, "")); + vector> pmpdParams(PMPD_PARAM_LAST, vector(_maxLanes, "")); for (u_int32_t lane = 0; lane < _maxLanes; lane++) { @@ -1867,7 +1885,6 @@ void MlxlinkAmBerCollector::getTestModeModulePMPD(vector& fields, st updateField("host_media", moduleSide == "host"); updateField("lane", lane); sendRegister(ACCESS_REG_PMPD, MACCESS_REG_METHOD_GET); - ; pmpdParams[PMPD_PARAM_STATUS][lane] = getStrByValue(getFieldValue("status"), _mlxlinkMaps->_modulePMPDStatus); pmpdParams[PMPD_PARAM_PRBS_BITS][lane] = @@ -1939,6 +1956,8 @@ void MlxlinkAmBerCollector::groupValidIf(bool condition) vector MlxlinkAmBerCollector::collectSheet(AMBER_SHEET sheet) { vector fields; + bool invalidSheet = false; + _invalidate = false; fields.push_back(AmberField("N/A", "N/A")); AmberField::reset(); @@ -1973,63 +1992,105 @@ vector MlxlinkAmBerCollector::collectSheet(AMBER_SHEET sheet) { fields = getPortCounters(); } + else if (isIn(sheet, _sheetsToDump)) + { + invalidSheet = true; + } break; case AMBER_SHEET_TROUBLESHOOTING: if (!_inPRBSMode) { fields = getTroubleshootingInfo(); } + else if (isIn(sheet, _sheetsToDump)) + { + invalidSheet = true; + } break; case AMBER_SHEET_PHY_OPERATION_INFO: if (!_inPRBSMode) { fields = getPhyOperationInfo(); } + else if (isIn(sheet, _sheetsToDump)) + { + invalidSheet = true; + } break; case AMBER_SHEET_LINK_UP_INFO: if (!_inPRBSMode) { fields = getLinkUpInfo(); } + else if (isIn(sheet, _sheetsToDump)) + { + invalidSheet = true; + } break; case AMBER_SHEET_LINK_DOWN_INFO: if (!_inPRBSMode) { fields = getLinkDownInfo(); } + else if (isIn(sheet, _sheetsToDump)) + { + invalidSheet = true; + } break; case AMBER_SHEET_TEST_MODE_INFO: if (_inPRBSMode) { fields = getTestModeInfo(); } + else if (isIn(sheet, _sheetsToDump)) + { + invalidSheet = true; + } break; case AMBER_SHEET_TEST_MODE_MODULE_INFO: if (_inPRBSMode) { fields = getTestModeModuleInfo(); } + else if (isIn(sheet, _sheetsToDump)) + { + invalidSheet = true; + } break; case AMBER_SHEET_PHY_DEBUG_INFO: if (!_inPRBSMode) { fields = getPhyDebugInfo(); } + else if (isIn(sheet, _sheetsToDump)) + { + invalidSheet = true; + } break; + default: + throw MlxRegException("Invalid amBER page index: %d", sheet); + } + + if (!_sheetsToDump.empty()) + { + if (invalidSheet) + { + string mode = _inPRBSMode ? "Operational mode" : "PRBS test mode"; + throw MlxRegException("Page %d is valid in %s only!", sheet, mode.c_str()); + } } return fields; } void MlxlinkAmBerCollector::collect() { - for (auto it = _sheetsList.begin(); it != _sheetsList.end(); it++) + for (const auto& sheet : _sheetsList) { - auto sheetFields = collectSheet(it->first); - if (!sheetFields.empty() && sheetFields.back().getUiField() == "N/A") + auto sheetFields = collectSheet(sheet.first); + if (sheetFields.empty() || sheetFields.back().getUiField() != "N/A") { - continue; + _amberCollection[sheet.first] = sheetFields; } - _amberCollection[it->first] = sheetFields; } } @@ -2056,15 +2117,15 @@ u_int32_t MlxlinkAmBerCollector::fixFieldsData() { if (_isPortPCIE) { - lastFieldIndexPerGroup = _sheetsList[(*it).first].numOfPcieFields; + lastFieldIndexPerGroup = _sheetsList[getSheetIndex((*it).first)].second.numOfPcieFields; } else if (_isPortETH) { - lastFieldIndexPerGroup = _sheetsList[(*it).first].numOfEthFields; + lastFieldIndexPerGroup = _sheetsList[getSheetIndex((*it).first)].second.numOfEthFields; } else if (_isPortIB) { - lastFieldIndexPerGroup = _sheetsList[(*it).first].numOfIbFields; + lastFieldIndexPerGroup = _sheetsList[getSheetIndex((*it).first)].second.numOfIbFields; } for (u_int32_t fieldIdx = (*it).second.size() + 1; fieldIdx <= lastFieldIndexPerGroup; fieldIdx++) { @@ -2075,6 +2136,19 @@ u_int32_t MlxlinkAmBerCollector::fixFieldsData() return totalFields; } +u_int32_t MlxlinkAmBerCollector::getSheetIndex(AMBER_SHEET sheet) +{ + u_int32_t index = 0; + for (; index < _sheetsList.size(); index++) + { + if (_sheetsList[index].first == sheet) + { + break; + } + } + return index; +} + void MlxlinkAmBerCollector::exportToCSV() { const char* fileName = _csvFileName.c_str(); @@ -2082,19 +2156,18 @@ void MlxlinkAmBerCollector::exportToCSV() ofstream berFile(fileName, std::ofstream::app); u_int32_t totalNumOfFields = fixFieldsData(); - // Preparing CSV header line if (!ifile.good()) { // Going over all groups inside _amberCollection and getting the field name for each one - for (auto it = _amberCollection.begin(); it != _amberCollection.end(); it++) + for (const auto& sheet : _sheetsList) { - for (auto fieldIt = (*it).second.begin(); fieldIt != (*it).second.end(); fieldIt++) + for (const auto& field : _amberCollection[sheet.first]) { - if ((*fieldIt).isVisible()) + if (field.isVisible()) { - berFile << (*fieldIt).getUiField(); - if ((*fieldIt).getFieldIndex() != (totalNumOfFields - 1)) + berFile << field.getUiField(); + if (field.getFieldIndex() < totalNumOfFields) { berFile << ","; } @@ -2105,20 +2178,21 @@ void MlxlinkAmBerCollector::exportToCSV() } // Preparing CSV values // Going over all groups inside _amberCollection and getting the field value for each one - for (auto it = _amberCollection.begin(); it != _amberCollection.end(); it++) + for (const auto& sheet : _sheetsList) { - for (auto fieldIt = (*it).second.begin(); fieldIt != (*it).second.end(); fieldIt++) + for (const auto& field : _amberCollection[sheet.first]) { - if ((*fieldIt).isVisible()) + if (field.isVisible()) { - berFile << (*fieldIt).getUiValue(); - if ((*fieldIt).getFieldIndex() != (totalNumOfFields - 1)) + berFile << field.getUiValue(); + if (field.getFieldIndex() < totalNumOfFields) { berFile << ","; } } } } + berFile << endl; berFile.close(); } diff --git a/mlxlink/modules/mlxlink_amBER_collector.h b/mlxlink/modules/mlxlink_amBER_collector.h index fb7d8571..72f613d1 100644 --- a/mlxlink/modules/mlxlink_amBER_collector.h +++ b/mlxlink/modules/mlxlink_amBER_collector.h @@ -92,6 +92,7 @@ class MlxlinkAmBerCollector : public MlxlinkRegParser MlxlinkMaps* _mlxlinkMaps; vector _localPorts; // will be valid for switches bool _isHca; + vector _sheetsToDump; private: string getRawFieldValue(const string fieldName); @@ -123,6 +124,7 @@ class MlxlinkAmBerCollector : public MlxlinkRegParser void groupValidIf(bool condition); void getTestModeModulePMPT(vector& fields, string moduleSide, ModuleAccess_t mode); void getTestModeModulePMPD(vector& fields, string moduleSide); + u_int32_t getSheetIndex(AMBER_SHEET sheet); bool _isQsfpCable; bool _isSfpCable; @@ -132,6 +134,7 @@ class MlxlinkAmBerCollector : public MlxlinkRegParser u_int32_t _splitPort; u_int32_t _secondSplit; map> _amberCollection; + map _baseSheetsList; protected: string getBitmaskPerLaneStr(u_int32_t bitmask); @@ -150,6 +153,7 @@ class MlxlinkAmBerCollector : public MlxlinkRegParser string getClRawBer(); // Callers + void initAmberSheetsToDump(); vector collectSheet(AMBER_SHEET sheet); void collect(); @@ -171,7 +175,7 @@ class MlxlinkAmBerCollector : public MlxlinkRegParser Json::Value& _jsonRoot; vector _amBerCollectorOutput; - map _sheetsList; + vector> _sheetsList; u_int32_t _activeSpeed; u_int32_t _protoActive; diff --git a/mlxlink/modules/mlxlink_enums.h b/mlxlink/modules/mlxlink_enums.h index c9c40bc2..f6246c98 100644 --- a/mlxlink/modules/mlxlink_enums.h +++ b/mlxlink/modules/mlxlink_enums.h @@ -1446,7 +1446,8 @@ enum AMBER_SHEET AMBER_SHEET_LINK_DOWN_INFO = 12, AMBER_SHEET_TEST_MODE_INFO = 13, AMBER_SHEET_TEST_MODE_MODULE_INFO = 14, - AMBER_SHEET_PHY_DEBUG_INFO = 15 + AMBER_SHEET_PHY_DEBUG_INFO = 15, + AMBER_SHEET_ALL // Keep this enum last }; enum PCIE_DEVICE_STATUS From 6b8502a678928eccda9dcfdedb7d412a48cb8cb1 Mon Sep 17 00:00:00 2001 From: Mustafa Dalloul Date: Sun, 3 Jul 2022 13:45:31 +0300 Subject: [PATCH 12/46] [mstlink] Serdes Tx and PCIe Grade code alignment Description: -> Re-formatting serdes tx code -> Fixing PCIe eye info flow Issue: 3088059 Signed-off-by: Mustafa Dalloul --- mlxlink/modules/mlxlink_amBER_collector.cpp | 95 +++++-- mlxlink/modules/mlxlink_amBER_collector.h | 1 + mlxlink/modules/mlxlink_commander.cpp | 270 +++++++++++--------- mlxlink/modules/mlxlink_commander.h | 12 +- mlxlink/modules/mlxlink_enums.h | 59 +++-- mlxlink/modules/mlxlink_maps.cpp | 23 ++ mlxlink/modules/mlxlink_maps.h | 11 + 7 files changed, 294 insertions(+), 177 deletions(-) diff --git a/mlxlink/modules/mlxlink_amBER_collector.cpp b/mlxlink/modules/mlxlink_amBER_collector.cpp index f01d872b..d8ddafda 100644 --- a/mlxlink/modules/mlxlink_amBER_collector.cpp +++ b/mlxlink/modules/mlxlink_amBER_collector.cpp @@ -843,7 +843,7 @@ vector MlxlinkAmBerCollector::getSerdesHDR() if (!_isPortPCIE) { vector> slrgParams(SLRG_PARAMS_LAST, vector(_maxLanes, "")); - vector> sltpParams(PARAMS_16NM_LAST, vector(_maxLanes, "")); + vector> sltpParams(SLTP_HDR_LAST, vector(_maxLanes, "")); vector sltpStatus; u_int32_t lane = 0; // Getting 16nm SLRG information for all lanes @@ -873,24 +873,24 @@ vector MlxlinkAmBerCollector::getSerdesHDR() updateField("lane", lane); sendRegister(ACCESS_REG_SLTP, MACCESS_REG_METHOD_GET); - sltpParams[PRE_2_TAP][lane] = getFieldStr("pre_2_tap"); - sltpParams[PRE_TAP][lane] = getFieldStr("pre_tap"); - sltpParams[MAIN_TAP][lane] = getFieldStr("main_tap"); - sltpParams[POST_TAP][lane] = getFieldStr("post_tap"); - sltpParams[OB_M2LP][lane] = getFieldStr("ob_m2lp"); - sltpParams[OB_AMP][lane] = getFieldStr("ob_amp"); - sltpParams[OB_ALEV_OUT][lane] = getFieldStr("ob_alev_out"); + sltpParams[SLTP_HDR_PRE_2_TAP][lane] = getFieldStr("pre_2_tap"); + sltpParams[SLTP_HDR_PRE_TAP][lane] = getFieldStr("pre_tap"); + sltpParams[SLTP_HDR_MAIN_TAP][lane] = getFieldStr("main_tap"); + sltpParams[SLTP_HDR_POST_TAP][lane] = getFieldStr("post_tap"); + sltpParams[SLTP_HDR_OB_M2LP][lane] = getFieldStr("ob_m2lp"); + sltpParams[SLTP_HDR_OB_AMP][lane] = getFieldStr("ob_amp"); + sltpParams[SLTP_HDR_OB_ALEV_OUT][lane] = getFieldStr("ob_alev_out"); sltpStatus.push_back(getFieldValue("status") ? "Valid" : "Invalid"); } fillParamsToFields("tx_status", sltpStatus, fields); - fillParamsToFields("pre_2_tap", sltpParams[PRE_2_TAP], fields); - fillParamsToFields("pre_tap", sltpParams[PRE_TAP], fields); - fillParamsToFields("main_tap", sltpParams[MAIN_TAP], fields); - fillParamsToFields("post_tap", sltpParams[POST_TAP], fields); - fillParamsToFields("ob_m2lp", sltpParams[OB_M2LP], fields); - fillParamsToFields("ob_amp", sltpParams[OB_AMP], fields); - fillParamsToFields("ob_alev_out", sltpParams[OB_ALEV_OUT], fields); + fillParamsToFields("pre_2_tap", sltpParams[SLTP_HDR_PRE_2_TAP], fields); + fillParamsToFields("pre_tap", sltpParams[SLTP_HDR_PRE_TAP], fields); + fillParamsToFields("main_tap", sltpParams[SLTP_HDR_MAIN_TAP], fields); + fillParamsToFields("post_tap", sltpParams[SLTP_HDR_POST_TAP], fields); + fillParamsToFields("ob_m2lp", sltpParams[SLTP_HDR_OB_M2LP], fields); + fillParamsToFields("ob_amp", sltpParams[SLTP_HDR_OB_AMP], fields); + fillParamsToFields("ob_alev_out", sltpParams[SLTP_HDR_OB_ALEV_OUT], fields); } } catch (const std::exception& exc) @@ -901,6 +901,46 @@ vector MlxlinkAmBerCollector::getSerdesHDR() return fields; } +u_int32_t MlxlinkAmBerCollector::getFomMeasurement() +{ + u_int32_t fomMeasurement = SLRG_EOM_NONE; + if (!_isPortPCIE) + { + fomMeasurement = SLRG_EOM_COMPOSITE; + if (!isSpeed25GPerLane(_activeSpeed, _protoActive)) + { + fomMeasurement |= (SLRG_EOM_UPPER | SLRG_EOM_MIDDLE | SLRG_EOM_LOWER); + } + } + else + { + for (u_int32_t lane = 0; lane < _numOfLanes; lane++) + { + resetParser(ACCESS_REG_SLRG); + updateField("local_port", _localPort); + updateField("pnat", PNAT_PCIE); + updateField("lane", lane); + updateField("fom_measurment", SLRG_EOM_COMPOSITE); + genBuffSendRegister(ACCESS_REG_SLRG, MACCESS_REG_METHOD_GET); + } + u_int32_t it = 0; + while (it < SLRG_PCIE_7NM_TIMEOUT) + { + resetParser(ACCESS_REG_SLRG); + updateField("local_port", _localPort); + updateField("pnat", PNAT_PCIE); + genBuffSendRegister(ACCESS_REG_SLRG, MACCESS_REG_METHOD_GET); + if (getFieldValue("status")) + { + break; + } + it++; + msleep(SLRG_PCIE_7NM_SLEEP); + } + } + return fomMeasurement; +} + vector MlxlinkAmBerCollector::getSerdesNDR() { vector fields; @@ -911,8 +951,10 @@ vector MlxlinkAmBerCollector::getSerdesNDR() fields.push_back(AmberField("BKV_version", "N/A")); vector> slrgParams(SLRG_PARAMS_LAST, vector(_maxLanes, "")); - vector> sltpParams(PARAMS_7NM_LAST + 1, vector(_maxLanes, "")); + vector> sltpParams(SLTP_NDR_LAST + 1, vector(_maxLanes, "")); + u_int32_t fomMeasurement = getFomMeasurement(); u_int32_t lane = 0; + // Getting 7nm SLRG information for all lanes for (; lane < _maxLanes; lane++) { @@ -920,6 +962,7 @@ vector MlxlinkAmBerCollector::getSerdesNDR() updateField("local_port", _localPort); updateField("lane", lane); updateField("pnat", _pnat); + updateField("fom_measurment", fomMeasurement); sendRegister(ACCESS_REG_SLRG, MACCESS_REG_METHOD_GET); slrgParams[SLRG_PARAMS_INITIAL_FOM][lane] = getFieldStr("initial_fom"); @@ -951,17 +994,17 @@ vector MlxlinkAmBerCollector::getSerdesNDR() updateField("pnat", _pnat); sendRegister(ACCESS_REG_SLTP, MACCESS_REG_METHOD_GET); - sltpParams[FIR_PRE3][lane] = getFieldStr("fir_pre3"); - sltpParams[FIR_PRE2][lane] = getFieldStr("fir_pre2"); - sltpParams[FIR_PRE1][lane] = getFieldStr("fir_pre1"); - sltpParams[FIR_MAIN][lane] = getFieldStr("fir_main"); - sltpParams[FIR_POST1][lane] = getFieldStr("fir_post1"); + sltpParams[SLTP_NDR_FIR_PRE3][lane] = getFieldStr("fir_pre3"); + sltpParams[SLTP_NDR_FIR_PRE2][lane] = getFieldStr("fir_pre2"); + sltpParams[SLTP_NDR_FIR_PRE1][lane] = getFieldStr("fir_pre1"); + sltpParams[SLTP_NDR_FIR_MAIN][lane] = getFieldStr("fir_main"); + sltpParams[SLTP_NDR_FIR_POST1][lane] = getFieldStr("fir_post1"); } - fillParamsToFields("pre_3_tap", sltpParams[FIR_PRE3], fields); - fillParamsToFields("pre_2_tap", sltpParams[FIR_PRE2], fields); - fillParamsToFields("pre_1_tap", sltpParams[FIR_PRE1], fields); - fillParamsToFields("main_tap", sltpParams[FIR_MAIN], fields); - fillParamsToFields("post_1_tap", sltpParams[FIR_POST1], fields); + fillParamsToFields("pre_3_tap", sltpParams[SLTP_NDR_FIR_PRE3], fields); + fillParamsToFields("pre_2_tap", sltpParams[SLTP_NDR_FIR_PRE2], fields); + fillParamsToFields("pre_1_tap", sltpParams[SLTP_NDR_FIR_PRE1], fields); + fillParamsToFields("main_tap", sltpParams[SLTP_NDR_FIR_MAIN], fields); + fillParamsToFields("post_1_tap", sltpParams[SLTP_NDR_FIR_POST1], fields); } } catch (const std::exception& exc) diff --git a/mlxlink/modules/mlxlink_amBER_collector.h b/mlxlink/modules/mlxlink_amBER_collector.h index fb7d8571..22de9c3d 100644 --- a/mlxlink/modules/mlxlink_amBER_collector.h +++ b/mlxlink/modules/mlxlink_amBER_collector.h @@ -123,6 +123,7 @@ class MlxlinkAmBerCollector : public MlxlinkRegParser void groupValidIf(bool condition); void getTestModeModulePMPT(vector& fields, string moduleSide, ModuleAccess_t mode); void getTestModeModulePMPD(vector& fields, string moduleSide); + u_int32_t getFomMeasurement(); bool _isQsfpCable; bool _isSfpCable; diff --git a/mlxlink/modules/mlxlink_commander.cpp b/mlxlink/modules/mlxlink_commander.cpp index dec2699b..6f17bf87 100644 --- a/mlxlink/modules/mlxlink_commander.cpp +++ b/mlxlink/modules/mlxlink_commander.cpp @@ -1715,46 +1715,48 @@ string MlxlinkCommander::getComplianceLabel(u_int32_t compliance, u_int32_t extC return complianceLabel; } -void MlxlinkCommander::prepareSltp28_40nm(std::vector >& sltpLanes, u_int32_t laneNumber) +string MlxlinkCommander::getSltpFieldStr(const PRM_FIELD& field) { - sltpLanes[laneNumber].push_back(getFieldStr("polarity")); - sltpLanes[laneNumber].push_back(getFieldStr("ob_tap0")); - sltpLanes[laneNumber].push_back(getFieldStr("ob_tap1")); - sltpLanes[laneNumber].push_back(getFieldStr("ob_tap2")); - sltpLanes[laneNumber].push_back(getFieldStr("ob_bias")); - sltpLanes[laneNumber].push_back(getFieldStr("ob_preemp_mode")); - if (_userInput._advancedMode) + string fieldStr = getFieldStr(field.prmField); + if (field.isSigned) { - sltpLanes[laneNumber].push_back(getFieldStr("ob_reg")); - sltpLanes[laneNumber].push_back(getFieldStr("ob_leva")); + fieldStr = to_string(readSigned(getFieldValue(field.prmField), getFieldSize(field.prmField))); } + return MlxlinkRecord::addSpace(fieldStr, field.uiField.size() + 1, false); } -void MlxlinkCommander::prepareSltp16nm(std::vector >& sltpLanes, u_int32_t laneNumber) +void MlxlinkCommander::prepareSltpEdrHdrGen(vector>& sltpLanes, u_int32_t laneNumber) { - // The first four fields are stored as a signed integers - sltpLanes[laneNumber].push_back(to_string(readSignedByte(getFieldValue("pre_2_tap")))); - sltpLanes[laneNumber].push_back(to_string(readSignedByte(getFieldValue("pre_tap")))); - sltpLanes[laneNumber].push_back(to_string(readSignedByte(getFieldValue("main_tap")))); - sltpLanes[laneNumber].push_back(to_string(readSignedByte(getFieldValue("post_tap")))); - sltpLanes[laneNumber].push_back(to_string(readSigned(getFieldValue("ob_m2lp"), getFieldSize("ob_m2lp")))); - sltpLanes[laneNumber].push_back(getFieldStr("ob_amp")); + map sltpParam = _mlxlinkMaps->_SltpEdrParams; + if (_productTechnology == PRODUCT_16NM) + { + sltpParam = _mlxlinkMaps->_SltpHdrParams; + } + + for (auto const& param : sltpParam) + { + if ((param.second.fieldAccess & FIELD_ACCESS_R) || + (_userInput._advancedMode && (param.second.fieldAccess & FIELD_ACCESS_ADVANCED))) + { + sltpLanes[laneNumber].push_back(getSltpFieldStr(param.second)); + } + } } -void MlxlinkCommander::prepareSltp7nm(std::vector >& sltpLanes, u_int32_t laneNumber) +void MlxlinkCommander::prepareSltpNdrGen(std::vector>& sltpLanes, u_int32_t laneNumber) { if (isSpeed100GPerLane(_protoActive == IB ? _activeSpeed : _activeSpeedEx, _protoActive)) { - sltpLanes[laneNumber].push_back(to_string(readSignedByte(getFieldValue("fir_pre3")))); - sltpLanes[laneNumber].push_back(to_string(readSignedByte(getFieldValue("fir_pre2")))); + sltpLanes[laneNumber].push_back(getSltpFieldStr(_mlxlinkMaps->_SltpNdrParams[SLTP_NDR_FIR_PRE3])); + sltpLanes[laneNumber].push_back(getSltpFieldStr(_mlxlinkMaps->_SltpNdrParams[SLTP_NDR_FIR_PRE2])); } else if (isSpeed50GPerLane(_protoActive == IB ? _activeSpeed : _activeSpeedEx, _protoActive)) { - sltpLanes[laneNumber].push_back(to_string(readSignedByte(getFieldValue("fir_pre2")))); + sltpLanes[laneNumber].push_back(getSltpFieldStr(_mlxlinkMaps->_SltpNdrParams[SLTP_NDR_FIR_PRE2])); } - sltpLanes[laneNumber].push_back(to_string(readSignedByte(getFieldValue("fir_pre1")))); - sltpLanes[laneNumber].push_back(to_string(readSignedByte(getFieldValue("fir_main")))); - sltpLanes[laneNumber].push_back(to_string(readSignedByte(getFieldValue("fir_post1")))); + sltpLanes[laneNumber].push_back(getSltpFieldStr(_mlxlinkMaps->_SltpNdrParams[SLTP_NDR_FIR_PRE1])); + sltpLanes[laneNumber].push_back(getSltpFieldStr(_mlxlinkMaps->_SltpNdrParams[SLTP_NDR_FIR_MAIN])); + sltpLanes[laneNumber].push_back(getSltpFieldStr(_mlxlinkMaps->_SltpNdrParams[SLTP_NDR_FIR_POST1])); } template @@ -2498,15 +2500,14 @@ void MlxlinkCommander::prepare7nmEyeInfo(u_int32_t numOfLanesToUse) string fomMode = _mlxlinkMaps->_slrgFomMode[getFieldValue("fom_mode")]; setPrintVal(_eyeOpeningInfoCmd, "FOM Mode", fomMode, ANSI_COLOR_RESET, true, true, true); setPrintVal(_eyeOpeningInfoCmd, "Lane", getStringFromVector(legand), ANSI_COLOR_RESET, true, true, true); - setPrintVal(_eyeOpeningInfoCmd, "Initial FOM", getStringFromVector(initialFom), ANSI_COLOR_RESET, - !initialFom.empty(), true, true); + setPrintVal(_eyeOpeningInfoCmd, "Initial FOM", getStringFromVector(initialFom), ANSI_COLOR_RESET, true, true, true); setPrintVal(_eyeOpeningInfoCmd, "Last FOM", getStringFromVector(lastFom), ANSI_COLOR_RESET, true, true, true); - setPrintVal(_eyeOpeningInfoCmd, "Upper Grades", getStringFromVector(upperFom), ANSI_COLOR_RESET, true, - (fomMeasurement & SLRG_EOM_UPPER), true); - setPrintVal(_eyeOpeningInfoCmd, "Mid Grades", getStringFromVector(midFom), ANSI_COLOR_RESET, true, - (fomMeasurement & SLRG_EOM_MIDDLE), true); - setPrintVal(_eyeOpeningInfoCmd, "Lower Grades", getStringFromVector(lowerFom), ANSI_COLOR_RESET, true, - (fomMeasurement & SLRG_EOM_LOWER), true); + setPrintVal(_eyeOpeningInfoCmd, "Upper Grades", getStringFromVector(upperFom), ANSI_COLOR_RESET, + (fomMeasurement & SLRG_EOM_UPPER), true, true); + setPrintVal(_eyeOpeningInfoCmd, "Mid Grades", getStringFromVector(midFom), ANSI_COLOR_RESET, + (fomMeasurement & SLRG_EOM_MIDDLE), true, true); + setPrintVal(_eyeOpeningInfoCmd, "Lower Grades", getStringFromVector(lowerFom), ANSI_COLOR_RESET, + (fomMeasurement & SLRG_EOM_LOWER), true, true); } void MlxlinkCommander::showEye() @@ -2670,6 +2671,55 @@ void MlxlinkCommander::showFEC() } } +string MlxlinkCommander::getSltpHeader() +{ + string sep = ","; + vector sltpHeader; + map sltpParam = _mlxlinkMaps->_SltpNdrParams; + + if (_productTechnology == PRODUCT_7NM) + { + bool is100gPerLane = isSpeed100GPerLane(_protoActive == IB ? _activeSpeed : _activeSpeedEx, _protoActive); + bool is50gPerLane = isSpeed50GPerLane(_protoActive == IB ? _activeSpeed : _activeSpeedEx, _protoActive); + if (is100gPerLane) + { + sltpHeader.push_back(MlxlinkRecord::addSpace(sltpParam[SLTP_NDR_FIR_PRE3].uiField, + sltpParam[SLTP_NDR_FIR_PRE3].uiField.size() + 1, false)); + } + if (is50gPerLane || is100gPerLane) + { + sltpHeader.push_back(MlxlinkRecord::addSpace(sltpParam[SLTP_NDR_FIR_PRE2].uiField, + sltpParam[SLTP_NDR_FIR_PRE2].uiField.size() + 1, false)); + } + sltpHeader.push_back(MlxlinkRecord::addSpace(sltpParam[SLTP_NDR_FIR_PRE1].uiField, + sltpParam[SLTP_NDR_FIR_PRE1].uiField.size() + 1, false)); + sltpHeader.push_back(MlxlinkRecord::addSpace(sltpParam[SLTP_NDR_FIR_MAIN].uiField, + sltpParam[SLTP_NDR_FIR_MAIN].uiField.size() + 1, false)); + sltpHeader.push_back(MlxlinkRecord::addSpace(sltpParam[SLTP_NDR_FIR_POST1].uiField, + sltpParam[SLTP_NDR_FIR_POST1].uiField.size() + 1, false)); + } + else + { + sltpParam = _mlxlinkMaps->_SltpEdrParams; + if (_productTechnology == PRODUCT_16NM) + { + sltpParam = _mlxlinkMaps->_SltpHdrParams; + } + + for (auto const& param : sltpParam) + { + if ((param.second.fieldAccess & FIELD_ACCESS_R) || + (_userInput._advancedMode && (param.second.fieldAccess & FIELD_ACCESS_ADVANCED))) + { + sltpHeader.push_back( + MlxlinkRecord::addSpace(param.second.uiField, param.second.uiField.size() + 1, false)); + } + } + } + + return getStringFromVector(sltpHeader); +} + void MlxlinkCommander::showSltp() { if (_userInput._pcie) @@ -2678,75 +2728,50 @@ void MlxlinkCommander::showSltp() } try { - string regName = "SLTP"; - bool valid = true; u_int32_t numOfLanesToUse = (_userInput._pcie) ? _numOfLanesPcie : _numOfLanes; - std::vector > sltpLanes(numOfLanesToUse, std::vector()); + std::vector> sltpLanes(numOfLanesToUse, std::vector()); string showSltpTitle = "Serdes Tuning Transmitter Info"; + string sltpHeader = getSltpHeader(); + if (_userInput._pcie) { showSltpTitle += " (PCIe)"; } setPrintTitle(_sltpInfoCmd, showSltpTitle, numOfLanesToUse + 1); - if (_productTechnology == PRODUCT_7NM) - { - _mlxlinkMaps->_sltpHeader = "fir_pre1,fir_main,fir_post1"; - if (isSpeed100GPerLane(_protoActive == IB ? _activeSpeed : _activeSpeedEx, _protoActive)) - { - _mlxlinkMaps->_sltpHeader = "fir_pre3,fir_pre2," + _mlxlinkMaps->_sltpHeader; - } - else if (isSpeed50GPerLane(_protoActive == IB ? _activeSpeed : _activeSpeedEx, _protoActive)) - { - _mlxlinkMaps->_sltpHeader = "fir_pre2," + _mlxlinkMaps->_sltpHeader; - } - } - else if (_productTechnology == PRODUCT_16NM) - { - _mlxlinkMaps->_sltpHeader = "pre2Tap,preTap,mainTap,postTap,m2lp,amp"; - } - else - { - _mlxlinkMaps->_sltpHeader = "Pol,tap0,tap1,tap2,bias,preemp_mode"; - if (_userInput._advancedMode) - { - _mlxlinkMaps->_sltpHeader += ",reg,leva"; - } - } + if (!_linkUP && !_userInput._pcie && !_prbsTestMode) { - setPrintVal(_sltpInfoCmd, "Serdes TX parameters", _mlxlinkMaps->_sltpHeader, ANSI_COLOR_RESET, true, false, - true); + setPrintVal(_sltpInfoCmd, "Serdes TX parameters", sltpHeader, ANSI_COLOR_RESET, true, false, true); cout << _sltpInfoCmd; return; } - setPrintVal(_sltpInfoCmd, "Serdes TX parameters", _mlxlinkMaps->_sltpHeader, ANSI_COLOR_RESET, true, true, - true); + setPrintVal(_sltpInfoCmd, "Serdes TX parameters", sltpHeader, ANSI_COLOR_RESET, true, true, true); + for (u_int32_t i = 0; i < numOfLanesToUse; i++) { - resetParser(regName); + resetParser(ACCESS_REG_SLTP); updatePortType(); updateField("local_port", _localPort); updateField("pnat", (_userInput._pcie) ? PNAT_PCIE : PNAT_LOCAL); updateField("lane", i); updateField("c_db", _userInput._db); - genBuffSendRegister(regName, MACCESS_REG_METHOD_GET); - if (_productTechnology == PRODUCT_16NM) - { - prepareSltp16nm(sltpLanes, i); - } - else if (_productTechnology == PRODUCT_7NM) + genBuffSendRegister(ACCESS_REG_SLTP, MACCESS_REG_METHOD_GET); + + if (_productTechnology == PRODUCT_7NM) { - prepareSltp7nm(sltpLanes, i); + prepareSltpNdrGen(sltpLanes, i); } else { - prepareSltp28_40nm(sltpLanes, i); + prepareSltpEdrHdrGen(sltpLanes, i); } + if (!getFieldValue("status")) { valid = false; } + setPrintVal(_sltpInfoCmd, "Lane " + to_string(i), getStringFromVector(sltpLanes[i]), ANSI_COLOR_RESET, true, valid, true); } @@ -3857,6 +3882,22 @@ void MlxlinkCommander::checkPRBSModeCap(u_int32_t modeSelector, u_int32_t capMas modeToCheck += "A"; } + switch (modeToCheck[-1]) + { + case '8': + findAndReplace(modeToCheck, "8", "A"); + break; + case '4': + findAndReplace(modeToCheck, "4", "B"); + break; + case '2': + findAndReplace(modeToCheck, "2", "C"); + break; + case '1': + findAndReplace(modeToCheck, "1", "D"); + break; + } + // Fetching mode capability from mode list u_int32_t modeCap = 0; @@ -4521,7 +4562,7 @@ void MlxlinkCommander::getSltpAlevOut(u_int32_t lane) genBuffSendRegister(ACCESS_REG_SLTP, MACCESS_REG_METHOD_GET); - _userInput._sltpParams[OB_ALEV_OUT] = getFieldValue("ob_alev_out"); + _userInput._sltpParams[SLTP_HDR_OB_ALEV_OUT] = getFieldValue("ob_alev_out"); } void MlxlinkCommander::getSltpRegAndLeva(u_int32_t lane) @@ -4534,8 +4575,8 @@ void MlxlinkCommander::getSltpRegAndLeva(u_int32_t lane) genBuffSendRegister(ACCESS_REG_SLTP, MACCESS_REG_METHOD_GET); - _userInput._sltpParams[OB_REG] = getFieldValue("ob_reg"); - _userInput._sltpParams[OB_LEVA] = getFieldValue("ob_leva"); + _userInput._sltpParams[SLTP_EDR_OB_REG] = getFieldValue("ob_reg"); + _userInput._sltpParams[SLTP_EDR_OB_LEVA] = getFieldValue("ob_leva"); } u_int32_t MlxlinkCommander::getLaneSpeed(u_int32_t lane) @@ -4558,17 +4599,17 @@ void MlxlinkCommander::validateNumOfParamsForNDRGen() errMsg += "valid parameters for the active speed are: "; if (isSpeed100GPerLane(_protoActive == IB ? _activeSpeed : _activeSpeedEx, _protoActive)) { - params = PARAMS_7NM_LAST; + params = SLTP_NDR_LAST; errMsg += "fir_pre3,fir_pre2,fir_pre1,fir_main,fir_post1"; } else if (isSpeed50GPerLane(_protoActive == IB ? _activeSpeed : _activeSpeedEx, _protoActive)) { - params = FIR_POST1; + params = SLTP_NDR_FIR_POST1; errMsg += "fir_pre2,fir_pre1,fir_main,fir_post1"; } else { - params = FIR_MAIN; + params = SLTP_NDR_FIR_MAIN; errMsg += "fir_pre1,fir_main,fir_post1"; } if (_userInput._sltpParams.size() != params) @@ -4587,10 +4628,10 @@ void MlxlinkCommander::validateNumOfParamsForNDRGen() void MlxlinkCommander::checkSltpParamsSize() { - u_int32_t sltpParamsSize = OB_REG; + u_int32_t sltpParamsSize = SLTP_EDR_OB_REG; if (_productTechnology == PRODUCT_16NM) { - sltpParamsSize = OB_ALEV_OUT; + sltpParamsSize = SLTP_HDR_OB_ALEV_OUT; for (map::iterator it = _userInput._sltpParams.begin(); it != _userInput._sltpParams.end(); it++) @@ -4607,7 +4648,7 @@ void MlxlinkCommander::checkSltpParamsSize() } else if (_userInput._advancedMode) { - sltpParamsSize = PARAMS_40NM_LAST; + sltpParamsSize = SLTP_EDR_LAST; } if (_userInput._sltpParams.size() != sltpParamsSize && _productTechnology != PRODUCT_7NM) { @@ -4615,49 +4656,43 @@ void MlxlinkCommander::checkSltpParamsSize() } } -void MlxlinkCommander::updateSltp28_40nmFields() +void MlxlinkCommander::updateSltpEdrHdrFields() { - updateField("polarity", _userInput._sltpParams[POLARITY]); - updateField("ob_tap0", _userInput._sltpParams[OB_TAP0]); - updateField("ob_tap1", _userInput._sltpParams[OB_TAP1]); - updateField("ob_tap2", _userInput._sltpParams[OB_TAP2]); - updateField("ob_bias", _userInput._sltpParams[OB_BIAS]); - updateField("ob_preemp_mode", _userInput._sltpParams[OB_PREEMP_MODE]); - updateField("ob_reg", _userInput._sltpParams[OB_REG]); - updateField("ob_leva", _userInput._sltpParams[OB_LEVA]); -} + map sltpParam = _mlxlinkMaps->_SltpEdrParams; + if (_productTechnology == PRODUCT_16NM) + { + sltpParam = _mlxlinkMaps->_SltpHdrParams; + } -void MlxlinkCommander::updateSltp16nmFields() -{ - updateField("pre_2_tap", _userInput._sltpParams[PRE_2_TAP]); - updateField("pre_tap", _userInput._sltpParams[PRE_TAP]); - updateField("main_tap", _userInput._sltpParams[MAIN_TAP]); - updateField("post_tap", _userInput._sltpParams[POST_TAP]); - updateField("ob_m2lp", _userInput._sltpParams[OB_M2LP]); - updateField("ob_amp", _userInput._sltpParams[OB_AMP]); - updateField("ob_alev_out", _userInput._sltpParams[OB_ALEV_OUT]); + for (auto const& param : sltpParam) + { + if (param.second.fieldAccess & (FIELD_ACCESS_W | FIELD_ACCESS_ADVANCED)) + { + updateField(param.second.prmField, _userInput._sltpParams[param.first]); + } + } } -void MlxlinkCommander::updateSltp7nmFields() +void MlxlinkCommander::updateSltpNdrFields() { u_int32_t indexCorrection = 0; if (isSpeed100GPerLane(_protoActive == IB ? _activeSpeed : _activeSpeedEx, _protoActive)) { - updateField("fir_pre3", _userInput._sltpParams[FIR_PRE3]); - updateField("fir_pre2", _userInput._sltpParams[FIR_PRE2]); + updateField("fir_pre3", _userInput._sltpParams[SLTP_NDR_FIR_PRE3]); + updateField("fir_pre2", _userInput._sltpParams[SLTP_NDR_FIR_PRE2]); } else if (isSpeed50GPerLane(_protoActive == IB ? _activeSpeed : _activeSpeedEx, _protoActive)) { indexCorrection = 1; - updateField("fir_pre2", _userInput._sltpParams[FIR_PRE2 - indexCorrection]); + updateField("fir_pre2", _userInput._sltpParams[SLTP_NDR_FIR_PRE2 - indexCorrection]); } else { indexCorrection = 2; } - updateField("fir_pre1", _userInput._sltpParams[FIR_PRE1 - indexCorrection]); - updateField("fir_main", _userInput._sltpParams[FIR_MAIN - indexCorrection]); - updateField("fir_post1", _userInput._sltpParams[FIR_POST1 - indexCorrection]); + updateField("fir_pre1", _userInput._sltpParams[SLTP_NDR_FIR_PRE1 - indexCorrection]); + updateField("fir_main", _userInput._sltpParams[SLTP_NDR_FIR_MAIN - indexCorrection]); + updateField("fir_post1", _userInput._sltpParams[SLTP_NDR_FIR_POST1 - indexCorrection]); } string MlxlinkCommander::getSltpStatus() @@ -4741,19 +4776,16 @@ void MlxlinkCommander::sendSltp() updateField("lane_speed", laneSpeed); updateField("lane", i); updateField("tx_policy", _userInput._txPolicy); - switch (_productTechnology) + + if (_productTechnology == PRODUCT_7NM) { - case PRODUCT_40NM: - case PRODUCT_28NM: - updateSltp28_40nmFields(); - break; - case PRODUCT_16NM: - updateSltp16nmFields(); - break; - case PRODUCT_7NM: - updateSltp7nmFields(); - break; + updateSltpNdrFields(); } + else + { + updateSltpEdrHdrFields(); + } + updateField("c_db", _userInput._db || _userInput._txPolicy); genBuffSendRegister(ACCESS_REG_SLTP, MACCESS_REG_METHOD_SET); } diff --git a/mlxlink/modules/mlxlink_commander.h b/mlxlink/modules/mlxlink_commander.h index 24445550..03bb9d22 100644 --- a/mlxlink/modules/mlxlink_commander.h +++ b/mlxlink/modules/mlxlink_commander.h @@ -435,9 +435,10 @@ class MlxlinkCommander : public MlxlinkRegParser void strToInt32(char* str, u_int32_t& value); template string getValueAndThresholdsStr(T value, Q lowTH, Q highTH); - void prepareSltp28_40nm(std::vector >& sltpLanes, u_int32_t laneNumber); - void prepareSltp16nm(std::vector >& sltpLanes, u_int32_t laneNumber); - void prepareSltp7nm(std::vector >& sltpLanes, u_int32_t laneNumber); + string getSltpFieldStr(const PRM_FIELD& field); + void prepareSltpEdrHdrGen(vector>& sltpLanes, u_int32_t laneNumber); + virtual void prepareSltpNdrGen(vector>& sltpLanes, u_int32_t laneNumber); + virtual string getSltpHeader(); void startSlrgPciScan(u_int32_t numOfLanesToUse); void initValidDPNList(); u_int32_t readBitFromField(const string& fieldName, u_int32_t bitIndex); @@ -562,9 +563,8 @@ class MlxlinkCommander : public MlxlinkRegParser u_int32_t fecToBit(const string& fec, const string& speedStrG); u_int32_t getFecCapForCheck(const string& speedStr); void checkPplmCap(); - void updateSltp28_40nmFields(); - void updateSltp16nmFields(); - void updateSltp7nmFields(); + void updateSltpEdrHdrFields(); + void updateSltpNdrFields(); string getSltpStatus(); void getSltpAlevOut(u_int32_t lane); void getSltpRegAndLeva(u_int32_t lane); diff --git a/mlxlink/modules/mlxlink_enums.h b/mlxlink/modules/mlxlink_enums.h index c9c40bc2..d33ea596 100644 --- a/mlxlink/modules/mlxlink_enums.h +++ b/mlxlink/modules/mlxlink_enums.h @@ -400,6 +400,13 @@ #define SECOND_LEVEL_PORT_ACCESS 2 #define THIRD_LEVEL_PORT_ACCESS 3 +enum FIELD_ACCESS +{ + FIELD_ACCESS_R = 0x1, + FIELD_ACCESS_W = 0x2, + FIELD_ACCESS_RW = FIELD_ACCESS_R | FIELD_ACCESS_W, + FIELD_ACCESS_ADVANCED = 0x8, +}; // mlxlink commander enums enum PPAOS_ADMIN { @@ -660,39 +667,39 @@ enum SLRG_PARAMS SLRG_PARAMS_LAST }; -enum SLTP_40_28NM_PARAMS +enum SLTP_EDR { - POLARITY, - OB_TAP0, - OB_TAP1, - OB_TAP2, - OB_BIAS, - OB_PREEMP_MODE, - OB_REG, - OB_LEVA, - PARAMS_40NM_LAST + SLTP_EDR_POLARITY, + SLTP_EDR_OB_TAP0, + SLTP_EDR_OB_TAP1, + SLTP_EDR_OB_TAP2, + SLTP_EDR_OB_BIAS, + SLTP_EDR_OB_PREEMP_MODE, + SLTP_EDR_OB_REG, + SLTP_EDR_OB_LEVA, + SLTP_EDR_LAST }; -enum SLTP_16NM_PARAMS +enum SLTP_HDR { - PRE_2_TAP, - PRE_TAP, - MAIN_TAP, - POST_TAP, - OB_M2LP, - OB_AMP, - OB_ALEV_OUT, - PARAMS_16NM_LAST + SLTP_HDR_PRE_2_TAP, + SLTP_HDR_PRE_TAP, + SLTP_HDR_MAIN_TAP, + SLTP_HDR_POST_TAP, + SLTP_HDR_OB_M2LP, + SLTP_HDR_OB_AMP, + SLTP_HDR_OB_ALEV_OUT, + SLTP_HDR_LAST }; -enum SLTP_7NM_PARAMS +enum SLTP_NDR { - FIR_PRE3, - FIR_PRE2, - FIR_PRE1, - FIR_MAIN, - FIR_POST1, - PARAMS_7NM_LAST + SLTP_NDR_FIR_PRE3, + SLTP_NDR_FIR_PRE2, + SLTP_NDR_FIR_PRE1, + SLTP_NDR_FIR_MAIN, + SLTP_NDR_FIR_POST1, + SLTP_NDR_LAST }; enum FEC_MODE diff --git a/mlxlink/modules/mlxlink_maps.cpp b/mlxlink/modules/mlxlink_maps.cpp index ba0069a1..7fbd9fb1 100644 --- a/mlxlink/modules/mlxlink_maps.cpp +++ b/mlxlink/modules/mlxlink_maps.cpp @@ -580,6 +580,29 @@ void MlxlinkMaps::initLinkDownInfoMapping() void MlxlinkMaps::initSltpStatusMapping() { + _SltpEdrParams[SLTP_EDR_POLARITY] = PRM_FIELD{"polarity", "Pol", FIELD_ACCESS_RW, false}; + _SltpEdrParams[SLTP_EDR_OB_TAP0] = PRM_FIELD{"ob_tap0", "tap0", FIELD_ACCESS_RW, false}; + _SltpEdrParams[SLTP_EDR_OB_TAP1] = PRM_FIELD{"ob_tap1", "tap1", FIELD_ACCESS_RW, false}; + _SltpEdrParams[SLTP_EDR_OB_TAP2] = PRM_FIELD{"ob_tap2", "tap2", FIELD_ACCESS_RW, false}; + _SltpEdrParams[SLTP_EDR_OB_BIAS] = PRM_FIELD{"ob_bias", "bias", FIELD_ACCESS_RW, false}; + _SltpEdrParams[SLTP_EDR_OB_PREEMP_MODE] = PRM_FIELD{"ob_preemp_mode", "preemp_mode", FIELD_ACCESS_RW, false}; + _SltpEdrParams[SLTP_EDR_OB_REG] = PRM_FIELD{"ob_reg", "reg", FIELD_ACCESS_ADVANCED, false}; + _SltpEdrParams[SLTP_EDR_OB_LEVA] = PRM_FIELD{"ob_leva", "leva", FIELD_ACCESS_ADVANCED, false}; + + _SltpHdrParams[SLTP_HDR_PRE_2_TAP] = PRM_FIELD{"pre_2_tap", "pre2Tap", FIELD_ACCESS_RW, true}; + _SltpHdrParams[SLTP_HDR_PRE_TAP] = PRM_FIELD{"pre_tap", "preTap", FIELD_ACCESS_RW, true}; + _SltpHdrParams[SLTP_HDR_MAIN_TAP] = PRM_FIELD{"main_tap", "mainTap", FIELD_ACCESS_RW, true}; + _SltpHdrParams[SLTP_HDR_POST_TAP] = PRM_FIELD{"post_tap", "postTap", FIELD_ACCESS_RW, true}; + _SltpHdrParams[SLTP_HDR_OB_M2LP] = PRM_FIELD{"ob_m2lp", "m2lp", FIELD_ACCESS_RW, true}; + _SltpHdrParams[SLTP_HDR_OB_AMP] = PRM_FIELD{"ob_amp", "amp", FIELD_ACCESS_RW, false}; + _SltpHdrParams[SLTP_HDR_OB_ALEV_OUT] = PRM_FIELD{"ob_alev_out", "alev_out", FIELD_ACCESS_W, false}; + + _SltpNdrParams[SLTP_NDR_FIR_PRE3] = PRM_FIELD{"fir_pre3", "fir_pre3", FIELD_ACCESS_RW, true}; + _SltpNdrParams[SLTP_NDR_FIR_PRE2] = PRM_FIELD{"fir_pre2", "fir_pre2", FIELD_ACCESS_RW, true}; + _SltpNdrParams[SLTP_NDR_FIR_PRE1] = PRM_FIELD{"fir_pre1", "fir_pre1", FIELD_ACCESS_RW, true}; + _SltpNdrParams[SLTP_NDR_FIR_MAIN] = PRM_FIELD{"fir_main", "fir_main", FIELD_ACCESS_RW, true}; + _SltpNdrParams[SLTP_NDR_FIR_POST1] = PRM_FIELD{"fir_post1", "fir_post1", FIELD_ACCESS_RW, true}; + _SLTP7BadSetStatus2Str[BAD_STAT_7NM_INVALID_PRE3] = "pre3 is out of range"; _SLTP7BadSetStatus2Str[BAD_STAT_7NM_INVALID_PRE2] = "pre2 is out of range"; _SLTP7BadSetStatus2Str[BAD_STAT_7NM_INVALID_PRE1] = "pre1 is out of range"; diff --git a/mlxlink/modules/mlxlink_maps.h b/mlxlink/modules/mlxlink_maps.h index 141c2d21..1ea5fa98 100644 --- a/mlxlink/modules/mlxlink_maps.h +++ b/mlxlink/modules/mlxlink_maps.h @@ -106,6 +106,14 @@ struct CAP_VALUE string name; }; +struct PRM_FIELD +{ + string prmField; + string uiField; + u_int32_t fieldAccess; + bool isSigned; +}; + class MlxlinkMaps { private: @@ -200,6 +208,9 @@ class MlxlinkMaps std::map _SLTPBadSetStatus2Str; std::map _SLTP16BadSetStatus2Str; std::map _SLTP7BadSetStatus2Str; + std::map _SltpEdrParams; + std::map _SltpHdrParams; + std::map _SltpNdrParams; std::map _ethANFsmState; std::map _fecModeActive; std::map> _fecModeMask; From 118451cb438523bc33633e056a7314d55493721c Mon Sep 17 00:00:00 2001 From: Mustafa Dalloul Date: Sun, 3 Jul 2022 14:53:45 +0300 Subject: [PATCH 13/46] [mstlink] Fixing code coverity issues Description: Fixing code coverity issues and code align with MFT Signed-off-by: Mustafa Dalloul --- mlxlink/modules/mlxlink_amBER_collector.h | 2 +- mlxlink/modules/mlxlink_cables_commander.cpp | 16 ++++++++-------- mlxlink/modules/mlxlink_maps.h | 1 + mlxlink/modules/mlxlink_reg_parser.h | 1 + mlxlink/modules/mlxlink_utils.cpp | 4 ++++ 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/mlxlink/modules/mlxlink_amBER_collector.h b/mlxlink/modules/mlxlink_amBER_collector.h index 9adbaa26..fe3fb024 100644 --- a/mlxlink/modules/mlxlink_amBER_collector.h +++ b/mlxlink/modules/mlxlink_amBER_collector.h @@ -124,8 +124,8 @@ class MlxlinkAmBerCollector : public MlxlinkRegParser void groupValidIf(bool condition); void getTestModeModulePMPT(vector& fields, string moduleSide, ModuleAccess_t mode); void getTestModeModulePMPD(vector& fields, string moduleSide); - u_int32_t getFomMeasurement(); u_int32_t getSheetIndex(AMBER_SHEET sheet); + u_int32_t getFomMeasurement(); bool _isQsfpCable; bool _isSfpCable; diff --git a/mlxlink/modules/mlxlink_cables_commander.cpp b/mlxlink/modules/mlxlink_cables_commander.cpp index bd77389a..b5507748 100644 --- a/mlxlink/modules/mlxlink_cables_commander.cpp +++ b/mlxlink/modules/mlxlink_cables_commander.cpp @@ -419,7 +419,7 @@ void MlxlinkCablesCommander::prepareSfpddDdmInfo() void MlxlinkCablesCommander::prepareQSFPDdmInfo() { u_int32_t tempVal = 0; - u_int8_t* page0L = (u_int8_t*)malloc(sizeof(u_int8_t) * CABLE_PAGE_SIZE); + u_int8_t* page0L = (u_int8_t*)calloc(CABLE_PAGE_SIZE, sizeof(u_int8_t)); if (page0L != NULL) { loadEEPRMPage(PAGE_0, LOWER_PAGE_OFFSET, page0L); @@ -552,7 +552,7 @@ void MlxlinkCablesCommander::prepareThresholdInfo(u_int8_t* thresholdPage) // Reading cable DDM information void MlxlinkCablesCommander::readCableDDMInfo() { - u_int8_t* thresholdPage = (u_int8_t*)malloc(sizeof(u_int8_t) * CABLE_PAGE_SIZE); + u_int8_t* thresholdPage = (u_int8_t*)calloc(CABLE_PAGE_SIZE, sizeof(u_int8_t)); switch (_cableIdentifier) { @@ -795,7 +795,7 @@ void MlxlinkCablesCommander::initValidPages() } if (qsfpCable && !_passiveQsfp) { - u_int8_t* page0H = (u_int8_t*)malloc(sizeof(u_int8_t) * CABLE_PAGE_SIZE); + u_int8_t* page0H = (u_int8_t*)calloc(CABLE_PAGE_SIZE, sizeof(u_int8_t)); loadEEPRMPage(PAGE_0, UPPER_PAGE_OFFSET, page0H); u_int8_t optionsValue = 0; readFromPage(page0H, 195 - 0x80, &optionsValue); @@ -830,7 +830,7 @@ void MlxlinkCablesCommander::initValidPages() // (SFP-DD) // if 2:7=0, dump page 0x1 u_int8_t extendedPages = 0; - u_int8_t* page0L = (u_int8_t*)malloc(sizeof(u_int8_t) * CABLE_PAGE_SIZE); + u_int8_t* page0L = (u_int8_t*)calloc(CABLE_PAGE_SIZE, sizeof(u_int8_t)); loadEEPRMPage(PAGE_0, LOWER_PAGE_OFFSET, page0L); ; readFromPage(page0L, EXTENDED_PAGES_1_2_10_11_ADDR, &extendedPages); @@ -852,7 +852,7 @@ void MlxlinkCablesCommander::initValidPages() // dump page 0x12 (H) // B142:5=1, dump page 0x13 (H) // dump page 0x14 (H) - u_int8_t* page1H = (u_int8_t*)malloc(sizeof(u_int8_t) * CABLE_PAGE_SIZE); + u_int8_t* page1H = (u_int8_t*)calloc(CABLE_PAGE_SIZE, sizeof(u_int8_t)); loadEEPRMPage(PAGE_01, UPPER_PAGE_OFFSET, page1H); ; u_int8_t extendedQsfpPages = 0; @@ -885,7 +885,7 @@ vector MlxlinkCablesCommander::getPagesToDump() initValidPages(); for (u_int32_t i = 0; i < _validPages.size(); i++) { - u_int8_t* pageP = (u_int8_t*)malloc(sizeof(u_int8_t) * CABLE_PAGE_SIZE); + u_int8_t* pageP = (u_int8_t*)calloc(CABLE_PAGE_SIZE, sizeof(u_int8_t)); if (pageP != NULL) { loadEEPRMPage(_validPages[i].page, _validPages[i].offset, pageP, _validPages[i].i2cAddress); @@ -998,11 +998,11 @@ MlxlinkCmdPrint MlxlinkCablesCommander::readFromEEPRM(u_int16_t page, u_int16_t { i2cAddress = I2C_ADDR_HIGH; } - pageL = (u_int8_t*)malloc(sizeof(u_int8_t) * CABLE_PAGE_SIZE); + pageL = (u_int8_t*)calloc(CABLE_PAGE_SIZE, sizeof(u_int8_t)); loadEEPRMPage(page, LOWER_PAGE_OFFSET, pageL, i2cAddress); if ((length + offset) > CABLE_PAGE_SIZE) { - pageH = (u_int8_t*)malloc(sizeof(u_int8_t) * CABLE_PAGE_SIZE); + pageH = (u_int8_t*)calloc(CABLE_PAGE_SIZE, sizeof(u_int8_t)); loadEEPRMPage(page, UPPER_PAGE_OFFSET, pageH); } char label[32]; diff --git a/mlxlink/modules/mlxlink_maps.h b/mlxlink/modules/mlxlink_maps.h index 1ea5fa98..20c4b154 100644 --- a/mlxlink/modules/mlxlink_maps.h +++ b/mlxlink/modules/mlxlink_maps.h @@ -31,6 +31,7 @@ * */ + #ifndef MLXLINK_MAPS_H #define MLXLINK_MAPS_H diff --git a/mlxlink/modules/mlxlink_reg_parser.h b/mlxlink/modules/mlxlink_reg_parser.h index 189ba8b3..0c7defe4 100644 --- a/mlxlink/modules/mlxlink_reg_parser.h +++ b/mlxlink/modules/mlxlink_reg_parser.h @@ -31,6 +31,7 @@ * */ + #ifndef MLXLINK_REG_PARSER_H #define MLXLINK_REG_PARSER_H diff --git a/mlxlink/modules/mlxlink_utils.cpp b/mlxlink/modules/mlxlink_utils.cpp index 031593b2..f15a2efa 100644 --- a/mlxlink/modules/mlxlink_utils.cpp +++ b/mlxlink/modules/mlxlink_utils.cpp @@ -493,6 +493,10 @@ int ptysSpeedToExtMaskETH(const string& speed) { return ETH_LINK_SPEED_EXT_400GAUI_8; } + if (speed == "800G_8X") + { + return ETH_LINK_SPEED_EXT_800GAUI_8; + } return 0x0; } From 709d32cca69beb99902640151a2cedb7c6e367da Mon Sep 17 00:00:00 2001 From: Matan Eliyahu Date: Sun, 3 Jul 2022 15:36:14 +0300 Subject: [PATCH 14/46] [flint|mlxfwops] Fix error message for dc command on encrypted image Description: dc command isn't supported on encrypted images, error message fixed Tested OS: Linux Tested devices: bb Tested flows: flint -i dc Known gaps (with RM ticket): N/A Issue: 3086580 --- mlxfwops/lib/fs3_ops.cpp | 3 +-- mlxfwops/lib/fs4_ops.cpp | 15 +++++++++++++++ mlxfwops/lib/fs4_ops.h | 1 + 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/mlxfwops/lib/fs3_ops.cpp b/mlxfwops/lib/fs3_ops.cpp index 46365ad9..dbef1c46 100644 --- a/mlxfwops/lib/fs3_ops.cpp +++ b/mlxfwops/lib/fs3_ops.cpp @@ -1411,9 +1411,8 @@ bool Fs3Operations::FwReadRom(std::vector& romSect) return true; } -bool Fs3Operations::FwGetSection(u_int32_t sectType, std::vector& sectInfo, bool stripedImage) +bool Fs3Operations::FwGetSection(u_int32_t sectType, std::vector& sectInfo, bool) { - (void) stripedImage; // unused for FS3 //FwGetSection only supports retrieving FS3_DBG_FW_INI section atm. if (sectType != FS3_DBG_FW_INI) { return errmsg("Unsupported section type."); diff --git a/mlxfwops/lib/fs4_ops.cpp b/mlxfwops/lib/fs4_ops.cpp index 94400d77..85561343 100644 --- a/mlxfwops/lib/fs4_ops.cpp +++ b/mlxfwops/lib/fs4_ops.cpp @@ -958,6 +958,21 @@ bool Fs4Operations::FwVerify(VerifyCallBack verifyCallBackFunc, bool isStripedIm return Fs3Operations::FwVerify(verifyCallBackFunc, isStripedImage, showItoc, ignoreDToc); } +bool Fs4Operations::FwGetSection(u_int32_t sectType, std::vector& sectInfo, bool) +{ + bool image_encrypted = false; + if (!isEncrypted(image_encrypted)) + { + return errmsg(getErrorCode(), "%s", err()); + } + if (image_encrypted) + { + return errmsg("Operation not supported on an encrypted %s", _ioAccess->is_flash() ? "flash" : "image"); + } + + return Fs3Operations::FwGetSection(sectType, sectInfo); +} + bool Fs4Operations::GetImageInfo(u_int8_t *buff) { DPRINTF(("Fs4Operations::GetImageInfo call Fs3Operations::GetImageInfo\n")); diff --git a/mlxfwops/lib/fs4_ops.h b/mlxfwops/lib/fs4_ops.h index f8cd61a8..b8baf21f 100644 --- a/mlxfwops/lib/fs4_ops.h +++ b/mlxfwops/lib/fs4_ops.h @@ -81,6 +81,7 @@ class Fs4Operations : public Fs3Operations { bool FwQueryTimeStamp(struct tools_open_ts_entry& timestamp, struct tools_open_fw_version& fwVer, bool queryRunning = false); bool FwResetTimeStamp(); + virtual bool FwGetSection(u_int32_t sectType, std::vector& sectInfo, bool stripedImage = false); bool FwSignWithHmac(const char *key_file); bool signForSecureBoot(const char *private_key_file, const char *public_key_file, const char *guid_key_file); bool signForSecureBootUsingHSM(const char *public_key_file, const char *uuid, MlxSign::OpensslEngineSigner& engineSigner); From 576e0228d97917f9c6b80971b1372f702115b7f5 Mon Sep 17 00:00:00 2001 From: Matan Eliyahu Date: Sun, 3 Jul 2022 16:24:00 +0300 Subject: [PATCH 15/46] [mlxsign] redundant code removal Description: N/A Tested OS: N/A Tested devices: N/A Tested flows: N/A Known gaps (with RM ticket): N/A Issue: None --- mlxsign_lib/mlxsign_lib.cpp | 57 ------------------------------------- mlxsign_lib/mlxsign_lib.h | 6 ---- 2 files changed, 63 deletions(-) diff --git a/mlxsign_lib/mlxsign_lib.cpp b/mlxsign_lib/mlxsign_lib.cpp index b0f0ddb4..1fa3fcc1 100644 --- a/mlxsign_lib/mlxsign_lib.cpp +++ b/mlxsign_lib/mlxsign_lib.cpp @@ -237,63 +237,6 @@ int MlxSignRSA::verify(MlxSign::SHAType shaType, const std::vector& di return MlxSign::MLX_SIGN_SUCCESS; } -int MlxSignRSA::encrypt(const std::vector& msg, std::vector& encryptedMsg) -{ - int maxMsgSize; - - if (!_privCtx) { - return MlxSign::MLX_SIGN_RSA_NO_PRIV_KEY_ERROR; - } - // size check - maxMsgSize = RSA_size((RSA*)_privCtx); - if (static_cast(msg.size()) > maxMsgSize) { - return MlxSign::MLX_SIGN_RSA_MESSAGE_TOO_LONG_ERROR; - } - // do the job - encryptedMsg.resize(maxMsgSize, 0); - if (RSA_private_encrypt((int)msg.size(), &msg[0], &encryptedMsg[0], (RSA*)_privCtx, RSA_PKCS1_PADDING ) != maxMsgSize) { - return MlxSign::MLX_SIGN_RSA_CALCULATION_ERROR; - } - return MlxSign::MLX_SIGN_SUCCESS; -} - -int MlxSignRSA::decrypt(const std::vector& encryptedMsg, std::vector& originalMsg) -{ - int maxMsgSize; - int origMsgSize; - if (!_pubCtx) { - return MlxSign::MLX_SIGN_RSA_NO_PUB_KEY_ERROR; - } - // size check - maxMsgSize = RSA_size((RSA*)_pubCtx); - if (static_cast(encryptedMsg.size()) > maxMsgSize) { - return MlxSign::MLX_SIGN_RSA_MESSAGE_TOO_LONG_ERROR; - } - // do the job - originalMsg.resize(maxMsgSize, 0); - if ((origMsgSize = RSA_public_decrypt((int)encryptedMsg.size(), &encryptedMsg[0], &originalMsg[0], (RSA*)_pubCtx, RSA_PKCS1_PADDING )) == -1) { - return MlxSign::MLX_SIGN_RSA_CALCULATION_ERROR; - } - originalMsg.resize(origMsgSize); - return MlxSign::MLX_SIGN_SUCCESS; -} - -int MlxSignRSA::getEncryptMaxMsgSize() -{ - if (_privCtx) { - return RSA_size((RSA*)_privCtx); - } - return 0; -} - -int MlxSignRSA::getDecryptMaxMsgSize() -{ - if (_pubCtx) { - return RSA_size((RSA*)_pubCtx); - } - return 0; -} - std::string MlxSignRSA::str(const std::vector& msg) { char *digestStr = NULL; diff --git a/mlxsign_lib/mlxsign_lib.h b/mlxsign_lib/mlxsign_lib.h index 01778304..c18f966d 100644 --- a/mlxsign_lib/mlxsign_lib.h +++ b/mlxsign_lib/mlxsign_lib.h @@ -115,12 +115,6 @@ class MlxSignRSA { int setPubKeyFromFile(const std::string& pemKeyFilePath); int setPubKey(const std::string& pemKey); - int getEncryptMaxMsgSize(); - int getDecryptMaxMsgSize(); - - int encrypt(const std::vector& msg, std::vector& encryptedMsg); // encrypt with private - int decrypt(const std::vector& encryptedMsg, std::vector& originalMsg); // decrypt with public (used for testing for now) - int sign(MlxSign::SHAType shaType, const std::vector& msg, std::vector& encryptedMsg); int verify(MlxSign::SHAType shaType, const std::vector& sha256Dgst, const std::vector& sig, bool& result); From ba4266f8a13d93c99b1532f8825a454caf1a259a Mon Sep 17 00:00:00 2001 From: Matan Eliyahu Date: Sun, 3 Jul 2022 20:55:47 +0300 Subject: [PATCH 16/46] [flint] Coverity fix Description: N/A Tested OS: linux Tested devices: CX3 Tested flows: flint_oem -d /dev/mst/mt4099_pciconf0 hw query Known gaps (with RM ticket): N/A Issue: 3108155 --- mlxfwops/lib/flint_io.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mlxfwops/lib/flint_io.cpp b/mlxfwops/lib/flint_io.cpp index b2dc135a..35cac6d6 100644 --- a/mlxfwops/lib/flint_io.cpp +++ b/mlxfwops/lib/flint_io.cpp @@ -821,7 +821,9 @@ bool Flash::get_attr(ext_flash_attr_t& attr) attr.rev_id = _attr.rev_id; if (_attr.type_str != NULL) { // we don't print the flash type in old devices - attr.type_str = strcpy(new char[strlen(_attr.type_str) + 1], _attr.type_str); + int type_str_len = strlen(_attr.type_str); + attr.type_str = strncpy(new char[type_str_len + 1], _attr.type_str, type_str_len); + attr.type_str[type_str_len] = '\0'; } attr.size = _attr.size; attr.sector_size = _attr.sector_size; From 13b49fd1710cb670f0b100063baa83b6110304d6 Mon Sep 17 00:00:00 2001 From: Matan Eliyahu Date: Sun, 3 Jul 2022 21:15:03 +0300 Subject: [PATCH 17/46] [flint][BF3] Certificate Chain Injection into DIGITAL_CERT_RW section Description: For BF3 we'll need the ability to store certificates in DIGITAL_CERT_RW section. The user will have to provide an index with the certificate to specify where to store it. In case index==0 old set certificate flow will be executed storing the certificate in CERT_CHAIN_0, otherwise it'll be stored in DIGITAL_CERT_RW according to given index Tested OS: Linux Tested devices: N/A Tested flows: flint_oem -i cx7.bin --cert_chain_index set_attestation_cert_chain Known gaps (with RM ticket): N/A Issue: 3015150 --- flint/cmd_line_parser.cpp | 23 ++++ flint/flint_params.h | 1 + flint/subcommands.cpp | 2 +- mlxfwops/lib/fs4_ops.cpp | 248 +++++++++++++++++++++++++++++++++----- mlxfwops/lib/fs4_ops.h | 13 +- mlxfwops/lib/fw_ops.cpp | 2 +- mlxfwops/lib/fw_ops.h | 2 +- 7 files changed, 256 insertions(+), 35 deletions(-) diff --git a/flint/cmd_line_parser.cpp b/flint/cmd_line_parser.cpp index b765d79c..7c3932a4 100644 --- a/flint/cmd_line_parser.cpp +++ b/flint/cmd_line_parser.cpp @@ -235,6 +235,7 @@ FlagMetaData::FlagMetaData() #endif _flags.push_back(new Flag("", "output_file", 1)); _flags.push_back(new Flag("", "user_password", 1)); + _flags.push_back(new Flag("", "cert_chain_index", 1)); } FlagMetaData::~FlagMetaData() @@ -932,6 +933,14 @@ void Flint::initCmdParser() "", "Use this flag to reduce CPU utilization while burning, Windows only. Legal values are from 1 (lowest CPU) to 5 (highest CPU)"); #endif + AddOptions( + "cert_chain_index", + ' ', + "", + "Use this flag to specify the certificate location, acceptable values are between 0 and 7 (default - 0). " + "In case index=0 certificate chain will be stored at CERT_CHAIN_0 section, otherwise at DIGITAL_CERT_RW " + "section according to given index.\n" + "This flag is relevant only for set_attestation_cert_chain command."); for (map_sub_cmd_t_to_subcommand::iterator it = _subcommands.begin(); it != _subcommands.end(); it++) { if (it->first == SC_ResetCfg) { @@ -1255,6 +1264,20 @@ ParseStatus Flint::HandleOption(string name, string value) _flintParams.cableDeviceSize = cableDeviceSize; _flintParams.cable_device_size_specified = true; } + else if (name == "cert_chain_index") + { + int cert_chain_index = 0; + if (!strToInt(value, cert_chain_index)) + { + return PARSE_ERROR; + } + if (cert_chain_index < 0 || cert_chain_index > 7) + { + printf("certificate chain index should be between 0 and 7.\n"); + return PARSE_ERROR; + } + _flintParams.cert_chain_index = cert_chain_index; + } else { cout << "Unknown Flag: " << name; cout << _cmdParser.GetSynopsis(); diff --git a/flint/flint_params.h b/flint/flint_params.h index 7717e623..b28f237a 100644 --- a/flint/flint_params.h +++ b/flint/flint_params.h @@ -202,6 +202,7 @@ class FlintParams { string openssl_engine; string openssl_key_id; bool openssl_engine_usage_specified; + u_int32_t cert_chain_index; }; #endif diff --git a/flint/subcommands.cpp b/flint/subcommands.cpp index 5f0da479..46399f61 100644 --- a/flint/subcommands.cpp +++ b/flint/subcommands.cpp @@ -4785,7 +4785,7 @@ FlintStatus SetCertChainSubCommand::executeCommand() return FLINT_FAILED; } FwOperations *ops = _flintParams.device_specified ? _fwOps : _imgOps; - if (!ops->FwSetCertChain((char*)_flintParams.cmd_params[0].c_str(), &verifyCbFunc)) { + if (!ops->FwSetCertChain((char*)_flintParams.cmd_params[0].c_str(), _flintParams.cert_chain_index, &verifyCbFunc)) { reportErr(true, FLINT_CERT_CHAIN_ERROR, ops->err()); return FLINT_FAILED; } diff --git a/mlxfwops/lib/fs4_ops.cpp b/mlxfwops/lib/fs4_ops.cpp index 85561343..967cbf16 100644 --- a/mlxfwops/lib/fs4_ops.cpp +++ b/mlxfwops/lib/fs4_ops.cpp @@ -2788,6 +2788,74 @@ bool Fs4Operations::Fs4UpdateVsdSection(std::vector section_data, cha return true; } +bool Fs4Operations::Init() +{ + fw_info_t fwInfo; + if (!FwQuery(&fwInfo, false, false, false)) + { + return false; + } + return true; +} + +bool Fs4Operations::UpdateDigitalCertRWSection(char* certChainFile, + u_int32_t certChainIndex, + std::vector& newSectionData) +{ + if (!Init()) + { + return false; + } + struct fs4_toc_info* tocArr = _fs4ImgInfo.dtocArr.tocArr; + u_int32_t numOfTocs = _fs4ImgInfo.dtocArr.numOfTocs; + + // Get DIGITAL_CERT_RW entry + struct fs4_toc_info* digitalCertRWSectionToc = (fs4_toc_info*)NULL; + if (!Fs4GetItocInfo(tocArr, numOfTocs, FS4_DIGITAL_CERT_RW, digitalCertRWSectionToc)) + { + return false; + } + + // Get CERT_CHAIN_0 entry + struct fs4_toc_info* certChain0SectionToc = (fs4_toc_info*)NULL; + if (!Fs4GetItocInfo(tocArr, numOfTocs, FS4_CERT_CHAIN_0, certChain0SectionToc)) + { + return false; + } + u_int32_t certChain0SectionSize = certChain0SectionToc->toc_entry.size << 2; + + int certChainBuffSize = 0; + u_int8_t* certChainBuffData = (u_int8_t*)NULL; + if (!ReadBinFile(certChainFile, certChainBuffData, certChainBuffSize)) + { + return false; + } + DPRINTF(("Fs4Operations::UpdateDigitalCertRWSection new cert file size = 0x%x\n", certChainBuffSize)); + + //* Assert given certificate chain doesn't exceed its allocated size (compared to CERT_CHAIN_0 with same size) + if ((u_int32_t)certChainBuffSize > certChain0SectionSize) + { + return errmsg("Certificate chain data exceeds its allocated size of 0x%x bytes", certChain0SectionSize); + } + + std::vector certChainBuff(certChainBuffData, certChainBuffData + certChainBuffSize); + certChainBuff.resize(certChain0SectionSize); // Padding the cert chain if needed to match cert chain size + + newSectionData = digitalCertRWSectionToc->section_data; + u_int32_t newCertChainOffsetInSection = + certChain0SectionSize * (certChainIndex - 1); // index 0 belongs to CERT_CHAIN_0 + DPRINTF( + ("Fs4Operations::UpdateDigitalCertRWSection copy new cert to DIGITAL_CERT_RW at offset = 0x%x, size = 0x%x\n", + newCertChainOffsetInSection, (u_int32_t)certChainBuff.size())); + if ((newCertChainOffsetInSection + certChainBuff.size()) > (digitalCertRWSectionToc->toc_entry.size << 2)) + { + return errmsg("Certificate chain data exceeds its allocation"); + } + std::copy(certChainBuff.begin(), certChainBuff.end(), newSectionData.begin() + newCertChainOffsetInSection); + + return true; +} + bool Fs4Operations::UpdateCertChainSection(struct fs4_toc_info *curr_toc, char *certChainFile, std::vector &newSectionData) { @@ -3102,6 +3170,7 @@ bool Fs4Operations::isDTocSection(fs3_section_t sect_type, bool& isDtoc) case FS3_MFG_INFO: case FS3_DEV_INFO: case FS3_VPD_R0: + case FS4_DIGITAL_CERT_RW: case FS4_CERT_CHAIN_0: isDtoc = true; break; @@ -3167,14 +3236,30 @@ bool Fs4Operations::VerifyImageAfterModifications() { return true; } -bool Fs4Operations::FwSetCertChain(char *certFileStr, PrintCallBack callBackFunc) { +bool Fs4Operations::FwSetCertChain(char *certFileStr, u_int32_t certIndex, PrintCallBack callBackFunc) { if (!certFileStr) { return errmsg("Please specify a valid certificate chain file."); } FAIL_NO_OCR("set attestation certificate chain"); - if (!UpdateSection(certFileStr, FS4_CERT_CHAIN_0, false, CMD_UNKNOWN, callBackFunc)) { - return false; + if (certIndex == 0) + { + if (!UpdateSection(certFileStr, FS4_CERT_CHAIN_0, false, CMD_UNKNOWN, callBackFunc)) + { + return false; + } + } + else + { + std::vector newSectionData; + if (!UpdateDigitalCertRWSection(certFileStr, certIndex, newSectionData)) + { + return false; + } + if (!UpdateSection(FS4_DIGITAL_CERT_RW, newSectionData, "DIGITAL_CERT_RW", callBackFunc)) + { + return false; + } } // on image verify that image is OK after modification (we skip this on device for performance reasons) if (!_ioAccess->is_flash() && !VerifyImageAfterModifications()) { @@ -3371,56 +3456,157 @@ bool Fs4Operations::UpdateSection(void *new_info, fs3_section_t sect_type, bool, return errmsg("Section type %s is not supported\n", GetSectionNameByType(sect_type)); } - newSectionAddr = curr_toc->toc_entry.flash_addr << 2; + if (!WriteSection(curr_toc, newSection, type_msg, callBackFunc)) + { + return false; + } + + if (is_sect_failsafe) { + u_int32_t flash_addr = old_toc->toc_entry.flash_addr << 2; + // If encrypted image was given we'll write to it + if (_encrypted_image_io_access) { + DPRINTF(("Fs4Operations::UpdateSection updating encrypted image at addr 0x%x with 0x0\n", flash_addr)); + if (!_encrypted_image_io_access->write(flash_addr, + (u_int8_t *)&zeroes, sizeof(zeroes))) { + return errmsg("%s", _encrypted_image_io_access->err()); + } + } + else { + if (!writeImage((ProgressCallBack)NULL, + flash_addr, + (u_int8_t *)&zeroes, sizeof(zeroes), isDtoc, true)) { + return false; + } + } + } + + return true; +} - if (!_encrypted_image_io_access) { // In case of BB secure-boot sign flow we don't update ITOC since it's already encrypted - if (!Fs4UpdateItocInfo(curr_toc, curr_toc->toc_entry.size, newSection)) { +bool Fs4Operations::WriteSection(struct fs4_toc_info* sectionToc, + std::vector& newSectionData, + const char* msg, + PrintCallBack callBackFunc) +{ + DPRINTF( + ("Fs4Operations::WriteSection section type=%s, msg=%s", GetSectionNameByType(sectionToc->toc_entry.type), msg)); + bool isDtoc; + fs3_section_t sectionType = static_cast(sectionToc->toc_entry.type); + if (!isDTocSection(sectionType, isDtoc)) + { + return false; + } + u_int32_t newSectionAddr = sectionToc->toc_entry.flash_addr << 2; + + if (!_encrypted_image_io_access) + { // In case of BB secure-boot sign flow we don't update ITOC since it's already encrypted + if (!Fs4UpdateItocInfo(sectionToc, sectionToc->toc_entry.size, newSectionData)) + { return false; } } - if (!Fs4ReburnSection(newSectionAddr, curr_toc->toc_entry.size * 4, newSection, type_msg, callBackFunc)) { + if (!Fs4ReburnSection(newSectionAddr, sectionToc->toc_entry.size * 4, newSectionData, msg, callBackFunc)) + { return false; } - if (!_encrypted_image_io_access) { // In case of BB secure-boot sign flow we don't update ITOC since it's already encrypted - if (sect_type != FS3_DEV_INFO) { - if (!Fs4ReburnTocSection(isDtoc, callBackFunc)) { + if (!_encrypted_image_io_access) + { // In case of BB secure-boot sign flow we don't update ITOC since it's already encrypted + if (sectionType != FS3_DEV_INFO) + { + if (!Fs4ReburnTocSection(isDtoc, callBackFunc)) + { return false; } } } - if (!isDtoc) { - if (!UpdateSectionHashInHashesTable(newSectionAddr, curr_toc->toc_entry.size * 4, sect_type)) { + if (!isDtoc) + { + if (!UpdateSectionHashInHashesTable(newSectionAddr, sectionToc->toc_entry.size * 4, sectionType)) + { return false; } } + return true; +} - +bool Fs4Operations::UpdateSection(fs3_section_t sectionType, + std::vector& newSectionData, + const char* msg, + PrintCallBack callBackFunc) +{ + if (sectionType == FS3_DEV_INFO) + { + return errmsg("Fs4Operations::UpdateSection doesn't support updating DEV_INFO section\n"); + } - // TODO - in case hashes_table (HTOC) exists recalculate modified section SHA and store it in hashes_table. - // TODO - Currently it's not implemented since there is no use-case where we need to update hashes_table, - // TODO - so we prefer to ignore it for now instead of inserting a potential bug. + // Query + bool isDtoc; + if (!isDTocSection(sectionType, isDtoc)) + { + return false; + } + bool image_encrypted = false; + if (!isEncrypted(image_encrypted)) + { + return errmsg(getErrorCode(), "%s", err()); + } - if (is_sect_failsafe) { - u_int32_t flash_addr = old_toc->toc_entry.flash_addr << 2; - // If encrypted image was given we'll write to it - if (_encrypted_image_io_access) { - DPRINTF(("Fs4Operations::UpdateSection updating encrypted image at addr 0x%x with 0x0\n", flash_addr)); - if (!_encrypted_image_io_access->write(flash_addr, - (u_int8_t *)&zeroes, sizeof(zeroes))) { - return errmsg("%s", _encrypted_image_io_access->err()); - } + if (image_encrypted) + { + if (!isDtoc) + { + return errmsg("Can't update ITOC section in case of encrypted image"); } - else { - if (!writeImage((ProgressCallBack)NULL, - flash_addr, - (u_int8_t *)&zeroes, sizeof(zeroes), isDtoc, true)) { - return false; - } + fw_info_t fwInfo; + if (!encryptedFwQuery(&fwInfo)) + { + return errmsg("%s", err()); } } + else + { + // init sector to read + _readSectList.push_back(sectionType); + if (!FsIntQueryAux()) + { + _readSectList.pop_back(); + return false; + } + _readSectList.pop_back(); + } + + // Get relevant TOC + struct fs4_toc_info* tocArr; + u_int32_t numOfTocs; + if (isDtoc) + { + tocArr = _fs4ImgInfo.dtocArr.tocArr; + numOfTocs = _fs4ImgInfo.dtocArr.numOfTocs; + } + else + { + tocArr = _fs4ImgInfo.itocArr.tocArr; + numOfTocs = _fs4ImgInfo.itocArr.numOfTocs; + } + // Find TOC entry + int tocIndex = 0; + struct fs4_toc_info* sectionToc = (fs4_toc_info*)NULL; + if (!Fs4GetItocInfo(tocArr, numOfTocs, sectionType, sectionToc, tocIndex)) + { + return false; + } + if (sectionType == FS3_VPD_R0 && ((u_int32_t)tocIndex) != numOfTocs - 1) + { + return errmsg("VPD Section is not the last device section"); + } + + if (!WriteSection(sectionToc, newSectionData, msg, callBackFunc)) + { + return false; + } return true; } diff --git a/mlxfwops/lib/fs4_ops.h b/mlxfwops/lib/fs4_ops.h index b8baf21f..31c50ef5 100644 --- a/mlxfwops/lib/fs4_ops.h +++ b/mlxfwops/lib/fs4_ops.h @@ -177,6 +177,7 @@ class Fs4Operations : public Fs3Operations { bool encryptedFwQuery(fw_info_t *fwInfo, bool readRom = true, bool quickQuery = true, bool ignoreDToc = false, bool verbose = false); virtual bool FwQuery(fw_info_t *fwInfo, bool readRom = true, bool isStripedImage = false, bool quickQuery = true, bool ignoreDToc = false, bool verbose = false); bool FsVerifyAux(VerifyCallBack verifyCallBackFunc, bool show_itoc, struct QueryOptions queryOptions, bool ignoreDToc = false, bool verbose = false); + bool Init(); bool CheckTocSignature(struct image_layout_itoc_header *itoc_header, u_int32_t first_signature); bool CheckDevInfoSignature(u_int32_t *buff); bool FsBurnAux(FwOperations *imageOps, ExtBurnParams& burnParams); @@ -189,6 +190,14 @@ class Fs4Operations : public Fs3Operations { bool Fs4GetItocInfo(struct fs4_toc_info *tocArr, int num_of_itocs, fs3_section_t sect_type, vector& curr_toc); bool UpdateSection(void *new_info, fs3_section_t sect_type = FS3_DEV_INFO, bool is_sect_failsafe = true, CommandType cmd_type = CMD_UNKNOWN, PrintCallBack callBackFunc = (PrintCallBack)NULL ); + bool UpdateSection(fs3_section_t sectionType, + std::vector& newSectionData, + const char* msg, + PrintCallBack callBackFunc = (PrintCallBack)NULL); + bool WriteSection(struct fs4_toc_info* sectionToc, + std::vector& newSectionData, + const char* msg, + PrintCallBack callBackFunc); bool Fs4UpdateMfgUidsSection(struct fs4_toc_info *curr_toc, std::vector section_data, fs3_uid_t base_uid, std::vector &newSectionData); @@ -201,7 +210,9 @@ class Fs4Operations : public Fs3Operations { std::vector &newSectionData); bool UpdateCertChainSection(struct fs4_toc_info *curr_toc, char *certChainFile, std::vector &newSectionData); - bool FwSetCertChain(char *certFileStr, PrintCallBack callBackFunc); + bool + UpdateDigitalCertRWSection(char* certChainFile, u_int32_t certChainIndex, std::vector& newSectionData); + bool FwSetCertChain(char *certFileStr, u_int32_t certIndex, PrintCallBack callBackFunc); bool Fs4ReburnSection(u_int32_t newSectionAddr, u_int32_t newSectionSize, std::vector newSectionData, const char *msg, PrintCallBack callBackFunc); diff --git a/mlxfwops/lib/fw_ops.cpp b/mlxfwops/lib/fw_ops.cpp index bf71cfa6..9107fcde 100644 --- a/mlxfwops/lib/fw_ops.cpp +++ b/mlxfwops/lib/fw_ops.cpp @@ -2069,7 +2069,7 @@ const char* FwOperations::expRomType2Str(u_int16_t type) return (const char*)NULL; } -bool FwOperations::FwSetCertChain(char *, PrintCallBack) +bool FwOperations::FwSetCertChain(char *, u_int32_t, PrintCallBack) { return errmsg("Operation not supported."); } diff --git a/mlxfwops/lib/fw_ops.h b/mlxfwops/lib/fw_ops.h index 45e65061..4ad64325 100644 --- a/mlxfwops/lib/fw_ops.h +++ b/mlxfwops/lib/fw_ops.h @@ -192,7 +192,7 @@ class MLXFWOP_API FwOperations : public FlintErrMsg { // use progressFunc when dealing with FS2 image and printFunc when dealing with FS3 image. virtual bool FwSetVSD(char *vsdStr, ProgressCallBack progressFunc = (ProgressCallBack)NULL, PrintCallBack printFunc = (PrintCallBack)NULL) = 0; virtual bool FwSetVPD(char *vpdFileStr, PrintCallBack callBackFunc = (PrintCallBack)NULL) = 0; - virtual bool FwSetCertChain(char *certFileStr, PrintCallBack callBackFunc = (PrintCallBack)NULL); + virtual bool FwSetCertChain(char *certFileStr, u_int32_t certIndex, PrintCallBack callBackFunc = (PrintCallBack)NULL); virtual bool FwSetAccessKey(hw_key_t userKey, ProgressCallBack progressFunc = (ProgressCallBack)NULL) = 0; virtual bool FwGetSection(u_int32_t sectType, std::vector& sectInfo, bool stripedImage = false) = 0; virtual bool FwResetNvData() = 0; From 0a24fd306d092a63f7cdeb666e3237f355c2ce59 Mon Sep 17 00:00:00 2001 From: Matan Eliyahu Date: Sun, 3 Jul 2022 21:18:06 +0300 Subject: [PATCH 18/46] [flint][mflash] Block mflash open for GB device that's not manager Description: Since we can't access the flash GW directly of GB that's not a manager we need to block that option so we won't make an illegal cr-space access Tested OS: Linux Tested devices: Buffalo Tested flows: flint_oem -d /dev/mst/gbox/switch_mt53104_pciconf0_gbox53108_ln8_0 -i /.autodirect/fwgwork/hilaj/pelican/pelican/hila.bin b Known gaps (with RM ticket): N/A Issue: 3110958 --- mflash/mflash.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/mflash/mflash.c b/mflash/mflash.c index 9757a2f9..d1d03ea1 100644 --- a/mflash/mflash.c +++ b/mflash/mflash.c @@ -1688,8 +1688,9 @@ int is4_flash_init(mflash *mfl, flash_params_t *flash_params) return gen4_flash_init_com(mfl, flash_params, 0); } -static void flash_update_gearbox_gw(mflash *mfl) +static void flash_update_amos_gearbox_gw(mflash *mfl) { + FLASH_ACCESS_DPRINTF(("flash_update_amos_gearbox_gw()\n")); mfl->gw_data = HCR_FLASH_GEARBOX_DATA; mfl->gw_cmd = HCR_FLASH_GEARBOX_CMD; mfl->gw_addr = HCR_FLASH_GEARBOX_ADDR; @@ -2004,7 +2005,12 @@ int fifth_gen_flash_init(mflash *mfl, flash_params_t *flash_params) int rc = 0; u_int8_t needs_cache_replacement = 0; if (mfl->mf->gb_info.is_gb_mngr) { - flash_update_gearbox_gw(mfl);//need to update GW offsets before calling to the check_cache_replacement_guard + // need to update GW offsets before calling to the check_cache_replacement_guard + flash_update_amos_gearbox_gw(mfl); + } + else if (mfl->mf->gb_info.is_gearbox) + { + return MFE_OCR_NOT_SUPPORTED; // Accessing flash GW of GB that's not manager is not possible } rc = check_cache_replacement_guard(mfl, &needs_cache_replacement); CHECK_RC(rc); From 507a63ffd7d8cea709fbac788b6e7f3c6a22f9b2 Mon Sep 17 00:00:00 2001 From: Matan Eliyahu Date: Sun, 3 Jul 2022 21:25:26 +0300 Subject: [PATCH 19/46] [mlxfwops] Coverity HTOC initialization fix Description: N/A Tested OS: Linux Tested devices: CX7 Tested flows: sign/rsa_sign Known gaps (with RM ticket): N/A Issue: 3117342 --- mlxfwops/lib/fs4_ops.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/mlxfwops/lib/fs4_ops.cpp b/mlxfwops/lib/fs4_ops.cpp index 967cbf16..33764f3f 100644 --- a/mlxfwops/lib/fs4_ops.cpp +++ b/mlxfwops/lib/fs4_ops.cpp @@ -4709,6 +4709,7 @@ Fs4Operations::TocArray::TocArray() } Fs4Operations::HTOC::HTOC(vector img, u_int32_t htoc_start_addr) { + memset(entries, 0, MAX_HTOC_ENTRIES_NUM * sizeof(image_layout_htoc_entry)); this->htoc_start_addr = htoc_start_addr; //* Parse header vector header_data(img.begin() + htoc_start_addr, img.begin() + htoc_start_addr + IMAGE_LAYOUT_HTOC_HEADER_SIZE); From 7a18e3ae74fad788e5a25d10d5e5f64d072c92c7 Mon Sep 17 00:00:00 2001 From: Matan Eliyahu Date: Sun, 3 Jul 2022 21:32:49 +0300 Subject: [PATCH 20/46] [mlxfwreset] mlxfwreset fails to find path for mst Description: mst tool has been moved from "/etc/init.d/" to "/etc/systemd/system/" by commit ae33702507860d9211606fda26b0cc0a99f318ce. Updated mlxfwreset to look for mst in the new path. Tested OS: Linux Tested devices: HCA Tested flows: mlxfwreset -d r Known gaps (with RM ticket): N/A Issue: 3118837 --- small_utils/mstfwreset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/small_utils/mstfwreset.py b/small_utils/mstfwreset.py index ee93b513..862724d5 100644 --- a/small_utils/mstfwreset.py +++ b/small_utils/mstfwreset.py @@ -752,7 +752,7 @@ def mstRestart(busId): raise RuntimeError("The device is not appearing in lspci output!") ignore_signals() - cmd = "/etc/init.d/mst restart %s" % MstFlags + cmd = "/etc/systemd/system/mst.service restart %s" % MstFlags logger.debug('Execute {0}'.format(cmd)) (rc, stdout, stderr) = cmdExec(cmd) if rc != 0: From cfb934ebd47e44e6166abd1e7483d6b863aed8a7 Mon Sep 17 00:00:00 2001 From: Matan Eliyahu Date: Sun, 3 Jul 2022 21:36:33 +0300 Subject: [PATCH 21/46] [flint] Converting DMA not supported due to BME unset warning message to debug print Description: Since this warning message created noise we decided to convert it to debug print as it doesn't fail the burn only its performance Tested OS: N/A Tested devices: N/A Tested flows: N/A Known gaps (with RM ticket): N/A Issue: 2701705 --- flint/subcommands_linkx.cpp | 2 +- mlxfwops/lib/fsctrl_ops.cpp | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/flint/subcommands_linkx.cpp b/flint/subcommands_linkx.cpp index 5c9ef8aa..6c0f3c42 100644 --- a/flint/subcommands_linkx.cpp +++ b/flint/subcommands_linkx.cpp @@ -317,7 +317,7 @@ FlintStatus BurnSubCommand::BurnLinkX(string deviceName, int deviceIndex, int de // Checking if BME is disabled to print indication to user bool isBmeSet = DMAComponentAccess::isBMESet(fwCompsAccess.getMfileObj()); if (!isBmeSet) { - printf("-W- DMA burning is not supported due to BME is unset (Bus Master Enable).\n"); + DPRINTF(("-W- DMA burning is not supported due to BME is unset (Bus Master Enable).\n")); } } } diff --git a/mlxfwops/lib/fsctrl_ops.cpp b/mlxfwops/lib/fsctrl_ops.cpp index 7897aee3..91137955 100644 --- a/mlxfwops/lib/fsctrl_ops.cpp +++ b/mlxfwops/lib/fsctrl_ops.cpp @@ -319,6 +319,7 @@ void FsCtrlOperations::ExtractSwitchFWVersion(const fwInfoT& fwQuery) (_fwImgInfo.ext_info.fw_ver[1] == _fwImgInfo.ext_info.running_fw_ver[1]) && (_fwImgInfo.ext_info.fw_ver[2] == _fwImgInfo.ext_info.running_fw_ver[2])) { strncpy(_fwImgInfo.ext_info.branch_ver, fwQuery.imageVsd, BRANCH_LEN); + _fwImgInfo.ext_info.branch_ver[BRANCH_LEN - 1] = '\0'; } } @@ -640,7 +641,7 @@ bool FsCtrlOperations::_Burn(std::vector imageOps4MData, ExtBurnParam // Checking if BME is disabled to print indication to user bool isBmeSet = DMAComponentAccess::isBMESet(_fwCompsAccess->getMfileObj()); if (!isBmeSet) { - printf("-W- DMA burning is not supported due to BME is unset (Bus Master Enable).\n"); + DPRINTF(("-W- DMA burning is not supported due to BME is unset (Bus primary Enable).\n")); } } if (!_fwCompsAccess->burnComponents(compsToBurn, &burnParams.ProgressFuncAdv)) { @@ -997,4 +998,4 @@ bool FsCtrlOperations::IsSecurityVersionViolated(u_int32_t image_security_versio // Check violation of security-version return (imageSecurityVersion < deviceEfuseSecurityVersion); -} \ No newline at end of file +} From 33600b0e826e336adb6de251533038de4b68fd0c Mon Sep 17 00:00:00 2001 From: Tomer Tubi Date: Tue, 5 Jul 2022 10:43:22 +0300 Subject: [PATCH 22/46] update mstflint version for 4.21.0 release --- configure.ac | 4 ++-- debian/changelog | 6 ++++++ kernel/mstflint_kernel.spec | 2 +- mstflint.spec.in | 5 ++++- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 04ea1b47..477da4c4 100644 --- a/configure.ac +++ b/configure.ac @@ -31,12 +31,12 @@ dnl Process this file with autoconf to produce a configure script. -AC_INIT(mstflint, 4.20.1, eranj@mellanox.co.il) +AC_INIT(mstflint, 4.21.0, eranj@mellanox.co.il) AC_DEFINE_UNQUOTED([PROJECT], ["mstflint"], [Define the project name.]) AC_SUBST([PROJECT]) -AC_DEFINE_UNQUOTED([VERSION], ["4.20.1"], [Define the project version.]) +AC_DEFINE_UNQUOTED([VERSION], ["4.21.0"], [Define the project version.]) AC_SUBST([VERSION]) AC_CONFIG_MACRO_DIR([m4]) diff --git a/debian/changelog b/debian/changelog index 4e6e411e..bcb0ec4a 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +mstflint (4.21.0-1) unstable; urgency=low + + * Updated from MFT-4.21.0 + + -- Tomer Tubi Sun, 31 Jul 2022 00:00:00 +0000 + mstflint (4.20.1-1) unstable; urgency=low * Updated from MFT-4.20.1 diff --git a/kernel/mstflint_kernel.spec b/kernel/mstflint_kernel.spec index 64b1fb73..c261c39d 100644 --- a/kernel/mstflint_kernel.spec +++ b/kernel/mstflint_kernel.spec @@ -22,7 +22,7 @@ %global _name kernel-mstflint %endif -%{!?version: %global version 4.20.1} +%{!?version: %global version 4.21.0} %{!?_release: %global _release 1} %global _kmp_rel %{_release}%{?_kmp_build_num}%{?_dist} diff --git a/mstflint.spec.in b/mstflint.spec.in index e638be29..fc619a55 100644 --- a/mstflint.spec.in +++ b/mstflint.spec.in @@ -1,6 +1,6 @@ %{!?ibmadlib: %define ibmadlib libibmad-devel} %{!?name: %define name mstflint} -%{!?version: %define version 4.20.1} +%{!?version: %define version 4.21.0} %{!?release: %define release 1} %{!?buildtype: %define buildtype "native"} %{!?noinband: %define noinband 0} @@ -215,6 +215,9 @@ rm -rf $RPM_BUILD_ROOT %{_mandir}/man1/* %changelog +* Sun Jul 31 2022 Tomer Tubi + MFT 4.21.0 Updates + * Thu May 31 2022 Tomer Tubi MFT 4.20.1 Updates From d4a0be149e372eb4cf7614cf1e944df2009cac0b Mon Sep 17 00:00:00 2001 From: Mustafa Dalloul Date: Wed, 6 Jul 2022 11:33:21 +0300 Subject: [PATCH 23/46] [mstlink] Updating amber collection to version 2.05 Description: Updating amber collection to version 2.05 Issue: 3062640 Signed-off-by: Mustafa Dalloul --- mlxlink/modules/mlxlink_amBER_collector.cpp | 14 ++++++++++++-- mlxlink/modules/mlxlink_enums.h | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/mlxlink/modules/mlxlink_amBER_collector.cpp b/mlxlink/modules/mlxlink_amBER_collector.cpp index c002f039..d4f1c03a 100644 --- a/mlxlink/modules/mlxlink_amBER_collector.cpp +++ b/mlxlink/modules/mlxlink_amBER_collector.cpp @@ -76,11 +76,11 @@ MlxlinkAmBerCollector::MlxlinkAmBerCollector(Json::Value& jsonRoot) : _jsonRoot( _baseSheetsList[AMBER_SHEET_GENERAL] = FIELDS_COUNT{4, 4, 4}; _baseSheetsList[AMBER_SHEET_INDEXES] = FIELDS_COUNT{2, 2, 4}; - _baseSheetsList[AMBER_SHEET_LINK_STATUS] = FIELDS_COUNT{48, 139, 6}; + _baseSheetsList[AMBER_SHEET_LINK_STATUS] = FIELDS_COUNT{48, 141, 6}; _baseSheetsList[AMBER_SHEET_MODULE_STATUS] = FIELDS_COUNT{111, 111, 0}; _baseSheetsList[AMBER_SHEET_SYSTEM] = FIELDS_COUNT{16, 21, 11}; _baseSheetsList[AMBER_SHEET_SERDES_16NM] = FIELDS_COUNT{376, 736, 0}; - _baseSheetsList[AMBER_SHEET_SERDES_7NM] = FIELDS_COUNT{203, 323, 499}; + _baseSheetsList[AMBER_SHEET_SERDES_7NM] = FIELDS_COUNT{206, 326, 499}; _baseSheetsList[AMBER_SHEET_PORT_COUNTERS] = FIELDS_COUNT{35, 0, 35}; _baseSheetsList[AMBER_SHEET_TROUBLESHOOTING] = FIELDS_COUNT{2, 2, 0}; _baseSheetsList[AMBER_SHEET_PHY_OPERATION_INFO] = FIELDS_COUNT{18, 18, 15}; @@ -654,6 +654,16 @@ void MlxlinkAmBerCollector::getPpcntBer(u_int32_t portType, vector& to_string(getFieldValue("effective_ber_coef")) + "E-" + to_string(getFieldValue("effective_ber_magnitude")); fields.push_back(AmberField(preTitle + "Effective_BER", berStr)); + if (_isPortETH) + { + string effErrorsStr = (portType == NETWORK_PORT_TYPE_NEAR || portType == NETWORK_PORT_TYPE_FAR) ? + to_string(add32BitTo64(getFieldValue("phy_effective_errors_high"), + getFieldValue("phy_effective_errors__low"))) : + "N/A"; + + fields.push_back(AmberField(preTitle + "Effective_Errors", effErrorsStr)); + } + if (portType != NETWORK_PORT_TYPE || (portType == NETWORK_PORT_TYPE && _isPortIB)) { berStr = diff --git a/mlxlink/modules/mlxlink_enums.h b/mlxlink/modules/mlxlink_enums.h index b80ab568..aed41482 100644 --- a/mlxlink/modules/mlxlink_enums.h +++ b/mlxlink/modules/mlxlink_enums.h @@ -34,7 +34,7 @@ #define MLXLINK_ENUMS_H // Common definitions -#define AMBER_VERSION "2.02" +#define AMBER_VERSION "2.05" #define ACCESS_REG_PGUID "PGUID" #define ACCESS_REG_SPZR "SPZR" From d1c6687fc30b2121e8c803de2ac8352a1627439e Mon Sep 17 00:00:00 2001 From: Jack German Date: Wed, 6 Jul 2022 18:28:12 +0300 Subject: [PATCH 24/46] Enforce code style with clang-format toolt Format is included in .clang-format --- .clang-format | 77 + adb_parser/adb_common_functions.h | 1 - adb_parser/adb_config.cpp | 28 +- adb_parser/adb_config.h | 3 +- adb_parser/adb_db.cpp | 273 +- adb_parser/adb_db.h | 104 +- adb_parser/adb_exceptionHolder.cpp | 32 +- adb_parser/adb_exceptionHolder.h | 17 +- adb_parser/adb_expr.cpp | 43 +- adb_parser/adb_expr.h | 6 +- adb_parser/adb_field.cpp | 25 +- adb_parser/adb_field.h | 6 +- adb_parser/adb_instance.cpp | 439 +- adb_parser/adb_instance.h | 57 +- adb_parser/adb_logfile.cpp | 42 +- adb_parser/adb_logfile.h | 6 +- adb_parser/adb_node.cpp | 11 +- adb_parser/adb_node.h | 8 +- adb_parser/adb_parser.cpp | 1376 +- adb_parser/adb_parser.h | 72 +- adb_parser/adb_xmlCreator.cpp | 86 +- adb_parser/adb_xmlCreator.h | 28 +- adb_parser/buf_ops.cpp | 137 +- adb_parser/buf_ops.h | 6 +- adb_parser/expr.cpp | 1114 +- adb_parser/expr.h | 68 +- cmdif/cmdif.py | 87 +- cmdif/icmd_cif_common.c | 163 +- cmdif/icmd_cif_common.h | 95 +- cmdif/icmd_cif_macros.h | 83 +- cmdif/icmd_cif_open.c | 18 +- cmdif/icmd_cif_open.h | 39 +- cmdif/tools_cif.c | 69 +- cmdif/tools_cif.h | 163 +- cmdparser/cmdparser.cpp | 434 +- cmdparser/cmdparser.h | 84 +- cmdparser/my_getopt.c | 749 +- cmdparser/my_getopt.h | 161 +- common/autocomplete/mft_help_to_completion.py | 282 +- common/bit_slice.h | 36 +- common/compatibility.h | 562 +- common/mft_logger.py | 3 +- common/tools_utils.h | 35 +- common/tools_version.h | 34 +- dev_mgt/dev_mgt.py | 20 +- dev_mgt/tools_dev_types.c | 1009 +- dev_mgt/tools_dev_types.h | 340 +- ext_libs/iniParser/dictionary.c | 255 +- ext_libs/iniParser/dictionary.h | 276 +- ext_libs/iniParser/iniparser.c | 573 +- ext_libs/iniParser/iniparser.h | 635 +- ext_libs/iniParser/test/iniexample.c | 145 +- ext_libs/iniParser/test/parse.c | 19 +- ext_libs/iniParser/test/sandbox.c | 11 +- ext_libs/iniParser/test/twisted-genhuge.py | 7 +- ext_libs/json/json/autolink.h | 26 +- ext_libs/json/json/config.h | 34 +- ext_libs/json/json/features.h | 75 +- ext_libs/json/json/forwards.h | 64 +- ext_libs/json/json/json.h | 13 +- ext_libs/json/json/reader.h | 360 +- ext_libs/json/json/value.h | 1828 +- ext_libs/json/json/writer.h | 336 +- ext_libs/json/json_batchallocator.h | 190 +- ext_libs/json/json_reader.cpp | 1500 +- ext_libs/json/json_value.cpp | 2378 +- ext_libs/json/json_writer.cpp | 1316 +- ext_libs/minixz/xz.h | 448 +- ext_libs/minixz/xz_config.h | 49 +- ext_libs/minixz/xz_crc32.c | 40 +- ext_libs/minixz/xz_dec_bcj.c | 910 +- ext_libs/minixz/xz_dec_lzma2.c | 1831 +- ext_libs/minixz/xz_dec_stream.c | 1222 +- ext_libs/minixz/xz_lzma2.h | 58 +- ext_libs/minixz/xz_private.h | 128 +- ext_libs/minixz/xz_stream.h | 18 +- ext_libs/muparser/muParser.cpp | 638 +- ext_libs/muparser/muParser.h | 119 +- ext_libs/muparser/muParserBase.cpp | 2897 ++- ext_libs/muparser/muParserBase.h | 259 +- ext_libs/muparser/muParserBytecode.cpp | 932 +- ext_libs/muparser/muParserBytecode.h | 110 +- ext_libs/muparser/muParserCallback.cpp | 881 +- ext_libs/muparser/muParserCallback.h | 100 +- ext_libs/muparser/muParserDLL.cpp | 476 +- ext_libs/muparser/muParserDLL.h | 442 +- ext_libs/muparser/muParserDef.h | 554 +- ext_libs/muparser/muParserError.cpp | 480 +- ext_libs/muparser/muParserError.h | 180 +- ext_libs/muparser/muParserFixes.h | 32 +- ext_libs/muparser/muParserInt.cpp | 388 +- ext_libs/muparser/muParserInt.h | 151 +- ext_libs/muparser/muParserStack.h | 158 +- ext_libs/muparser/muParserTemplateMagic.h | 176 +- ext_libs/muparser/muParserTest.cpp | 2602 +- ext_libs/muparser/muParserTest.h | 349 +- ext_libs/muparser/muParserToken.h | 532 +- ext_libs/muparser/muParserTokenReader.cpp | 1312 +- ext_libs/muparser/muParserTokenReader.h | 236 +- ext_libs/sqlite/sqlite3.h | 20611 ++++++++-------- flint/cmd_line_parser.cpp | 1081 +- flint/err_msgs.h | 272 +- flint/flint.cpp | 121 +- flint/flint.h | 12 +- flint/flint_params.cpp | 9 +- flint/flint_params.h | 12 +- flint/subcommands.cpp | 4801 ++-- flint/subcommands.h | 199 +- flint/subcommands_linkx.cpp | 297 +- fw_comps_mgr/fw_comps_mgr.cpp | 2291 +- fw_comps_mgr/fw_comps_mgr.h | 395 +- fw_comps_mgr/fw_comps_mgr_abstract_access.cpp | 19 +- fw_comps_mgr/fw_comps_mgr_abstract_access.h | 29 +- fw_comps_mgr/fw_comps_mgr_direct_access.cpp | 92 +- fw_comps_mgr/fw_comps_mgr_direct_access.h | 23 +- fw_comps_mgr/fw_comps_mgr_dma_access.cpp | 232 +- fw_comps_mgr/fw_comps_mgr_dma_access.h | 33 +- include/mtcr_ul/mtcr.h | 216 +- include/mtcr_ul/mtcr_com_defs.h | 203 +- include/mtcr_ul/mtcr_mf.h | 68 +- kernel/mst.h | 204 +- kernel/mst_kernel.h | 115 +- kernel/mst_main.c | 2634 +- kernel/mst_vpd.c | 233 +- libmfa/mfa.c | 367 +- libmfa/mfa.h | 44 +- libmfa/mfa_section.c | 214 +- libmfa/mfa_section.h | 67 +- libmfa/mfaerr.h | 5 +- libmfa/test.c | 20 +- libmfa/xz_io_ops.c | 161 +- libmfa/xz_io_ops.h | 13 +- libmfa/xz_io_ops_llzma.c | 219 +- mad_ifc/mad_ifc.c | 161 +- mad_ifc/mad_ifc.h | 45 +- mflash/flash_int_defs.h | 43 +- mflash/mflash.c | 2355 +- mflash/mflash.h | 168 +- mflash/mflash_access_layer.c | 224 +- mflash/mflash_access_layer.h | 91 +- mflash/mflash_common_structs.h | 104 +- mflash/mflash_dev_capability.c | 233 +- mflash/mflash_dev_capability.h | 27 +- mflash/mflash_gw.c | 246 +- mflash/mflash_gw.h | 27 +- mflash/mflash_new_gw.c | 234 +- mflash/mflash_new_gw.h | 27 +- mflash/mflash_pack_layer.c | 277 +- mflash/mflash_pack_layer.h | 333 +- mflash/mflash_types.h | 10 +- mft_utils/calc_hw_crc.c | 62 +- mft_utils/calc_hw_crc.h | 5 +- mft_utils/errmsg.cpp | 71 +- mft_utils/errmsg.h | 59 +- mft_utils/hsmclient/inc/cryptoki_v2.h | 2006 +- mft_utils/hsmclient/inc/hex64.h | 7 +- mft_utils/hsmclient/inc/hsmlunaclient.h | 59 +- mft_utils/hsmclient/inc/rsa/pkcs11.h | 73 +- mft_utils/hsmclient/inc/rsa/pkcs11f.h | 660 +- mft_utils/hsmclient/inc/rsa/pkcs11t.h | 2058 +- .../hsmclient/inc/sfnt_ext_typedef_members.h | 1156 +- mft_utils/hsmclient/inc/sfnt_extensions.h | 1576 +- mft_utils/hsmclient/src/burnprivatekey.cpp | 208 +- mft_utils/hsmclient/src/hex64.cpp | 195 +- mft_utils/hsmclient/src/hsmaesencryption.cpp | 89 +- .../hsmclient/src/hsmcreatersasignature.cpp | 144 +- mft_utils/hsmclient/src/hsmlunaclient.cpp | 547 +- mft_utils/hsmclient/src/hsmlunaclientinit.cpp | 71 +- mft_utils/hsmclient/src/hsmlunatest.cpp | 11 +- mft_utils/mft_sig_handler.c | 94 +- mft_utils/mft_sig_handler.h | 91 +- mft_utils/mft_utils.cpp | 38 +- mft_utils/mft_utils.h | 8 +- mft_utils/mlarge_buffer.cpp | 74 +- mft_utils/mlarge_buffer.h | 28 +- mlxarchive/mfa2_buff.cpp | 95 +- mlxarchive/mfa2_buff.h | 22 +- mlxarchive/mlxarchive.cpp | 192 +- mlxarchive/mlxarchive.h | 44 +- mlxarchive/mlxarchive_mfa2.cpp | 169 +- mlxarchive/mlxarchive_mfa2.h | 101 +- mlxarchive/mlxarchive_mfa2_builder.cpp | 114 +- mlxarchive/mlxarchive_mfa2_builder.h | 43 +- mlxarchive/mlxarchive_mfa2_common_header.cpp | 27 +- mlxarchive/mlxarchive_mfa2_common_header.h | 22 +- mlxarchive/mlxarchive_mfa2_component.h | 32 +- mlxarchive/mlxarchive_mfa2_descriptor.cpp | 204 +- mlxarchive/mlxarchive_mfa2_descriptor.h | 125 +- mlxarchive/mlxarchive_mfa2_element.cpp | 7 +- mlxarchive/mlxarchive_mfa2_element.h | 14 +- mlxarchive/mlxarchive_mfa2_extension.cpp | 103 +- mlxarchive/mlxarchive_mfa2_extension.h | 120 +- mlxarchive/mlxarchive_mfa2_package_gen.cpp | 10 +- mlxarchive/mlxarchive_mfa2_package_gen.h | 7 +- mlxarchive/mlxarchive_mfa2_utils.cpp | 51 +- mlxarchive/mlxarchive_mfa2_utils.h | 31 +- mlxconfig/mlxcfg_db_manager.h | 2 +- mlxconfig/mlxcfg_generic_commander.cpp | 5 +- mlxconfig/mlxcfg_parser.cpp | 30 +- mlxconfig/mlxcfg_ui.cpp | 3 +- mlxconfig/mlxcfg_utils.cpp | 1 - mlxfwops/lib/aux_tlv_ops.cpp | 255 +- mlxfwops/lib/aux_tlv_ops.h | 89 +- mlxfwops/lib/bluefiled_signature_manager.cpp | 30 +- mlxfwops/lib/connectx6_signature_manager.cpp | 16 +- mlxfwops/lib/flint_base.cpp | 166 +- mlxfwops/lib/flint_base.h | 631 +- mlxfwops/lib/flint_io.cpp | 682 +- mlxfwops/lib/flint_io.h | 212 +- mlxfwops/lib/fs2_ops.cpp | 1559 +- mlxfwops/lib/fs2_ops.h | 213 +- mlxfwops/lib/fs3_ops.cpp | 2893 ++- mlxfwops/lib/fs3_ops.h | 421 +- mlxfwops/lib/fs4_ops.cpp | 3320 +-- mlxfwops/lib/fs4_ops.h | 306 +- mlxfwops/lib/fs_checks.cpp | 102 +- mlxfwops/lib/fs_checks.h | 42 +- mlxfwops/lib/fsctrl_ops.cpp | 779 +- mlxfwops/lib/fsctrl_ops.h | 114 +- mlxfwops/lib/fuse_gw.cpp | 149 +- mlxfwops/lib/fuse_gw.h | 35 +- mlxfwops/lib/fw_ops.cpp | 1882 +- mlxfwops/lib/fw_ops.h | 571 +- mlxfwops/lib/fw_version.cpp | 151 +- mlxfwops/lib/fw_version.h | 34 +- mlxfwops/lib/mlxfwops.cpp | 246 +- mlxfwops/lib/mlxfwops.h | 87 +- mlxfwops/lib/mlxfwops_com.h | 259 +- mlxfwops/lib/security_version_gw.cpp | 136 +- mlxfwops/lib/security_version_gw.h | 18 +- mlxfwops/lib/signature_manager.h | 49 +- mlxfwops/lib/signature_manager_factory.h | 76 +- mlxfwops/uefi_c/mft_uefi_common.h | 12 +- mlxfwupdate/cmd_line_params.cpp | 58 +- mlxfwupdate/cmd_line_params.h | 3 +- mlxfwupdate/cmd_line_parser.cpp | 862 +- mlxfwupdate/cmd_line_parser.h | 6 +- mlxfwupdate/err_msgs.h | 59 +- mlxfwupdate/fw_version_old_clp.cpp | 29 +- mlxfwupdate/fw_version_old_clp.h | 10 +- mlxfwupdate/fw_version_with_sub_build.cpp | 30 +- mlxfwupdate/fw_version_with_sub_build.h | 10 +- mlxfwupdate/image_access.cpp | 432 +- mlxfwupdate/image_access.h | 43 +- mlxfwupdate/img_version.cpp | 113 +- mlxfwupdate/img_version.h | 18 +- mlxfwupdate/menu.cpp | 341 +- mlxfwupdate/menu.h | 88 +- mlxfwupdate/mlnx_dev.cpp | 918 +- mlxfwupdate/mlnx_dev.h | 72 +- mlxfwupdate/mlxfwmanager.cpp | 1998 +- mlxfwupdate/mlxfwmanager.h | 223 +- mlxfwupdate/mlxfwmanager_common.cpp | 174 +- mlxfwupdate/mlxfwmanager_common.h | 52 +- mlxfwupdate/output_fmts.cpp | 180 +- mlxfwupdate/output_fmts.h | 17 +- mlxfwupdate/psid_lookup_db.cpp | 44 +- mlxfwupdate/psid_lookup_db.h | 15 +- mlxfwupdate/psid_query_item.cpp | 11 +- mlxfwupdate/psid_query_item.h | 10 +- mlxfwupdate/server_request.cpp | 418 +- mlxfwupdate/server_request.h | 62 +- mlxreg/mlxreg_exception.cpp | 46 +- mlxreg/mlxreg_exception.h | 22 +- mlxreg/mlxreg_lib.cpp | 200 +- mlxreg/mlxreg_lib.h | 65 +- mlxreg/mlxreg_parser.cpp | 281 +- mlxreg/mlxreg_parser.h | 51 +- mlxreg/mlxreg_ui.cpp | 600 +- mlxreg/mlxreg_ui.h | 32 +- mlxsign_lib/mlxsign_com_def.h | 1 - mlxsign_lib/mlxsign_lib.cpp | 191 +- mlxsign_lib/mlxsign_lib.h | 37 +- mlxsign_lib/mlxsign_openssl_engine.cpp | 81 +- mlxsign_lib/mlxsign_openssl_engine.h | 19 +- mlxsign_lib/mlxsign_signer_interface.cpp | 51 +- mlxsign_lib/mlxsign_signer_interface.h | 12 +- mstdump/crd_lib/crdump.c | 580 +- mstdump/crd_lib/crdump.h | 133 +- mstdump/crd_main/mstdump.c | 85 +- mtcr_freebsd/mtcr_ul.c | 2003 +- mtcr_py/cmtcr.c | 163 +- mtcr_py/mtcr.py | 53 +- mtcr_py/test.py | 2 +- mtcr_ul/mtcr_ib.h | 45 +- mtcr_ul/mtcr_ib_ofed.c | 1455 +- mtcr_ul/mtcr_ib_res_mgt.c | 64 +- mtcr_ul/mtcr_ib_res_mgt.h | 22 +- mtcr_ul/mtcr_icmd_cif.h | 115 +- mtcr_ul/mtcr_int_defs.h | 24 +- mtcr_ul/mtcr_mem_ops.c | 52 +- mtcr_ul/mtcr_mem_ops.h | 15 +- mtcr_ul/mtcr_tools_cif.c | 409 +- mtcr_ul/mtcr_tools_cif.h | 51 +- mtcr_ul/mtcr_ul.c | 176 +- mtcr_ul/mtcr_ul_com.c | 2581 +- mtcr_ul/mtcr_ul_com.h | 227 +- mtcr_ul/mtcr_ul_icmd_cif.c | 1180 +- mtcr_ul/packets_common.c | 95 +- mtcr_ul/packets_common.h | 156 +- mtcr_ul/packets_layout.c | 40 +- mtcr_ul/packets_layout.h | 47 +- mvpd/mvpd.c | 396 +- mvpd/mvpd.h | 109 +- pldmlib/pldm_buff.cpp | 89 +- pldmlib/pldm_buff.h | 15 +- pldmlib/pldm_component_image.cpp | 37 +- pldmlib/pldm_component_image.h | 14 +- pldmlib/pldm_dev_id_record.cpp | 108 +- pldmlib/pldm_dev_id_record.h | 17 +- pldmlib/pldm_pkg.cpp | 50 +- pldmlib/pldm_pkg.h | 25 +- pldmlib/pldm_pkg_hdr.cpp | 37 +- pldmlib/pldm_pkg_hdr.h | 40 +- pldmlib/pldm_record_descriptor.cpp | 68 +- pldmlib/pldm_record_descriptor.h | 17 +- reg_access/reg_access.c | 782 +- reg_access/reg_access.h | 151 +- reg_access/regaccess.py | 135 +- resourcedump/__init__.py | 63 +- resourcedump/commands/CommandFactory.py | 65 +- resourcedump/commands/DumpCommand.py | 64 +- resourcedump/commands/QueryCommand.py | 60 +- resourcedump/commands/ResDumpCommand.py | 64 +- resourcedump/commands/__init__.py | 60 +- resourcedump/fetchers/CapabilityFetcher.py | 64 +- resourcedump/fetchers/ResourceDumpFetcher.py | 138 +- resourcedump/fetchers/__init__.py | 63 +- resourcedump/filters/SegmentsFilter.py | 60 +- resourcedump/filters/__init__.py | 62 +- resourcedump/mstresourcedump.py | 68 +- resourcedump/resource_data/DataPrinter.py | 69 +- resourcedump/resource_data/DumpData.py | 65 +- resourcedump/resource_data/QueryData.py | 68 +- resourcedump/resource_data/__init__.py | 63 +- resourcedump/segments/CommandSegment.py | 60 +- resourcedump/segments/ErrorSegment.py | 60 +- resourcedump/segments/InfoSegment.py | 60 +- resourcedump/segments/MenuRecord.py | 64 +- resourcedump/segments/MenuSegment.py | 72 +- resourcedump/segments/NoticeSegment.py | 60 +- resourcedump/segments/RefSegment.py | 64 +- resourcedump/segments/ResourceSegment.py | 60 +- resourcedump/segments/Segment.py | 64 +- resourcedump/segments/SegmentCreator.py | 64 +- resourcedump/segments/SegmentFactory.py | 64 +- resourcedump/segments/TerminateSegment.py | 60 +- resourcedump/segments/__init__.py | 60 +- resourcedump/utils/Exceptions.py | 60 +- resourcedump/utils/__init__.py | 65 +- resourcedump/utils/constants.py | 62 +- resourcedump/validation/ArgToMenuVerifier.py | 64 +- .../validation/CapabilityValidator.py | 64 +- resourcedump/validation/__init__.py | 63 +- resourceparse/__init__.py | 63 +- resourceparse/mstresourceparse.py | 64 +- resourceparse/parsers/AdbParser.py | 131 +- resourceparse/parsers/Parser.py | 72 +- resourceparse/parsers/__init__.py | 63 +- resourceparse/resource_data/AdbData.py | 66 +- resourceparse/resource_data/DataPrinter.py | 64 +- resourceparse/resource_data/RawData.py | 64 +- resourceparse/resource_data/__init__.py | 63 +- resourceparse/segments/CommandSegment.py | 60 +- resourceparse/segments/ErrorSegment.py | 60 +- resourceparse/segments/InfoSegment.py | 64 +- resourceparse/segments/MenuRecord.py | 64 +- resourceparse/segments/MenuSegment.py | 68 +- resourceparse/segments/NoticeSegment.py | 62 +- resourceparse/segments/RefSegment.py | 64 +- resourceparse/segments/ResourceSegment.py | 61 +- resourceparse/segments/Segment.py | 65 +- resourceparse/segments/SegmentCreator.py | 64 +- resourceparse/segments/SegmentFactory.py | 64 +- resourceparse/segments/TerminateSegment.py | 60 +- resourceparse/segments/__init__.py | 60 +- resourceparse/utils/Exceptions.py | 60 +- resourceparse/utils/__init__.py | 63 +- resourceparse/utils/constants.py | 64 +- small_utils/binary_file.py | 16 +- small_utils/congestion.cpp | 221 +- small_utils/congestion.h | 18 +- small_utils/mcra.c | 275 +- small_utils/mlxfwresetlib/__init__.py | 63 +- small_utils/mlxfwresetlib/cmd_reg_mcam.py | 8 +- small_utils/mlxfwresetlib/cmd_reg_mfrl.py | 49 +- small_utils/mlxfwresetlib/cmd_reg_mpcir.py | 22 +- small_utils/mlxfwresetlib/logger.py | 11 +- small_utils/mlxfwresetlib/mcra.py | 13 +- .../mlnx_peripheral_components.py | 24 +- .../mlxfwresetlib/mlxfwreset_mlnxdriver.py | 135 +- .../mlxfwreset_status_checker.py | 6 +- small_utils/mlxfwresetlib/mlxfwreset_utils.py | 41 +- small_utils/mlxfwresetlib/pci_device.py | 18 +- small_utils/mlxpci_lib.py | 118 +- small_utils/mread.c | 23 +- small_utils/mstfwreset.py | 537 +- small_utils/mtserver.c | 1118 +- small_utils/mwrite.c | 27 +- small_utils/tcp.c | 295 +- small_utils/tcp.h | 17 +- small_utils/vpd.c | 263 +- tools_crypto/tools_md5.c | 2 +- tools_crypto/tools_md5.h | 5 +- tools_layouts/adb_to_c_utils.c | 181 +- tools_layouts/adb_to_c_utils.h | 434 +- tools_layouts/cibfw_layouts.c | 2043 +- tools_layouts/cibfw_layouts.h | 1300 +- tools_layouts/cx4fw_layouts.c | 1162 +- tools_layouts/cx4fw_layouts.h | 670 +- tools_layouts/cx6fw_layouts.c | 394 +- tools_layouts/cx6fw_layouts.h | 239 +- tools_layouts/icmd_layouts.c | 719 +- tools_layouts/icmd_layouts.h | 1098 +- tools_layouts/image_info_layouts.c | 144 +- tools_layouts/image_info_layouts.h | 776 +- tools_layouts/image_layout_layouts.c | 2936 +-- tools_layouts/image_layout_layouts.h | 1964 +- tools_layouts/prm_adb_db.cpp | 59 +- tools_layouts/prm_adb_db.h | 12 +- tools_layouts/reg_access_hca_layouts.c | 5988 +++-- tools_layouts/reg_access_hca_layouts.h | 4001 +-- tools_layouts/reg_access_switch_layouts.c | 1874 +- tools_layouts/reg_access_switch_layouts.h | 1185 +- tools_layouts/register_access_open_layouts.c | 398 +- tools_layouts/register_access_open_layouts.h | 283 +- tools_layouts/register_access_sib_layouts.c | 935 +- tools_layouts/register_access_sib_layouts.h | 615 +- tools_layouts/tools_open_layouts.c | 10506 ++++---- tools_layouts/tools_open_layouts.h | 7116 +++--- tools_res_mgmt/tools_res_mgmt.c | 640 +- tools_res_mgmt/tools_res_mgmt.h | 131 +- tools_res_mgmt/tools_time.c | 10 +- tools_res_mgmt/tools_time.h | 18 +- tracers/fwtrace/fw_trace_utilities.py | 62 +- tracers/fwtrace/mstfwtrace.py | 87 +- tracers/fwtrace/secure_fw_trace.py | 56 +- xz_utils/xz_utils.c | 218 +- xz_utils/xz_utils.h | 31 +- 439 files changed, 94987 insertions(+), 84106 deletions(-) create mode 100755 .clang-format mode change 100755 => 100644 adb_parser/adb_parser.cpp mode change 100755 => 100644 ext_libs/json/json/autolink.h mode change 100755 => 100644 ext_libs/json/json/config.h mode change 100755 => 100644 ext_libs/json/json/features.h mode change 100755 => 100644 ext_libs/json/json/forwards.h mode change 100755 => 100644 ext_libs/json/json/json.h mode change 100755 => 100644 ext_libs/json/json/reader.h mode change 100755 => 100644 ext_libs/json/json/value.h mode change 100755 => 100644 ext_libs/json/json/writer.h mode change 100755 => 100644 ext_libs/muparser/muParser.cpp mode change 100755 => 100644 ext_libs/muparser/muParser.h mode change 100755 => 100644 ext_libs/muparser/muParserBase.cpp mode change 100755 => 100644 ext_libs/muparser/muParserBase.h mode change 100755 => 100644 ext_libs/muparser/muParserBytecode.cpp mode change 100755 => 100644 ext_libs/muparser/muParserBytecode.h mode change 100755 => 100644 ext_libs/muparser/muParserCallback.cpp mode change 100755 => 100644 ext_libs/muparser/muParserCallback.h mode change 100755 => 100644 ext_libs/muparser/muParserDLL.cpp mode change 100755 => 100644 ext_libs/muparser/muParserDLL.h mode change 100755 => 100644 ext_libs/muparser/muParserDef.h mode change 100755 => 100644 ext_libs/muparser/muParserError.cpp mode change 100755 => 100644 ext_libs/muparser/muParserError.h mode change 100755 => 100644 ext_libs/muparser/muParserFixes.h mode change 100755 => 100644 ext_libs/muparser/muParserInt.cpp mode change 100755 => 100644 ext_libs/muparser/muParserInt.h mode change 100755 => 100644 ext_libs/muparser/muParserStack.h mode change 100755 => 100644 ext_libs/muparser/muParserTemplateMagic.h mode change 100755 => 100644 ext_libs/muparser/muParserTest.cpp mode change 100755 => 100644 ext_libs/muparser/muParserTest.h mode change 100755 => 100644 ext_libs/muparser/muParserToken.h mode change 100755 => 100644 ext_libs/muparser/muParserTokenReader.cpp mode change 100755 => 100644 ext_libs/muparser/muParserTokenReader.h mode change 100755 => 100644 mflash/mflash_types.h mode change 100755 => 100644 mlxarchive/mfa2_buff.cpp mode change 100755 => 100644 mlxfwops/lib/fs2_ops.h mode change 100755 => 100644 mlxfwops/lib/fuse_gw.cpp mode change 100755 => 100644 mlxfwops/lib/fuse_gw.h mode change 100755 => 100644 mstdump/crd_lib/crdump.h mode change 100755 => 100644 tools_layouts/cx6fw_layouts.c mode change 100755 => 100644 tools_layouts/cx6fw_layouts.h mode change 100755 => 100644 tools_layouts/image_layout_layouts.c mode change 100755 => 100644 tools_layouts/image_layout_layouts.h mode change 100755 => 100644 tools_layouts/prm_adb_db.cpp mode change 100755 => 100644 tools_layouts/prm_adb_db.h mode change 100755 => 100644 xz_utils/xz_utils.h diff --git a/.clang-format b/.clang-format new file mode 100755 index 00000000..f90db87e --- /dev/null +++ b/.clang-format @@ -0,0 +1,77 @@ +--- +# BasedOnStyle: Google +AccessModifierOffset: -4 +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +ConstructorInitializerIndentWidth: 4 +ConstructorInitializerAllOnOneLineOrOnePerLine: true +AlignEscapedNewlinesLeft: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakTemplateDeclarations: true +AlwaysBreakBeforeMultilineStrings: false +BreakBeforeBinaryOperators: false +BreakBeforeTernaryOperators: false +BreakConstructorInitializers: AfterColon +BreakConstructorInitializersBeforeComma: false +BinPackParameters: false +Standard: Auto +IndentWidth: 4 +TabWidth: 8 +UseTab: Never +BraceWrapping: + AfterClass: false + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: true + AfterExternBlock: true + BeforeCatch: true + BeforeElse: true + IndentBraces: true + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +CommentPragmas: '^ ignore_styling:' +ColumnLimit: 120 +DerivePointerBinding: true +DerivePointerAlignment: false +ExperimentalAutoDetectBinPacking: true +IndentCaseLabels: true +KeepEmptyLinesAtTheStartOfBlocks: false +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCSpaceBeforeProtocolList: false +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 60 +PenaltyBreakString: 60 +PenaltyBreakFirstLessLess: 60 +PenaltyExcessCharacter: 60 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerBindsToType: true +PointerAlignment: Left +SpacesBeforeTrailingComments: 1 +Cpp11BracedListStyle: true +BreakBeforeBraces: Allman +IndentFunctionDeclarationAfterType: true +SpacesInParentheses: false +SpacesInAngles: false +SpaceInEmptyParentheses: false +SpacesInCStyleCastParentheses: false +SpaceAfterControlStatementKeyword: true +SpaceBeforeAssignmentOperators: true +ContinuationIndentWidth: 2 +ReflowComments: true +SortIncludes: false +SortUsingDeclarations: false +SpaceAfterTemplateKeyword: false +SpacesInContainerLiterals: false +AllowShortFunctionsOnASingleLine: Inline +BreakStringLiterals: false +... + diff --git a/adb_parser/adb_common_functions.h b/adb_parser/adb_common_functions.h index 47b06809..6c572817 100644 --- a/adb_parser/adb_common_functions.h +++ b/adb_parser/adb_common_functions.h @@ -32,5 +32,4 @@ * Version: $Id$ */ - indentString(int) diff --git a/adb_parser/adb_config.cpp b/adb_parser/adb_config.cpp index 90507501..363036a3 100644 --- a/adb_parser/adb_config.cpp +++ b/adb_parser/adb_config.cpp @@ -39,38 +39,42 @@ #include "adb_config.h" #include -void AdbConfig::print(int indent) { +void AdbConfig::print(int indent) +{ cout << indentString(indent) << "Attributes:" << endl; AttrsMap::iterator iter; for (iter = attrs.begin(); iter != attrs.end(); iter++) - cout << indentString(indent + 1) << iter->first << " - " - << iter->second << endl; + cout << indentString(indent + 1) << iter->first << " - " << iter->second << endl; cout << indentString(indent) << "Enums:" << endl; for (iter = enums.begin(); iter != enums.end(); iter++) - cout << indentString(indent + 1) << iter->first << " - " - << iter->second << endl; + cout << indentString(indent + 1) << iter->first << " - " << iter->second << endl; } /** * Function: AdbConfig::toXml **/ -string AdbConfig::toXml() { +string AdbConfig::toXml() +{ string xml = "first + "=\"" + encodeXml(it->second) + "\""; } - if (!enums.empty()) { + if (!enums.empty()) + { xml += " >\n"; - for (AttrsMap::iterator it = enums.begin(); it != enums.end(); it++) { - xml += "\tfirst) + "\" value=\"" - + encodeXml(it->second) + "\" />\n"; + for (AttrsMap::iterator it = enums.begin(); it != enums.end(); it++) + { + xml += "\tfirst) + "\" value=\"" + encodeXml(it->second) + "\" />\n"; } xml += ""; - } else { + } + else + { xml += " />"; } diff --git a/adb_parser/adb_config.h b/adb_parser/adb_config.h index c61465e2..8a891db1 100644 --- a/adb_parser/adb_config.h +++ b/adb_parser/adb_config.h @@ -46,7 +46,8 @@ using namespace std; typedef map AttrsMap; -class AdbConfig { +class AdbConfig +{ public: // FOR DEBUG void print(int indent = 0); diff --git a/adb_parser/adb_db.cpp b/adb_parser/adb_db.cpp index e56edb46..ccc01086 100644 --- a/adb_parser/adb_db.cpp +++ b/adb_parser/adb_db.cpp @@ -41,20 +41,21 @@ #include #include "adb_db.h" -#define CHECK_FIELD(field, node_w) \ - if (((AdbInstance*)field)->isReserved()) { \ - continue; \ - } \ - offset = db_field_offset(field); \ - if (offset - node_w->node->offset < from || \ - offset - node_w->node->offset > to) { \ - continue; \ +#define CHECK_FIELD(field, node_w) \ + if (((AdbInstance*)field)->isReserved()) \ + { \ + continue; \ + } \ + offset = db_field_offset(field); \ + if (offset - node_w->node->offset < from || offset - node_w->node->offset > to) \ + { \ + continue; \ } struct node_wrapper { - AdbInstance *node; - vector *fields; + AdbInstance* node; + vector* fields; }; static char err[1024] = {0}; @@ -65,15 +66,15 @@ static char err[1024] = {0}; adb_db_t* db_create() { return new Adb(); - } /** * db_load */ -int db_load(adb_db_t *db, const char *adb_file_path, int add_reserved) +int db_load(adb_db_t* db, const char* adb_file_path, int add_reserved) { - if (!((Adb*)db)->load(adb_file_path, add_reserved, false)) { + if (!((Adb*)db)->load(adb_file_path, add_reserved, false)) + { sprintf(err, "Failed to load adabe project: %s", ((Adb*)db)->getLastError().c_str()); return 1; } @@ -84,9 +85,10 @@ int db_load(adb_db_t *db, const char *adb_file_path, int add_reserved) /** * db_load_from_str */ -int db_load_from_str(adb_db_t *db, const char *adb_data, int add_reserved) +int db_load_from_str(adb_db_t* db, const char* adb_data, int add_reserved) { - if (!((Adb*)db)->loadFromString(adb_data, add_reserved, false)) { + if (!((Adb*)db)->loadFromString(adb_data, add_reserved, false)) + { sprintf(err, "Failed to load adabe project: %s", ((Adb*)db)->getLastError().c_str()); return 1; } @@ -97,9 +99,10 @@ int db_load_from_str(adb_db_t *db, const char *adb_data, int add_reserved) /** * db_destroy */ -void db_destroy(adb_db_t *db) +void db_destroy(adb_db_t* db) { - if (db) { + if (db) + { delete (Adb*)db; } } @@ -112,34 +115,39 @@ const char* db_get_last_err() return err; } - -adb_limits_map_t* db_create_limits_map(adb_db_t *db) +adb_limits_map_t* db_create_limits_map(adb_db_t* db) { - map *limits = new map(); + map* limits = new map(); // Load defines - if (db) { - for (size_t i = 0; i < ((Adb*)db)->configs.size(); i++) { + if (db) + { + for (size_t i = 0; i < ((Adb*)db)->configs.size(); i++) + { AttrsMap::iterator attrs_map = ((Adb*)db)->configs[i]->attrs.find("define"); - if (attrs_map != ((Adb*)db)->configs[i]->attrs.end()) { + if (attrs_map != ((Adb*)db)->configs[i]->attrs.end()) + { vector defVal; boost::algorithm::split(defVal, attrs_map->second, boost::is_any_of(string("="))); - if (defVal.size() == 1) { + if (defVal.size() == 1) + { ((map*)limits)->insert(pair(defVal[0], "0")); - } else { + } + else + { ((map*)limits)->insert(pair(defVal[0], defVal[1])); } } } } return (adb_limits_map_t*)limits; - } -void db_destroy_limits_map(adb_limits_map_t *limits) +void db_destroy_limits_map(adb_limits_map_t* limits) { - if (limits) { + if (limits) + { ((map*)limits)->clear(); delete (map*)limits; } @@ -148,16 +156,18 @@ void db_destroy_limits_map(adb_limits_map_t *limits) /** * db_get_node */ -adb_node_t* db_get_node(adb_db_t *db, const char *node_name) +adb_node_t* db_get_node(adb_db_t* db, const char* node_name) { - Adb *adb = (Adb*)db; - AdbInstance *node = adb->createLayout(node_name, false); - if (!node) { + Adb* adb = (Adb*)db; + AdbInstance* node = adb->createLayout(node_name, false); + if (!node) + { sprintf(err, "Failed to create node %s: %s", node_name, adb->getLastError().c_str()); return NULL; } - struct node_wrapper *node_w = (struct node_wrapper*)malloc(sizeof(struct node_wrapper)); - if (!node_w) { + struct node_wrapper* node_w = (struct node_wrapper*)malloc(sizeof(struct node_wrapper)); + if (!node_w) + { delete node; sprintf(err, "Failed to allocate memory for node"); return NULL; @@ -172,14 +182,17 @@ adb_node_t* db_get_node(adb_db_t *db, const char *node_name) /** * db_node_destroy */ -void db_node_destroy(adb_node_t *node) +void db_node_destroy(adb_node_t* node) { - struct node_wrapper *node_w = (struct node_wrapper*)node; - if (node_w) { - if (node_w->node) { + struct node_wrapper* node_w = (struct node_wrapper*)node; + if (node_w) + { + if (node_w->node) + { delete node_w->node; } - if (node_w->fields) { + if (node_w->fields) + { delete node_w->fields; } free(node_w); @@ -189,65 +202,73 @@ void db_node_destroy(adb_node_t *node) /** * db_node_name */ -void db_node_name(adb_node_t *node, char name[]) +void db_node_name(adb_node_t* node, char name[]) { - struct node_wrapper *node_w = (struct node_wrapper*)node; + struct node_wrapper* node_w = (struct node_wrapper*)node; strcpy(name, node_w->node->name.c_str()); } /** * db_node_size */ -int db_node_size(adb_node_t *node) +int db_node_size(adb_node_t* node) { - struct node_wrapper *node_w = (struct node_wrapper*)node; + struct node_wrapper* node_w = (struct node_wrapper*)node; return node_w->node->size; } /** * db_node_num_of_fields */ -int db_node_num_of_fields(adb_node_t *node) +int db_node_num_of_fields(adb_node_t* node) { - struct node_wrapper *node_w = (struct node_wrapper*)node; + struct node_wrapper* node_w = (struct node_wrapper*)node; return (int)node_w->fields->size(); } /** * db_node_get_field */ -adb_field_t* db_node_get_field(adb_node_t *node, int field_idx) +adb_field_t* db_node_get_field(adb_node_t* node, int field_idx) { - if (field_idx >= db_node_num_of_fields(node)) { + if (field_idx >= db_node_num_of_fields(node)) + { sprintf(err, "index out of range"); return NULL; } - struct node_wrapper *node_w = (struct node_wrapper*)node; + struct node_wrapper* node_w = (struct node_wrapper*)node; return node_w->fields->at(field_idx); } /** * db_node_get_field_by_path */ -adb_field_t* db_node_get_field_by_path(adb_node_t *node, const char *path, int is_case_sensitive) +adb_field_t* db_node_get_field_by_path(adb_node_t* node, const char* path, int is_case_sensitive) { - struct node_wrapper *node_w = (struct node_wrapper*)node; + struct node_wrapper* node_w = (struct node_wrapper*)node; string fullPath(path); - if (node_w->node->isConditionalNode()) { + if (node_w->node->isConditionalNode()) + { fullPath += ".val"; } - for (size_t i = 0; i < node_w->fields->size(); i++) { - if (is_case_sensitive) { - if (node_w->fields->at(i)->fullName(1) == fullPath) { + for (size_t i = 0; i < node_w->fields->size(); i++) + { + if (is_case_sensitive) + { + if (node_w->fields->at(i)->fullName(1) == fullPath) + { return node_w->fields->at(i); } - } else { + } + else + { string field_name_lower = boost::algorithm::to_lower_copy(node_w->fields->at(i)->fullName(1)); string path_lower = boost::algorithm::to_lower_copy(fullPath); - if (path_lower == field_name_lower) { + if (path_lower == field_name_lower) + { return node_w->fields->at(i); } } @@ -261,9 +282,9 @@ adb_field_t* db_node_get_field_by_path(adb_node_t *node, const char *path, int i * db_node_dump * Returns: false on error */ -bool db_node_dump(adb_node_t *node, u_int8_t buf[], dump_format_t format, FILE *stream) +bool db_node_dump(adb_node_t* node, u_int8_t buf[], dump_format_t format, FILE* stream) { - struct node_wrapper *node_w = (struct node_wrapper*)node; + struct node_wrapper* node_w = (struct node_wrapper*)node; return db_node_range_dump(node, 0, node_w->node->size - 1, buf, format, stream); } @@ -271,13 +292,13 @@ bool db_node_dump(adb_node_t *node, u_int8_t buf[], dump_format_t format, FILE * * db_node_dump_with_limits * Returns: false on error */ -bool db_node_conditional_dump(adb_node_t *node, +bool db_node_conditional_dump(adb_node_t* node, u_int8_t buf[], dump_format_t format, - FILE *stream, - adb_limits_map_t *values_map) + FILE* stream, + adb_limits_map_t* values_map) { - struct node_wrapper *node_w = (struct node_wrapper*)node; + struct node_wrapper* node_w = (struct node_wrapper*)node; return db_node_conditional_range_dump(node, 0, node_w->node->size - 1, buf, format, stream, values_map); } @@ -285,8 +306,12 @@ bool db_node_conditional_dump(adb_node_t *node, * db_node_range_dump * Returns: false on error */ -bool db_node_range_dump(adb_node_t *node, u_int32_t from, u_int32_t to, - u_int8_t buf[], dump_format_t format, FILE *stream) +bool db_node_range_dump(adb_node_t* node, + u_int32_t from, + u_int32_t to, + u_int8_t buf[], + dump_format_t format, + FILE* stream) { return db_node_conditional_range_dump(node, from, to, buf, format, stream, NULL); } @@ -295,36 +320,41 @@ bool db_node_range_dump(adb_node_t *node, u_int32_t from, u_int32_t to, * db_node_range_dump_with_limits * Returns: false on error */ -bool db_node_conditional_range_dump(adb_node_t *node, +bool db_node_conditional_range_dump(adb_node_t* node, u_int32_t from, u_int32_t to, u_int8_t buf[], dump_format_t format, - FILE *stream, - adb_limits_map_t *values_map) + FILE* stream, + adb_limits_map_t* values_map) { int i; - adb_field_t *field; + adb_field_t* field; char enum_str[256]; char name[256]; int is_enum; u_int32_t value; u_int32_t offset; u_int32_t size; - struct node_wrapper *node_w = (struct node_wrapper*)node; - if (values_map) { + struct node_wrapper* node_w = (struct node_wrapper*)node; + if (values_map) + { // Fill values map for conditions - for (i = 0; i < db_node_num_of_fields(node); i++) { + for (i = 0; i < db_node_num_of_fields(node); i++) + { field = db_node_get_field(node, i); - if (!field) { + if (!field) + { return false; } CHECK_FIELD(field, node_w); db_field_full_name(field, 0, name); value = db_field_value(field, (u_int8_t*)buf); - if (node_w->node->isConditionalNode()) { - char *p = strstr(name, ".val"); - if (p != NULL) { + if (node_w->node->isConditionalNode()) + { + char* p = strstr(name, ".val"); + if (p != NULL) + { *p = '\0'; } } @@ -332,52 +362,63 @@ bool db_node_conditional_range_dump(adb_node_t *node, } } - for (i = 0; i < db_node_num_of_fields(node); i++) { + for (i = 0; i < db_node_num_of_fields(node); i++) + { field = db_node_get_field(node, i); - if (!field) { + if (!field) + { return false; } CHECK_FIELD(field, node_w); db_field_full_name(field, 0, name); value = db_field_value(field, (u_int8_t*)buf); - if (node_w->node->isConditionalNode()) { - char *p = strstr(name, ".val"); - if (p != NULL) { + if (node_w->node->isConditionalNode()) + { + char* p = strstr(name, ".val"); + if (p != NULL) + { *p = '\0'; } } /* * Just if the node is Conditional */ - if (node_w->node->isConditionalNode() && values_map != NULL) { - try { - AdbInstance *parentField = node_w->node->subItems[i]; - if (!parentField->isConditionValid(((map*)values_map))) { + if (node_w->node->isConditionalNode() && values_map != NULL) + { + try + { + AdbInstance* parentField = node_w->node->subItems[i]; + if (!parentField->isConditionValid(((map*)values_map))) + { ((map*)values_map)->erase(name); continue; } - } catch (...) { + } + catch (...) + { continue; } } is_enum = db_field_enum(field, value, enum_str); size = db_field_size(field); - if (stream != NULL) { - switch (format) { - case DB_FORMAT_STANDARD: - fprintf(stream, "%-40s : 0x%x %s\n", name, value, is_enum ? enum_str : ""); - break; - - case DB_FORMAT_STANDARD_NO_ENUM: - fprintf(stream, "%-40s : 0x%x\n", name, value); - break; - - case DB_FORMAT_FULL_DETAILS: - fprintf(stream, "%-40s : 0x%x %s - address: 0x%x.%d:%d\n", - name, value, is_enum ? enum_str : "", offset / 32 * 4, offset % 32, size); - break; + if (stream != NULL) + { + switch (format) + { + case DB_FORMAT_STANDARD: + fprintf(stream, "%-40s : 0x%x %s\n", name, value, is_enum ? enum_str : ""); + break; + + case DB_FORMAT_STANDARD_NO_ENUM: + fprintf(stream, "%-40s : 0x%x\n", name, value); + break; + + case DB_FORMAT_FULL_DETAILS: + fprintf(stream, "%-40s : 0x%x %s - address: 0x%x.%d:%d\n", name, value, is_enum ? enum_str : "", + offset / 32 * 4, offset % 32, size); + break; } } } @@ -387,7 +428,7 @@ bool db_node_conditional_range_dump(adb_node_t *node, /** * db_field_name */ -void db_field_name(adb_field_t *field, char name[]) +void db_field_name(adb_field_t* field, char name[]) { strcpy(name, ((AdbInstance*)field)->name.c_str()); } @@ -395,7 +436,7 @@ void db_field_name(adb_field_t *field, char name[]) /** * db_field_full_name */ -void db_field_full_name(adb_field_t *field, int skip_level, char name[]) +void db_field_full_name(adb_field_t* field, int skip_level, char name[]) { strcpy(name, ((AdbInstance*)field)->fullName(skip_level + 1).c_str()); } @@ -403,7 +444,7 @@ void db_field_full_name(adb_field_t *field, int skip_level, char name[]) /** * db_field_offset */ -int db_field_offset(adb_field_t *field) +int db_field_offset(adb_field_t* field) { return ((AdbInstance*)field)->offset; } @@ -411,7 +452,7 @@ int db_field_offset(adb_field_t *field) /** * db_field_size */ -int db_field_size(adb_field_t *field) +int db_field_size(adb_field_t* field) { return ((AdbInstance*)field)->size; } @@ -419,19 +460,19 @@ int db_field_size(adb_field_t *field) /** * db_field_value */ -u_int64_t db_field_value(adb_field_t *field, u_int8_t buf[]) +u_int64_t db_field_value(adb_field_t* field, u_int8_t buf[]) { -// cout << ((AdbInstance*)field)->offset / 8 << endl; -// for (unsigned i = 0; i < ((AdbInstance*)field)->offset / 8; i++) { -// printf ("%02x ", buf[i]); -// } + // cout << ((AdbInstance*)field)->offset / 8 << endl; + // for (unsigned i = 0; i < ((AdbInstance*)field)->offset / 8; i++) { + // printf ("%02x ", buf[i]); + // } return ((AdbInstance*)field)->popBuf(buf); } /** * db_field_set_value */ -void db_field_set_value(adb_field_t *field, u_int8_t buf[], u_int64_t value) +void db_field_set_value(adb_field_t* field, u_int8_t buf[], u_int64_t value) { ((AdbInstance*)field)->pushBuf(buf, value); } @@ -439,13 +480,16 @@ void db_field_set_value(adb_field_t *field, u_int8_t buf[], u_int64_t value) /** * db_field_enum */ -int db_field_enum(adb_field_t *field, u_int64_t value, char enum_str[]) +int db_field_enum(adb_field_t* field, u_int64_t value, char enum_str[]) { string s; - if (((AdbInstance*)field)->intToEnum(value, s)) { + if (((AdbInstance*)field)->intToEnum(value, s)) + { strcpy(enum_str, s.c_str()); return 1; - } else { + } + else + { strcpy(enum_str, ""); return 0; } @@ -454,12 +498,13 @@ int db_field_enum(adb_field_t *field, u_int64_t value, char enum_str[]) /** * db_print_nodes */ -void db_print_nodes(adb_db_t *db) +void db_print_nodes(adb_db_t* db) { int i = 0; printf("DB nodes list:\n"); - for (NodesMap::iterator iter = ((Adb*)db)->nodesMap.begin(); iter != ((Adb*)db)->nodesMap.end(); iter++) { + for (NodesMap::iterator iter = ((Adb*)db)->nodesMap.begin(); iter != ((Adb*)db)->nodesMap.end(); iter++) + { i++; printf("%-5d) %s\n", i, iter->first.c_str()); } diff --git a/adb_parser/adb_db.h b/adb_parser/adb_db.h index 21e3b85e..e6f651b2 100644 --- a/adb_parser/adb_db.h +++ b/adb_parser/adb_db.h @@ -38,64 +38,76 @@ #ifndef ADB_DB_H #define ADB_DB_H - #include #include #include "adb_parser.h" #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -typedef void adb_db_t; -typedef void adb_node_t; -typedef void adb_field_t; -typedef void adb_limits_map_t; + typedef void adb_db_t; + typedef void adb_node_t; + typedef void adb_field_t; + typedef void adb_limits_map_t; -typedef enum -{ - DB_FORMAT_STANDARD, - DB_FORMAT_STANDARD_NO_ENUM, - DB_FORMAT_FULL_DETAILS -} dump_format_t; + typedef enum + { + DB_FORMAT_STANDARD, + DB_FORMAT_STANDARD_NO_ENUM, + DB_FORMAT_FULL_DETAILS + } dump_format_t; -// TODO - this API isn't thread-safe because of the error reporting mechanism -// DB Functions -adb_db_t* db_create(); -int db_load(adb_db_t *db, const char *adb_file_path, int add_reserved); -int db_load_from_str(adb_db_t *db, const char *adb_data, int add_reserved); -void db_destroy(adb_db_t *db); -const char* db_get_last_err(); + // TODO - this API isn't thread-safe because of the error reporting mechanism + // DB Functions + adb_db_t* db_create(); + int db_load(adb_db_t* db, const char* adb_file_path, int add_reserved); + int db_load_from_str(adb_db_t* db, const char* adb_data, int add_reserved); + void db_destroy(adb_db_t* db); + const char* db_get_last_err(); -adb_limits_map_t* db_create_limits_map(adb_db_t *db); -void db_destroy_limits_map(adb_limits_map_t *limits); + adb_limits_map_t* db_create_limits_map(adb_db_t* db); + void db_destroy_limits_map(adb_limits_map_t* limits); -// Node Functions - *** node contains flat fields (full path leaves) *** -adb_node_t* db_get_node(adb_db_t *db, const char *node_name); -void db_node_destroy(adb_node_t *node); -void db_node_name(adb_node_t *node, char name[]); -int db_node_size(adb_node_t *node); -int db_node_num_of_fields(adb_node_t *node); -adb_field_t* db_node_get_field(adb_node_t *node, int field_idx); -adb_field_t* db_node_get_field_by_path(adb_node_t *node, const char *path, int is_case_sensitive); -bool db_node_dump(adb_node_t *node, u_int8_t buf[], dump_format_t format, FILE *stream); -bool db_node_conditional_dump(adb_node_t *node, u_int8_t buf[], dump_format_t format, - FILE *stream, adb_limits_map_t *values_map); -bool db_node_range_dump(adb_node_t *node, u_int32_t from, u_int32_t to, - u_int8_t buf[], dump_format_t format, FILE *stream); -bool db_node_conditional_range_dump(adb_node_t *node, u_int32_t from, u_int32_t to, - u_int8_t buf[], dump_format_t format, FILE *stream, adb_limits_map_t *values_map); + // Node Functions - *** node contains flat fields (full path leaves) *** + adb_node_t* db_get_node(adb_db_t* db, const char* node_name); + void db_node_destroy(adb_node_t* node); + void db_node_name(adb_node_t* node, char name[]); + int db_node_size(adb_node_t* node); + int db_node_num_of_fields(adb_node_t* node); + adb_field_t* db_node_get_field(adb_node_t* node, int field_idx); + adb_field_t* db_node_get_field_by_path(adb_node_t* node, const char* path, int is_case_sensitive); + bool db_node_dump(adb_node_t* node, u_int8_t buf[], dump_format_t format, FILE* stream); + bool db_node_conditional_dump(adb_node_t* node, + u_int8_t buf[], + dump_format_t format, + FILE* stream, + adb_limits_map_t* values_map); + bool db_node_range_dump(adb_node_t* node, + u_int32_t from, + u_int32_t to, + u_int8_t buf[], + dump_format_t format, + FILE* stream); + bool db_node_conditional_range_dump(adb_node_t* node, + u_int32_t from, + u_int32_t to, + u_int8_t buf[], + dump_format_t format, + FILE* stream, + adb_limits_map_t* values_map); -// Field Functions -void db_field_name(adb_field_t *field, char name[]); -void db_field_full_name(adb_field_t *field, int skip_level, char name[]); -int db_field_offset(adb_field_t *field); -int db_field_size(adb_field_t *field); -u_int64_t db_field_value(adb_field_t *field, u_int8_t buf[]); -void db_field_set_value(adb_field_t *field, u_int8_t buf[], u_int64_t value); -int db_field_enum(adb_field_t *field, u_int64_t value, char enum_str[]); + // Field Functions + void db_field_name(adb_field_t* field, char name[]); + void db_field_full_name(adb_field_t* field, int skip_level, char name[]); + int db_field_offset(adb_field_t* field); + int db_field_size(adb_field_t* field); + u_int64_t db_field_value(adb_field_t* field, u_int8_t buf[]); + void db_field_set_value(adb_field_t* field, u_int8_t buf[], u_int64_t value); + int db_field_enum(adb_field_t* field, u_int64_t value, char enum_str[]); -// For debug only -void db_print_nodes(adb_db_t *db); + // For debug only + void db_print_nodes(adb_db_t* db); #ifdef __cplusplus } diff --git a/adb_parser/adb_exceptionHolder.cpp b/adb_parser/adb_exceptionHolder.cpp index b642393a..32c7b508 100644 --- a/adb_parser/adb_exceptionHolder.cpp +++ b/adb_parser/adb_exceptionHolder.cpp @@ -37,17 +37,17 @@ ExceptionsMap ExceptionHolder::adbExceptionMap; const string ExceptionHolder::FATAL_EXCEPTION = "FATAL"; -const string ExceptionHolder::ERROR_EXCEPTION = "ERROR"; -const string ExceptionHolder::WARN_EXCEPTION = "WARNING"; +const string ExceptionHolder::ERROR_EXCEPTION = "ERROR"; +const string ExceptionHolder::WARN_EXCEPTION = "WARNING"; int ExceptionHolder::exceptionCounter = 0; -AdbException::AdbException() { -} +AdbException::AdbException() {} /** * Function: AdbException::AdbException **/ -AdbException::AdbException(const char *fmt, ...) { +AdbException::AdbException(const char* fmt, ...) +{ char tmp[1024]; va_list args; va_start(args, fmt); @@ -59,31 +59,31 @@ AdbException::AdbException(const char *fmt, ...) { /** * Function: AdbException::AdbException **/ -AdbException::AdbException(string msg) : - _msg(msg) { -} +AdbException::AdbException(string msg) : _msg(msg) {} /** * Function: AdbException::~AdbException **/ -AdbException::~AdbException() throw () { -} +AdbException::~AdbException() throw() {} /** * Function: AdbException::what **/ -const char* AdbException::what() const throw () { +const char* AdbException::what() const throw() +{ return _msg.c_str(); } /** * Function: AdbException::what_s **/ -string AdbException::what_s() const { +string AdbException::what_s() const +{ return _msg; } -int ExceptionHolder::getNumberOfExceptions() { +int ExceptionHolder::getNumberOfExceptions() +{ return ExceptionHolder::exceptionCounter; } @@ -92,7 +92,8 @@ int ExceptionHolder::getNumberOfExceptions() { * * This function return the adb exception map * **/ -ExceptionsMap ExceptionHolder::getAdbExceptionsMap() { +ExceptionsMap ExceptionHolder::getAdbExceptionsMap() +{ return ExceptionHolder::adbExceptionMap; } @@ -101,7 +102,8 @@ ExceptionsMap ExceptionHolder::getAdbExceptionsMap() { * * This function take the excpetion type [FATAL:0, ERROR:1, WARNING:2] and the exception string * * Then it insert it to the adb exception map * **/ -void ExceptionHolder::insertNewException(const string exceptionType, string exceptionTxt) { +void ExceptionHolder::insertNewException(const string exceptionType, string exceptionTxt) +{ ExceptionHolder::adbExceptionMap[exceptionType].push_back(exceptionTxt); ExceptionHolder::exceptionCounter += 1; } diff --git a/adb_parser/adb_exceptionHolder.h b/adb_parser/adb_exceptionHolder.h index 80a93500..f6cfd751 100644 --- a/adb_parser/adb_exceptionHolder.h +++ b/adb_parser/adb_exceptionHolder.h @@ -45,18 +45,17 @@ using namespace std; - typedef vector StringVector; typedef map ExceptionsMap; - - -class ExceptionHolder { +class ExceptionHolder +{ public: // METHODS static void insertNewException(const string exceptionType, string exceptionTxt); static ExceptionsMap getAdbExceptionsMap(); static int getNumberOfExceptions(); + public: // VARIABLES static ExceptionsMap adbExceptionMap; @@ -67,21 +66,21 @@ class ExceptionHolder { }; /*************************** AdbException ***************************/ -class AdbException: public std::exception { +class AdbException : public std::exception +{ public: // Methods AdbException(); - AdbException(const char *msg, ...) __attribute__((format(__printf__, 2, 3))); + AdbException(const char* msg, ...) __attribute__((format(__printf__, 2, 3))); AdbException(string msg); - virtual ~AdbException() throw (); - virtual const char* what() const throw (); + virtual ~AdbException() throw(); + virtual const char* what() const throw(); virtual string what_s() const; private: string _msg; }; - /** * Function: ExceptionHolder::getNumberOfExceptions * This function return the number of exceptions found diff --git a/adb_parser/adb_expr.cpp b/adb_parser/adb_expr.cpp index 1d3e85cf..bb775117 100644 --- a/adb_parser/adb_expr.cpp +++ b/adb_parser/adb_expr.cpp @@ -38,23 +38,17 @@ /** * Function: AdbExpr::AdbExpr **/ -AdbExpr::AdbExpr() : _varsMap(0) -{ - -} +AdbExpr::AdbExpr() : _varsMap(0) {} /** * Function: AdbExpr::~AdbExpr **/ -AdbExpr::~AdbExpr() -{ - -} +AdbExpr::~AdbExpr() {} /** * Function: AdbExpr::setVars **/ -void AdbExpr::setVars(map *varsMap) +void AdbExpr::setVars(map* varsMap) { _varsMap = varsMap; } @@ -66,35 +60,44 @@ const char* AdbExpr::statusStr(int status) { switch (status) { - case Expr::ERR_RPAR_EXP: return "Right parentheses expected"; + case Expr::ERR_RPAR_EXP: + return "Right parentheses expected"; - case Expr::ERR_VALUE_EXP: return "Value expected"; + case Expr::ERR_VALUE_EXP: + return "Value expected"; - case Expr::ERR_BIN_EXP: return "Binary operation expected "; + case Expr::ERR_BIN_EXP: + return "Binary operation expected "; - case Expr::ERR_DIV_ZERO: return "Divide zero attempt"; + case Expr::ERR_DIV_ZERO: + return "Divide zero attempt"; - case Expr::ERR_BAD_NUMBER: return "Bad constant syntax"; + case Expr::ERR_BAD_NUMBER: + return "Bad constant syntax"; - case Expr::ERR_BAD_NAME: return "Variable Name not resolved"; + case Expr::ERR_BAD_NAME: + return "Variable Name not resolved"; - default: return "Unknown error"; + default: + return "Unknown error"; } } /** * Function: AdbExpr::ResolveName **/ -int AdbExpr::ResolveName(char *name, u_int64_t *val) +int AdbExpr::ResolveName(char* name, u_int64_t* val) { map::iterator it = _varsMap->find(name); - if (it == _varsMap->end()) { + if (it == _varsMap->end()) + { return ERR_BAD_NAME; } - char *end; + char* end; *val = strtoul(it->second.c_str(), &end, 0); - if (*end != '\0') { + if (*end != '\0') + { return ERR_BAD_NUMBER; } diff --git a/adb_parser/adb_expr.h b/adb_parser/adb_expr.h index 8c92f7f2..87edf552 100644 --- a/adb_parser/adb_expr.h +++ b/adb_parser/adb_expr.h @@ -49,12 +49,12 @@ class AdbExpr : public Expr ~AdbExpr(); static const char* statusStr(int status); - int ResolveName(char *name, u_int64_t *val); + int ResolveName(char* name, u_int64_t* val); void Error(const std::string& message); - void setVars(map *varsMap); + void setVars(map* varsMap); private: - map *_varsMap; + map* _varsMap; }; #endif // ADB_EXPR_H diff --git a/adb_parser/adb_field.cpp b/adb_parser/adb_field.cpp index 807885ad..8a165fb2 100644 --- a/adb_parser/adb_field.cpp +++ b/adb_parser/adb_field.cpp @@ -43,17 +43,22 @@ #include #include -AdbField::AdbField() : size(0), offset(0xffffffff), definedAsArr(false), lowBound(0), - highBound(0), unlimitedArr(false), isReserved(false), userData(0) +AdbField::AdbField() : + size(0), + offset(0xffffffff), + definedAsArr(false), + lowBound(0), + highBound(0), + unlimitedArr(false), + isReserved(false), + userData(0) { } /** * Function: AdbField::~AdbField **/ -AdbField::~AdbField() -{ -} +AdbField::~AdbField() {} /** * Function: AdbField::isLeaf @@ -74,7 +79,7 @@ bool AdbField::isStruct() /** * Function: AdbField::operator< **/ -bool AdbField::operator<(AdbField &other) +bool AdbField::operator<(AdbField& other) { return offset < other.offset; } @@ -138,15 +143,15 @@ u_int32_t AdbField::eSize() void AdbField::print(int indent) { cout << indentString(indent); - cout << "- FIELD - Name: " << name << " offset: 0x" << hex << offset / 32 * 4 << "." << dec << offset % 32 << " size: 0x" << hex << size / 32 * 4 << "." << dec << size % 32 << " low_bound: " << lowBound - << " high_bound: " << highBound << " sub_node: " << subNode - << " isReserved: " << isReserved << endl; + cout << "- FIELD - Name: " << name << " offset: 0x" << hex << offset / 32 * 4 << "." << dec << offset % 32 + << " size: 0x" << hex << size / 32 * 4 << "." << dec << size % 32 << " low_bound: " << lowBound + << " high_bound: " << highBound << " sub_node: " << subNode << " isReserved: " << isReserved << endl; } /** * Function: AdbField::toXml **/ -string AdbField::toXml(const string &addPrefix) +string AdbField::toXml(const string& addPrefix) { string xml = " #include -string addPathSuffixForArraySupport(string path) { - if (path[path.length()-1] == ']') { //Won't add suffix if leaf is in Array +string addPathSuffixForArraySupport(string path) +{ + if (path[path.length() - 1] == ']') + { // Won't add suffix if leaf is in Array return ""; - } - size_t pos = 0; + } + size_t pos = 0; string suffix = ""; - while ((pos = path.find("[")) != std::string::npos) {//Add array index number in path to suffix. + while ((pos = path.find("[")) != std::string::npos) + { // Add array index number in path to suffix. size_t end_pos = path.find("]"); - size_t len = end_pos - pos - 1; - suffix = suffix + "_" + path.substr(pos+1, len); - path.erase(0, end_pos+1); - } + size_t len = end_pos - pos - 1; + suffix = suffix + "_" + path.substr(pos + 1, len); + path.erase(0, end_pos + 1); + } return suffix; } AdbInstance::AdbInstance() : - fieldDesc(NULL), nodeDesc(NULL), parent(NULL), offset(0xffffffff), size(0), maxLeafSize(0), - arrIdx(0), isNameBeenExtended(false), unionSelector(NULL), isDiff(false), userData(NULL) + fieldDesc(NULL), + nodeDesc(NULL), + parent(NULL), + offset(0xffffffff), + size(0), + maxLeafSize(0), + arrIdx(0), + isNameBeenExtended(false), + unionSelector(NULL), + isDiff(false), + userData(NULL) { - } /** * Function: AdbInstance::AdbInstance **/ -AdbInstance::~AdbInstance() { +AdbInstance::~AdbInstance() +{ for (size_t i = 0; i < subItems.size(); i++) delete subItems[i]; } @@ -81,58 +93,69 @@ AdbInstance::~AdbInstance() { /** * Function: AdbInstance::isLeaf **/ -bool AdbInstance::isLeaf() { +bool AdbInstance::isLeaf() +{ return nodeDesc == NULL; } /** * Function: isUnionisUnion **/ -bool AdbInstance::isUnion() { +bool AdbInstance::isUnion() +{ return isNode() && nodeDesc->isUnion; } /** * Function: AdbInstance::isStruct **/ -bool AdbInstance::isStruct() { +bool AdbInstance::isStruct() +{ return isNode() && !isUnion(); } /** * Function: AdbInstance::isNode **/ -bool AdbInstance::isNode() { +bool AdbInstance::isNode() +{ return !isLeaf(); } /** * Function: AdbInstance::isNode **/ -bool AdbInstance::isPartOfArray() { +bool AdbInstance::isPartOfArray() +{ return fieldDesc->isArray(); } /** * Function: AdbInstance::fullName **/ -string AdbInstance::fullName(int skipLevel) { - list < string > fnList; - AdbInstance *p = parent; +string AdbInstance::fullName(int skipLevel) +{ + list fnList; + AdbInstance* p = parent; fnList.push_front(name); - while (p != NULL) { + while (p != NULL) + { fnList.push_front(p->name); p = p->parent; } - if ((int) fnList.size() > skipLevel) { - while (skipLevel--) { + if ((int)fnList.size() > skipLevel) + { + while (skipLevel--) + { fnList.pop_front(); } return boost::algorithm::join(fnList, "."); - } else { + } + else + { return fnList.back(); } } @@ -140,92 +163,102 @@ string AdbInstance::fullName(int skipLevel) { /** * Function: AdbInstance::fullName **/ -bool AdbInstance::isReserved() { +bool AdbInstance::isReserved() +{ return fieldDesc->isReserved; } /** * Function: AdbInstance::fullName **/ -u_int32_t AdbInstance::dwordAddr() { +u_int32_t AdbInstance::dwordAddr() +{ return (offset >> 5) << 2; } /** * Function: AdbInstance::fullName **/ -u_int32_t AdbInstance::startBit() { +u_int32_t AdbInstance::startBit() +{ return offset % 32; } /** * Function: AdbInstance::operator< **/ -bool AdbInstance::operator<(const AdbInstance& other) { +bool AdbInstance::operator<(const AdbInstance& other) +{ return offset < other.offset; } /** * Function: AdbInstance::getChildByPath **/ -AdbInstance* AdbInstance::getChildByPath(const string &path, - bool isCaseSensitive) { - string effPath = isCaseSensitive ? path : boost::algorithm::to_lower_copy( - path); - if (effPath[0] == '.') { +AdbInstance* AdbInstance::getChildByPath(const string& path, bool isCaseSensitive) +{ + string effPath = isCaseSensitive ? path : boost::algorithm::to_lower_copy(path); + if (effPath[0] == '.') + { effPath.erase(0, 1); } size_t idx = effPath.find("."); string childName = idx == string::npos ? effPath : effPath.substr(0, idx); - string grandChildPath = idx == string::npos ? string() : effPath.substr( - idx + 1); + string grandChildPath = idx == string::npos ? string() : effPath.substr(idx + 1); - if (path.empty()) { + if (path.empty()) + { return this; } // Search for childName - AdbInstance *child = NULL; - for (size_t i = 0; i < subItems.size(); i++) { - string subName = isCaseSensitive ? subItems[i]->name - : boost::algorithm::to_lower_copy(subItems[i]->name); - if (subName == childName) { + AdbInstance* child = NULL; + for (size_t i = 0; i < subItems.size(); i++) + { + string subName = isCaseSensitive ? subItems[i]->name : boost::algorithm::to_lower_copy(subItems[i]->name); + if (subName == childName) + { child = subItems[i]; break; } } - if (!child) { + if (!child) + { return NULL; } // if grandChildPath isn't empty this means we need to continue and find the desired field in grand child node - return grandChildPath.empty() ? child : child->getChildByPath( - grandChildPath, isCaseSensitive); + return grandChildPath.empty() ? child : child->getChildByPath(grandChildPath, isCaseSensitive); } /** * Function: AdbInstance::findChild **/ -vector AdbInstance::findChild(const string& childName, - bool isCaseSensitive, bool by_inst_name) { - string effName = isCaseSensitive ? childName - : boost::algorithm::to_lower_copy(childName); +vector AdbInstance::findChild(const string& childName, bool isCaseSensitive, bool by_inst_name) +{ + string effName = isCaseSensitive ? childName : boost::algorithm::to_lower_copy(childName); vector childList; - if (by_inst_name || isLeaf()) { - if (name == childName) { + if (by_inst_name || isLeaf()) + { + if (name == childName) + { childList.push_back(this); } - } else { - if (isNode() && nodeDesc->name == childName) { + } + else + { + if (isNode() && nodeDesc->name == childName) + { childList.push_back(this); } } // do that recursively for all child items - for (size_t i = 0; i < subItems.size(); i++) { + for (size_t i = 0; i < subItems.size(); i++) + { vector l = subItems[i]->findChild(effName, true); childList.insert(childList.end(), l.begin(), l.end()); } @@ -236,48 +269,53 @@ vector AdbInstance::findChild(const string& childName, /** * Function: AdbInstance::getAttr **/ -string AdbInstance::getInstanceAttr(const string &attrName) const +string AdbInstance::getInstanceAttr(const string& attrName) const { AttrsMap::const_iterator it = instAttrsMap.find(attrName); - if (it == instAttrsMap.end()) { - if (fieldDesc) { + if (it == instAttrsMap.end()) + { + if (fieldDesc) + { it = fieldDesc->attrs.find(attrName); - if (it == fieldDesc->attrs.end()) { + if (it == fieldDesc->attrs.end()) + { return string(); } } - else{ + else + { return string(); } } return it->second; } - /** * Function: AdbInstance::getInstanceAttrIterator **/ -AttrsMap::iterator AdbInstance::getInstanceAttrIterator(const string &attrName, bool &found) +AttrsMap::iterator AdbInstance::getInstanceAttrIterator(const string& attrName, bool& found) { AttrsMap::iterator it = instAttrsMap.find(attrName); found = false; - if (it != instAttrsMap.end()) { + if (it != instAttrsMap.end()) + { found = true; - } - else if (fieldDesc){ + } + else if (fieldDesc) + { it = fieldDesc->attrs.find(attrName); - if (it != fieldDesc->attrs.end()) { - found =true; + if (it != fieldDesc->attrs.end()) + { + found = true; } } return it; } - /** * Function: AdbInstance::setInstanceAttr **/ -void AdbInstance::setInstanceAttr(const string &attrName, const string &attrValue) +void AdbInstance::setInstanceAttr(const string& attrName, const string& attrValue) { instAttrsMap[attrName] = attrValue; } @@ -285,7 +323,7 @@ void AdbInstance::setInstanceAttr(const string &attrName, const string &attrValu /* * Function: AdbInstance::copyAllInstanceAttr - copies all attrs from attributes structure **/ -void AdbInstance::copyAllInstanceAttr(AttrsMap &attsToCopy) +void AdbInstance::copyAllInstanceAttr(AttrsMap& attsToCopy) { instAttrsMap = attsToCopy; } @@ -296,35 +334,37 @@ void AdbInstance::copyAllInstanceAttr(AttrsMap &attsToCopy) AttrsMap AdbInstance::getFullInstanceAttrsMapCopy() { AttrsMap tmpCopy; - // copy first the fields attr map - for (AttrsMap::iterator it = fieldDesc->attrs.begin(); it != fieldDesc->attrs.end(); it++){ + // copy first the fields attr map + for (AttrsMap::iterator it = fieldDesc->attrs.begin(); it != fieldDesc->attrs.end(); it++) + { tmpCopy[it->first] = it->second; } // copy the overriden variables - in instAttrsMap - for (AttrsMap::iterator it = instAttrsMap.begin(); it != instAttrsMap.end(); it++){ + for (AttrsMap::iterator it = instAttrsMap.begin(); it != instAttrsMap.end(); it++) + { tmpCopy[it->first] = it->second; } return tmpCopy; } /** - * Function: AdbInstance::setVarsMap - set an item in vars map + * Function: AdbInstance::setVarsMap - set an item in vars map **/ -void AdbInstance::setVarsMap(const string &attrName, const string &attrValue) +void AdbInstance::setVarsMap(const string& attrName, const string& attrValue) { varsMap[attrName] = attrValue; } /** - * Function: AdbInstance::setVarsMap - set an item in vars map + * Function: AdbInstance::setVarsMap - set an item in vars map **/ -void AdbInstance::setVarsMap(const AttrsMap &AttrsMap) +void AdbInstance::setVarsMap(const AttrsMap& AttrsMap) { varsMap = AttrsMap; } /** - * Function: AdbInstance::setVarsMap - returns a copy of vars map + * Function: AdbInstance::setVarsMap - returns a copy of vars map **/ AttrsMap AdbInstance::getVarsMap() { @@ -334,33 +374,38 @@ AttrsMap AdbInstance::getVarsMap() /** * Function: AdbInstance::isEnumExists **/ -bool AdbInstance::isEnumExists() { +bool AdbInstance::isEnumExists() +{ return !getInstanceAttr("enum").empty(); } /** * Function: AdbInstance::enumToInt **/ -bool AdbInstance::enumToInt(const string &name, u_int64_t &val) { - vector < string > enumValues; +bool AdbInstance::enumToInt(const string& name, u_int64_t& val) +{ + vector enumValues; string enums = getInstanceAttr("enum"); boost::algorithm::split(enumValues, enums, boost::is_any_of(string(","))); - for (size_t i = 0; i < enumValues.size(); i++) { - vector < string > pair; + for (size_t i = 0; i < enumValues.size(); i++) + { + vector pair; string trimedEnumValues = enumValues[i]; boost::algorithm::trim(trimedEnumValues); - boost::algorithm::split(pair, trimedEnumValues, - boost::is_any_of(string("="))); + boost::algorithm::split(pair, trimedEnumValues, boost::is_any_of(string("="))); - if (pair.size() != 2) { + if (pair.size() != 2) + { continue; } - char *end; - if (pair[0] == name) { + char* end; + if (pair[0] == name) + { val = strtoul(pair[1].c_str(), &end, 0); - if (*end != '\0') { + if (*end != '\0') + { return false; } return true; @@ -373,29 +418,33 @@ bool AdbInstance::enumToInt(const string &name, u_int64_t &val) { /** * Function: AdbInstance::intToEnum **/ -bool AdbInstance::intToEnum(u_int64_t val, string &valName) { - vector < string > enumValues; +bool AdbInstance::intToEnum(u_int64_t val, string& valName) +{ + vector enumValues; string enums = getInstanceAttr("enum"); boost::algorithm::split(enumValues, enums, boost::is_any_of(string(","))); - for (size_t i = 0; i < enumValues.size(); i++) { - vector < string > pair; + for (size_t i = 0; i < enumValues.size(); i++) + { + vector pair; string trimedEnumValues = enumValues[i]; boost::algorithm::trim(trimedEnumValues); - boost::algorithm::split(pair, trimedEnumValues, - boost::is_any_of(string("="))); + boost::algorithm::split(pair, trimedEnumValues, boost::is_any_of(string("="))); - if (pair.size() != 2) { + if (pair.size() != 2) + { continue; } - char *end; + char* end; u_int64_t tmp = strtoul(pair[1].c_str(), &end, 0); - if (*end != '\0') { + if (*end != '\0') + { continue; } - if (tmp == val) { + if (tmp == val) + { valName = pair[0]; return true; } @@ -407,30 +456,31 @@ bool AdbInstance::intToEnum(u_int64_t val, string &valName) { /** * Function: AdbInstance::getEnumMap **/ -map AdbInstance::getEnumMap() { - map < string, u_int64_t > enumMap; - vector < string > enumValues; +map AdbInstance::getEnumMap() +{ + map enumMap; + vector enumValues; string enums = getInstanceAttr("enum"); boost::algorithm::split(enumValues, enums, boost::is_any_of(string(","))); - for (size_t i = 0; i < enumValues.size(); i++) { - vector < string > pair; + for (size_t i = 0; i < enumValues.size(); i++) + { + vector pair; string trimedEnumValues = enumValues[i]; boost::algorithm::trim(trimedEnumValues); - boost::algorithm::split(pair, trimedEnumValues, - boost::is_any_of(string("="))); - if (pair.size() != 2) { + boost::algorithm::split(pair, trimedEnumValues, boost::is_any_of(string("="))); + if (pair.size() != 2) + { throw AdbException("Can't parse enum: " + enumValues[i]); - //continue; + // continue; } - char *end; + char* end; u_int64_t intVal = strtoul(pair[1].c_str(), &end, 0); - if (*end != '\0') { - throw AdbException( - string("Can't evaluate enum (") + pair[0].c_str() + "): " - + pair[1].c_str()); - //continue; + if (*end != '\0') + { + throw AdbException(string("Can't evaluate enum (") + pair[0].c_str() + "): " + pair[1].c_str()); + // continue; } enumMap[pair[0]] = intVal; @@ -442,25 +492,28 @@ map AdbInstance::getEnumMap() { /** * Function: AdbInstance::getEnumValues **/ -vector AdbInstance::getEnumValues() { - vector < u_int64_t > values; - vector < string > enumValues; +vector AdbInstance::getEnumValues() +{ + vector values; + vector enumValues; string enums = getInstanceAttr("enum"); boost::algorithm::split(enumValues, enums, boost::is_any_of(string(","))); - for (size_t i = 0; i < enumValues.size(); i++) { - vector < string > pair; + for (size_t i = 0; i < enumValues.size(); i++) + { + vector pair; string trimedEnumValues = enumValues[i]; boost::algorithm::trim(trimedEnumValues); - boost::algorithm::split(pair, trimedEnumValues, - boost::is_any_of(string("="))); - if (pair.size() != 2) { + boost::algorithm::split(pair, trimedEnumValues, boost::is_any_of(string("="))); + if (pair.size() != 2) + { continue; } - char *end; + char* end; u_int64_t intVal = strtoul(pair[1].c_str(), &end, 0); - if (*end != '\0') { + if (*end != '\0') + { continue; } @@ -473,70 +526,76 @@ vector AdbInstance::getEnumValues() { /** * Function: AdbInstance::getUnionSelectedNodeName **/ -AdbInstance* AdbInstance::getUnionSelectedNodeName(const u_int64_t& selectorVal) { - if (!isUnion()) { - throw AdbException( - "This is not union node (%s), can't get selected node name", fullName().c_str()); +AdbInstance* AdbInstance::getUnionSelectedNodeName(const u_int64_t& selectorVal) +{ + if (!isUnion()) + { + throw AdbException("This is not union node (%s), can't get selected node name", fullName().c_str()); } - if (!unionSelector) { + if (!unionSelector) + { throw AdbException("Can't find selector for union: " + name); } - map < string, u_int64_t > selectorValMap = unionSelector->getEnumMap(); - for (map::iterator it = selectorValMap.begin(); - it != selectorValMap.end(); it++) { - if (it->second == selectorVal) { + map selectorValMap = unionSelector->getEnumMap(); + for (map::iterator it = selectorValMap.begin(); it != selectorValMap.end(); it++) + { + if (it->second == selectorVal) + { const string& selectorEnum = it->first; // search for the sub instance with the "selected_by" attribute == selectorEnum - for (size_t i = 0; i < subItems.size(); i++) { - if (subItems[i]->getInstanceAttr("selected_by") == selectorEnum) { + for (size_t i = 0; i < subItems.size(); i++) + { + if (subItems[i]->getInstanceAttr("selected_by") == selectorEnum) + { return subItems[i]; } - } - throw AdbException("Found selector value (" + selectorEnum - + ") is defined for selector field (" - + unionSelector->name - + ") but no appropriate subfield of this union was found"); + throw AdbException("Found selector value (" + selectorEnum + ") is defined for selector field (" + + unionSelector->name + ") but no appropriate subfield of this union was found"); } } - throw AdbException( - "Union selector field (" + unionSelector->name - + ") doesn't define selector value (" - + boost::lexical_cast(selectorVal)); + throw AdbException("Union selector field (" + unionSelector->name + ") doesn't define selector value (" + + boost::lexical_cast(selectorVal)); } /** * Function: AdbInstance::getUnionSelectedNodeName **/ -AdbInstance* AdbInstance::getUnionSelectedNodeName(const string& selectorEnum) { - if (!isUnion()) { - throw AdbException( - "This is not union node (%s), can't get selected node name", fullName().c_str()); +AdbInstance* AdbInstance::getUnionSelectedNodeName(const string& selectorEnum) +{ + if (!isUnion()) + { + throw AdbException("This is not union node (%s), can't get selected node name", fullName().c_str()); } - if (!unionSelector) { + if (!unionSelector) + { throw AdbException("Can't find selector for union: " + name); } - for (size_t i = 0; i < subItems.size(); i++) { - if (subItems[i]->getInstanceAttr("selected_by") == selectorEnum) { + for (size_t i = 0; i < subItems.size(); i++) + { + if (subItems[i]->getInstanceAttr("selected_by") == selectorEnum) + { return subItems[i]; } } - throw AdbException("Union selector field (" + unionSelector->name - + ") doesn't define a selector value (" + selectorEnum + ")"); + throw AdbException("Union selector field (" + unionSelector->name + ") doesn't define a selector value (" + + selectorEnum + ")"); } /** * Function: AdbInstance::isConditionalNode * Throws exception: AdbException **/ -bool AdbInstance::isConditionalNode() { - if (isNode()) { +bool AdbInstance::isConditionalNode() +{ + if (isNode()) + { return (getInstanceAttr("is_conditional") == "1"); } return false; @@ -546,38 +605,43 @@ bool AdbInstance::isConditionalNode() { * Function: AdbInstance::isConditionValid * Throws exception: AdbException **/ -bool AdbInstance::isConditionValid(map *valuesMap) { +bool AdbInstance::isConditionValid(map* valuesMap) +{ u_int64_t res; AdbExpr expressionChecker; int status = -1; - char *condExp; - char *exp; + char* condExp; + char* exp; - if (fieldDesc->condition.empty()) { + if (fieldDesc->condition.empty()) + { return true; } condExp = new char[fieldDesc->condition.size() + 1]; exp = condExp; - if (!exp) { + if (!exp) + { throw AdbException("Memory allocation error"); } strcpy(exp, fieldDesc->condition.c_str()); expressionChecker.setVars(valuesMap); - try { + try + { status = expressionChecker.expr(&exp, &res); - } catch (AdbException &e) { + } + catch (AdbException& e) + { delete[] condExp; throw AdbException(string("AdbException: ") + e.what_s()); } delete[] condExp; - if (status < 0) { - throw AdbException( - string("Error evaluating expression \"") - + fieldDesc->condition.c_str() + "\" : " - + AdbExpr::statusStr(status)); + if (status < 0) + { + throw AdbException(string("Error evaluating expression \"") + fieldDesc->condition.c_str() + + "\" : " + AdbExpr::statusStr(status)); } return (status >= 0 && res != 0); @@ -586,19 +650,28 @@ bool AdbInstance::isConditionValid(map *valuesMap) { /** * Function: AdbInstance::getLeafFields **/ -vector AdbInstance::getLeafFields(bool extendenName) { +vector AdbInstance::getLeafFields(bool extendenName) +{ vector fields; - for (size_t i = 0; i < subItems.size(); i++) { - if (subItems[i]->isNode()) { + for (size_t i = 0; i < subItems.size(); i++) + { + if (subItems[i]->isNode()) + { vector subFields = subItems[i]->getLeafFields(extendenName); fields.insert(fields.end(), subFields.begin(), subFields.end()); - } else { - if (extendenName && !subItems[i]->isNameBeenExtended) { - if (subItems[i]->parent->fieldDesc->subNode == "uint64") { + } + else + { + if (extendenName && !subItems[i]->isNameBeenExtended) + { + if (subItems[i]->parent->fieldDesc->subNode == "uint64") + { subItems[i]->name = subItems[i]->parent->name + "_" + subItems[i]->name; - } else { - subItems[i]->name = subItems[i]->name + addPathSuffixForArraySupport(subItems[i]->fullName()); + } + else + { + subItems[i]->name = subItems[i]->name + addPathSuffixForArraySupport(subItems[i]->fullName()); } subItems[i]->isNameBeenExtended = true; } @@ -612,28 +685,30 @@ vector AdbInstance::getLeafFields(bool extendenName) { /** * Function: AdbInstance::pushBuf **/ -void AdbInstance::pushBuf(u_int8_t *buf, u_int64_t value) { +void AdbInstance::pushBuf(u_int8_t* buf, u_int64_t value) +{ push_to_buf(buf, offset, size, value); } /** * Function: AdbInstance::popBuf **/ -u_int64_t AdbInstance::popBuf(u_int8_t *buf) { +u_int64_t AdbInstance::popBuf(u_int8_t* buf) +{ return pop_from_buf(buf, offset, size); } /** * Function: AdbInstance::print **/ -void AdbInstance::print(int indent) { +void AdbInstance::print(int indent) +{ string indentStr = indentString(indent); - printf( - "%sfullName: %s, offset: 0x%x.%d, size: 0x%x.%d, isNode:%d, isUnion:%d\n", - indentStr.c_str(), fullName().c_str(), (offset >> 5) << 2, - offset % 32, (size >> 5) << 2, size % 32, isNode(), isUnion()); + printf("%sfullName: %s, offset: 0x%x.%d, size: 0x%x.%d, isNode:%d, isUnion:%d\n", indentStr.c_str(), + fullName().c_str(), (offset >> 5) << 2, offset % 32, (size >> 5) << 2, size % 32, isNode(), isUnion()); - if (isNode()) { + if (isNode()) + { for (size_t i = 0; i < subItems.size(); i++) subItems[i]->print(indent + 1); } diff --git a/adb_parser/adb_instance.h b/adb_parser/adb_instance.h index d9ed2922..dc1a7c26 100644 --- a/adb_parser/adb_instance.h +++ b/adb_parser/adb_instance.h @@ -35,8 +35,8 @@ #ifndef ADB_INSTANCE_H #define ADB_INSTANCE_H -\ -#include"adb_xmlCreator.h" + +#include "adb_xmlCreator.h" #include #include #include @@ -44,12 +44,12 @@ using namespace std; using namespace xmlCreator; - typedef map AttrsMap; class AdbField; class AdbNode; -class AdbInstance { +class AdbInstance +{ public: // Methods AdbInstance(); @@ -64,54 +64,53 @@ class AdbInstance { u_int32_t dwordAddr(); u_int32_t startBit(); bool isEnumExists(); - bool enumToInt(const string &name, u_int64_t &val); // false means no enum value found - bool intToEnum(u_int64_t val, string &valName); // false means no enum name found + bool enumToInt(const string& name, u_int64_t& val); // false means no enum value found + bool intToEnum(u_int64_t val, string& valName); // false means no enum name found map getEnumMap(); vector getEnumValues(); AdbInstance* getUnionSelectedNodeName(const u_int64_t& selectorVal); AdbInstance* getUnionSelectedNodeName(const string& selectorEnum); bool operator<(const AdbInstance& other); bool isConditionalNode(); - bool isConditionValid(map *valuesMap); + bool isConditionValid(map* valuesMap); // DB like access methods - AdbInstance - * getChildByPath(const string& path, bool isCaseSensitive = true); - vector findChild(const string& name, - bool isCaseSensitive = true, bool by_inst_name = false); - string getInstanceAttr(const string &attrName) const; - AttrsMap::iterator getInstanceAttrIterator(const string &attrName, bool &isEnd); - void setInstanceAttr(const string &attrName, const string &attrValue); - void copyAllInstanceAttr(AttrsMap &attsToCopy); + AdbInstance* getChildByPath(const string& path, bool isCaseSensitive = true); + vector findChild(const string& name, bool isCaseSensitive = true, bool by_inst_name = false); + string getInstanceAttr(const string& attrName) const; + AttrsMap::iterator getInstanceAttrIterator(const string& attrName, bool& isEnd); + void setInstanceAttr(const string& attrName, const string& attrValue); + void copyAllInstanceAttr(AttrsMap& attsToCopy); AttrsMap getFullInstanceAttrsMapCopy(); - void setVarsMap(const string &attrName, const string &attrValue); - void setVarsMap(const AttrsMap &AttrsMap); + void setVarsMap(const string& attrName, const string& attrValue); + void setVarsMap(const AttrsMap& AttrsMap); AttrsMap getVarsMap(); vector getLeafFields(bool extendedName); // Get all leaf fields - void pushBuf(u_int8_t *buf, u_int64_t value); - u_int64_t popBuf(u_int8_t *buf); - int instAttrsMapLen() {return instAttrsMap.size();} + void pushBuf(u_int8_t* buf, u_int64_t value); + u_int64_t popBuf(u_int8_t* buf); + int instAttrsMapLen() { return instAttrsMap.size(); } // FOR DEBUG void print(int indent = 0); public: // Members - AdbField *fieldDesc; - AdbNode *nodeDesc; - AdbInstance *parent; + AdbField* fieldDesc; + AdbNode* nodeDesc; + AdbInstance* parent; string name; // instance name vector subItems; - u_int32_t offset; // Global offset in bits (Relative to 0) - u_int32_t size; // in bits + u_int32_t offset; // Global offset in bits (Relative to 0) + u_int32_t size; // in bits u_int32_t maxLeafSize; // in bits for DS alignment check u_int32_t arrIdx; - bool isNameBeenExtended; - AdbInstance *unionSelector; // For union instances only + bool isNameBeenExtended; + AdbInstance* unionSelector; // For union instances only bool isDiff; // FOR USER USAGE - void *userData; + void* userData; + private: AttrsMap instAttrsMap; // Attributes after evaluations and array expanding - AttrsMap varsMap; // all variables relevant to this item after evaluation + AttrsMap varsMap; // all variables relevant to this item after evaluation }; #endif diff --git a/adb_parser/adb_logfile.cpp b/adb_parser/adb_logfile.cpp index 8e9a3fe9..e98bdb30 100644 --- a/adb_parser/adb_logfile.cpp +++ b/adb_parser/adb_logfile.cpp @@ -34,36 +34,46 @@ #include "adb_logfile.h" -#define WRITE "w" +#define WRITE "w" -LogFile::LogFile() : _logFile(NULL) { -} +LogFile::LogFile() : _logFile(NULL) {} -void LogFile::init(string logFileName, bool allowMultipleExceptions) { - if (logFileName.compare("") != 0) { +void LogFile::init(string logFileName, bool allowMultipleExceptions) +{ + if (logFileName.compare("") != 0) + { _logFile = fopen(logFileName.c_str(), WRITE); - if (!_logFile) { - string _lastError = "Can't open file (" + logFileName + ") for writing: " - + strerror(errno); - if (allowMultipleExceptions) { + if (!_logFile) + { + string _lastError = "Can't open file (" + logFileName + ") for writing: " + strerror(errno); + if (allowMultipleExceptions) + { ExceptionHolder::insertNewException(ExceptionHolder::FATAL_EXCEPTION, _lastError); - } else { + } + else + { throw AdbException(_lastError); } } - } else { + } + else + { _logFile = NULL; } } -LogFile::~LogFile() { - if (_logFile) { - fclose (_logFile); +LogFile::~LogFile() +{ + if (_logFile) + { + fclose(_logFile); } } -void LogFile::appendLogFile(string str) { - if (_logFile) { +void LogFile::appendLogFile(string str) +{ + if (_logFile) + { fprintf(_logFile, "%s", str.c_str()); } } diff --git a/adb_parser/adb_logfile.h b/adb_parser/adb_logfile.h index caac9bcf..c31197cc 100644 --- a/adb_parser/adb_logfile.h +++ b/adb_parser/adb_logfile.h @@ -45,14 +45,16 @@ using namespace std; -class LogFile { +class LogFile +{ public: LogFile(); void init(string logFileName, bool allowMultipleExceptions); ~LogFile(); void appendLogFile(string adbFileName); + private: - FILE *_logFile; + FILE* _logFile; }; #endif diff --git a/adb_parser/adb_node.cpp b/adb_parser/adb_node.cpp index 176a733f..25f1292a 100644 --- a/adb_parser/adb_node.cpp +++ b/adb_parser/adb_node.cpp @@ -53,9 +53,7 @@ using namespace boost; #include #include -AdbNode::AdbNode() : size(0), _maxLeafSize(0), isUnion(false), inLayout(false), lineNumber(-1), userData(0) -{ -} +AdbNode::AdbNode() : size(0), _maxLeafSize(0), isUnion(false), inLayout(false), lineNumber(-1), userData(0) {} /** * * Function: AdbNode::~AdbNode @@ -77,7 +75,7 @@ AdbNode::~AdbNode() /** * * Function: AdbNode::toXml * **/ -string AdbNode::toXml(const string &addPrefix) +string AdbNode::toXml(const string& addPrefix) { string xml = " AttrsMap; -typedef vector FieldsList; +typedef vector FieldsList; class AdbNode { public: // Methods AdbNode(); ~AdbNode(); - string toXml(const string &addPrefix); + string toXml(const string& addPrefix); // FOR DEBUG void print(int indent = 0); @@ -62,7 +62,7 @@ class AdbNode public: // Members string name; - u_int32_t size; // in bits + u_int32_t size; // in bits u_int32_t _maxLeafSize; // in bits bool isUnion; string desc; @@ -76,7 +76,7 @@ class AdbNode int lineNumber; // FOR USER USAGE - void *userData; + void* userData; }; #endif diff --git a/adb_parser/adb_parser.cpp b/adb_parser/adb_parser.cpp old mode 100755 new mode 100644 index 04f40689..49357a12 --- a/adb_parser/adb_parser.cpp +++ b/adb_parser/adb_parser.cpp @@ -46,7 +46,6 @@ #include #include - #if __cplusplus >= 201402L #include #else @@ -56,25 +55,30 @@ using namespace boost; using namespace xmlCreator; -class AdbParser { +class AdbParser +{ public: // METHODS - AdbParser(string fileName, Adb *adbCtxt, bool addReserved = false, - bool strict = true, - string includePath = "", bool enforceExtraChecks = false, bool checkDsAlign = false, bool enforceGuiChecks = false); + AdbParser(string fileName, + Adb* adbCtxt, + bool addReserved = false, + bool strict = true, + string includePath = "", + bool enforceExtraChecks = false, + bool checkDsAlign = false, + bool enforceGuiChecks = false); ~AdbParser(); bool load(); - bool loadFromString(const char *adbString); + bool loadFromString(const char* adbString); string getError(); static string descXmlToNative(const string& desc); static string descNativeToXml(const string& desc); - static void includeAllFilesInDir(AdbParser *adbParser, string dirPath, - int lineNumber = -1); + static void includeAllFilesInDir(AdbParser* adbParser, string dirPath, int lineNumber = -1); static bool checkSpecialChars(string tagName); static bool checkBigger32(string num); static bool checkHEXFormat(string addr); - static bool checkAttrExist(const XML_Char **atts, const XML_Char *name); + static bool checkAttrExist(const XML_Char** atts, const XML_Char* name); static void setAllowMultipleExceptionsTrue(); public: @@ -83,35 +87,34 @@ class AdbParser { private: // METHODS string findFile(string fileName); - static void addIncludePaths(Adb *adbCtxt, string includePaths); - static void includeFile(AdbParser *adbParser, string fileName, int lineNumber = -1); - static void startElement(void *adbParser, const XML_Char *name, const XML_Char **atts); - - static void startNodesDefElement(const XML_Char **atts, AdbParser *adbParser); - static void startEnumElement(const XML_Char **atts, AdbParser *adbParser, const int lineNumber); - static void startConfigElement(const XML_Char **atts, AdbParser *adbParser, const int lineNumber); - static void startInfoElement(const XML_Char **atts, AdbParser *adbParser); - static void startIncludeElement(const XML_Char **atts, AdbParser *adbParser, const int lineNumber); - static void startInstOpAttrReplaceElement(const XML_Char **atts, AdbParser *adbParser, const int lineNumber); - static void startNodeElement(const XML_Char **atts, AdbParser *adbParser, const int lineNumber); - static void startFieldElement(const XML_Char **atts, AdbParser *adbParser, const int lineNumber); - - static void endElement(void *adbParser, const XML_Char *name); - static void addReserved(vector &reserveds, u_int32_t offset, u_int32_t size); - static int attrCount(const XML_Char **atts); - static string attrValue(const XML_Char **atts, const XML_Char *attrName); - static string attrName(const XML_Char **atts, int i); - static string attrValue(const XML_Char **atts, int i); - static bool is_inst_ifdef_exist_and_correct_project(const XML_Char **atts, AdbParser *adbParser); + static void addIncludePaths(Adb* adbCtxt, string includePaths); + static void includeFile(AdbParser* adbParser, string fileName, int lineNumber = -1); + static void startElement(void* adbParser, const XML_Char* name, const XML_Char** atts); + + static void startNodesDefElement(const XML_Char** atts, AdbParser* adbParser); + static void startEnumElement(const XML_Char** atts, AdbParser* adbParser, const int lineNumber); + static void startConfigElement(const XML_Char** atts, AdbParser* adbParser, const int lineNumber); + static void startInfoElement(const XML_Char** atts, AdbParser* adbParser); + static void startIncludeElement(const XML_Char** atts, AdbParser* adbParser, const int lineNumber); + static void startInstOpAttrReplaceElement(const XML_Char** atts, AdbParser* adbParser, const int lineNumber); + static void startNodeElement(const XML_Char** atts, AdbParser* adbParser, const int lineNumber); + static void startFieldElement(const XML_Char** atts, AdbParser* adbParser, const int lineNumber); + + static void endElement(void* adbParser, const XML_Char* name); + static void addReserved(vector& reserveds, u_int32_t offset, u_int32_t size); + static int attrCount(const XML_Char** atts); + static string attrValue(const XML_Char** atts, const XML_Char* attrName); + static string attrName(const XML_Char** atts, int i); + static string attrValue(const XML_Char** atts, int i); + static bool is_inst_ifdef_exist_and_correct_project(const XML_Char** atts, AdbParser* adbParser); static u_int32_t addr2int(string& s); static u_int32_t dword(u_int32_t offset); static u_int32_t startBit(u_int32_t offset); - static bool raiseException(bool allowMultipleExceptions, string exceptionTxt, - string addedMsg, const string expType); + static bool raiseException(bool allowMultipleExceptions, string exceptionTxt, string addedMsg, const string expType); private: // MEMBERS - Adb *_adbCtxt; + Adb* _adbCtxt; XML_Parser _xmlParser; string _fileName; string _lastError; @@ -122,9 +125,9 @@ class AdbParser { bool skipNode; string _includePath; string _currentTagValue; - AdbNode *_currentNode; - AdbField *_currentField; - AdbConfig *_currentConfig; + AdbNode* _currentNode; + AdbField* _currentField; + AdbConfig* _currentConfig; bool _instanceOps; bool _enforceExtraChecks; bool _enforceGuiChecks; @@ -179,12 +182,28 @@ const string AdbParser::TAG_ATTR_DEFINE_PATTERN = "([A-Za-z_]\\w*)=(\\w+)"; /** * Function: AdbParser::AdbParser **/ -AdbParser::AdbParser(string fileName, Adb *adbCtxt, bool addReserved, - bool strict, string includePath, - bool enforceExtraChecks, bool _checkDsAlign, bool _enforceGuiChecks) : _adbCtxt(adbCtxt), _fileName(fileName), _addReserved(addReserved), - _progressCnt(0), _strict(strict), _checkDsAlign(_checkDsAlign), - skipNode(false),_includePath(includePath), _currentNode(0), _currentField(0), _currentConfig(0), - _enforceGuiChecks(_enforceGuiChecks), _nname_pattern(".*"), _fname_pattern(".*") +AdbParser::AdbParser(string fileName, + Adb* adbCtxt, + bool addReserved, + bool strict, + string includePath, + bool enforceExtraChecks, + bool _checkDsAlign, + bool _enforceGuiChecks) : + _adbCtxt(adbCtxt), + _fileName(fileName), + _addReserved(addReserved), + _progressCnt(0), + _strict(strict), + _checkDsAlign(_checkDsAlign), + skipNode(false), + _includePath(includePath), + _currentNode(0), + _currentField(0), + _currentConfig(0), + _enforceGuiChecks(_enforceGuiChecks), + _nname_pattern(".*"), + _fname_pattern(".*") { _enforceExtraChecks = enforceExtraChecks; @@ -212,29 +231,23 @@ AdbParser::AdbParser(string fileName, Adb *adbCtxt, bool addReserved, { // first add the opened project path adbCtxt->includePaths.push_back( - _fileName.find(OS_PATH_SEP) == string::npos ? "." - : _fileName.substr(0, _fileName.rfind(OS_PATH_SEP))); + _fileName.find(OS_PATH_SEP) == string::npos ? "." : _fileName.substr(0, _fileName.rfind(OS_PATH_SEP))); vector path; - boost::algorithm::split(path, fileName, - boost::is_any_of(string(OS_PATH_SEP))); + boost::algorithm::split(path, fileName, boost::is_any_of(string(OS_PATH_SEP))); IncludeFileInfo info = {fileName, "ROOT", 0}; _adbCtxt->includedFiles[path[path.size() - 1]] = info; } _instanceOps = false; } -void AdbParser::addIncludePaths(Adb *adbCtxt, string includePaths) +void AdbParser::addIncludePaths(Adb* adbCtxt, string includePaths) { vector paths; - boost::algorithm::split(paths, includePaths, - boost::is_any_of(string(";"))); - adbCtxt->includePaths.insert(adbCtxt->includePaths.end(), - paths.begin(), paths.end()); + boost::algorithm::split(paths, includePaths, boost::is_any_of(string(";"))); + adbCtxt->includePaths.insert(adbCtxt->includePaths.end(), paths.begin(), paths.end()); StringVector relatives; - string - projPath = - boost::filesystem::path(adbCtxt->mainFileName).parent_path().string(); + string projPath = boost::filesystem::path(adbCtxt->mainFileName).parent_path().string(); for (StringVector::iterator it = adbCtxt->includePaths.begin(); it != adbCtxt->includePaths.end(); it++) { @@ -244,8 +257,7 @@ void AdbParser::addIncludePaths(Adb *adbCtxt, string includePaths) } } - adbCtxt->includePaths.insert(adbCtxt->includePaths.end(), - relatives.begin(), relatives.end()); + adbCtxt->includePaths.insert(adbCtxt->includePaths.end(), relatives.begin(), relatives.end()); } /** @@ -270,8 +282,8 @@ void AdbParser::setAllowMultipleExceptionsTrue() **/ bool AdbParser::load() { - FILE *file; - char *data = NULL; + FILE* file; + char* data = NULL; file = fopen(_fileName.c_str(), "r"); _adbCtxt->_logFile->appendLogFile("Opening " + _fileName + "\n"); @@ -308,7 +320,7 @@ bool AdbParser::load() return false; } - data = (char *)malloc(fSize + 1); + data = (char*)malloc(fSize + 1); if (!data) { fclose(file); @@ -316,7 +328,7 @@ bool AdbParser::load() } if (fseek(file, 0L, SEEK_SET) < 0) - { //go back to the start of the file + { // go back to the start of the file _lastError = "Failed to read file (" + _fileName + "): " + strerror(errno); fclose(file); free(data); @@ -351,17 +363,17 @@ bool AdbParser::load() if (!XML_Parse(_xmlParser, data, strlen(data), 0)) { enum XML_Error errNo = XML_GetErrorCode(_xmlParser); - throw AdbException( - string("XML parsing issues: ") + XML_ErrorString(errNo)); + throw AdbException(string("XML parsing issues: ") + XML_ErrorString(errNo)); } } - catch (AdbException &exp) + catch (AdbException& exp) { if (exp.what_s().find("in file:") == string::npos) { int line = XML_GetCurrentLineNumber(_xmlParser); int column = XML_GetCurrentColumnNumber(_xmlParser); - _lastError = exp.what_s() + " in file: " + _fileName + " at line: " + boost::lexical_cast(line) + " column: " + boost::lexical_cast(column); + _lastError = exp.what_s() + " in file: " + _fileName + " at line: " + boost::lexical_cast(line) + + " column: " + boost::lexical_cast(column); } else { @@ -378,7 +390,7 @@ bool AdbParser::load() return false; } } - catch (std::runtime_error &e) + catch (std::runtime_error& e) { _lastError = CHECK_RUNTIME_ERROR(e); if (allowMultipleExceptions) @@ -396,9 +408,9 @@ bool AdbParser::load() { int line = XML_GetCurrentLineNumber(_xmlParser); int column = XML_GetCurrentColumnNumber(_xmlParser); - _lastError = string( - "An exception raised during the loading of the file: ") + - _fileName + " at line: " + boost::lexical_cast(line) + " column: " + boost::lexical_cast(column); + _lastError = string("An exception raised during the loading of the file: ") + _fileName + + " at line: " + boost::lexical_cast(line) + + " column: " + boost::lexical_cast(column); if (allowMultipleExceptions) { xmlStatus = false; @@ -418,7 +430,7 @@ bool AdbParser::load() /** * Function: AdbParser::loadFromString **/ -bool AdbParser::loadFromString(const char *adbString) +bool AdbParser::loadFromString(const char* adbString) { _fileName = "\"STRING\""; try @@ -426,29 +438,28 @@ bool AdbParser::loadFromString(const char *adbString) if (!XML_Parse(_xmlParser, adbString, strlen(adbString), 0)) { enum XML_Error errNo = XML_GetErrorCode(_xmlParser); - throw AdbException( - string("XML parsing issues: ") + XML_ErrorString(errNo)); + throw AdbException(string("XML parsing issues: ") + XML_ErrorString(errNo)); } } - catch (AdbException &exp) + catch (AdbException& exp) { if (exp.what_s().find("in file:") == string::npos) { int line = XML_GetCurrentLineNumber(_xmlParser); int column = XML_GetCurrentColumnNumber(_xmlParser); - _lastError = exp.what_s() + " in file: " + _fileName + " at line: " + boost::lexical_cast(line) + " column: " + boost::lexical_cast(column); + _lastError = exp.what_s() + " in file: " + _fileName + " at line: " + boost::lexical_cast(line) + + " column: " + boost::lexical_cast(column); } else { _lastError = exp.what_s(); } - _lastError += string( - "\nNOTE: this project is configured to work with: \"") + + _lastError += string("\nNOTE: this project is configured to work with: \"") + (_adbCtxt->bigEndianArr ? "Big" : "Little") + " Endian Arrays\""; return false; } - catch (std::runtime_error &e) + catch (std::runtime_error& e) { _lastError = CHECK_RUNTIME_ERROR(e); return false; @@ -457,9 +468,9 @@ bool AdbParser::loadFromString(const char *adbString) { int line = XML_GetCurrentLineNumber(_xmlParser); int column = XML_GetCurrentColumnNumber(_xmlParser); - _lastError = string( - "An exception raised during the loading of the file: ") + - _fileName + " at line: " + boost::lexical_cast(line) + " column: " + boost::lexical_cast(column); + _lastError = string("An exception raised during the loading of the file: ") + _fileName + + " at line: " + boost::lexical_cast(line) + + " column: " + boost::lexical_cast(column); return false; } @@ -477,7 +488,7 @@ string AdbParser::getError() /** * Function: AdbParser::attrsCount **/ -int AdbParser::attrCount(const XML_Char **atts) +int AdbParser::attrCount(const XML_Char** atts) { int i = 0; while (atts[i]) @@ -490,7 +501,7 @@ int AdbParser::attrCount(const XML_Char **atts) /** * Function: AdbParser::attrValue **/ -string AdbParser::attrValue(const XML_Char **atts, const XML_Char *attrName) +string AdbParser::attrValue(const XML_Char** atts, const XML_Char* attrName) { int i = 0; while (atts[i]) @@ -508,10 +519,10 @@ string AdbParser::attrValue(const XML_Char **atts, const XML_Char *attrName) /** * Function: AdbParser::checkAttrExist */ -bool AdbParser::checkAttrExist(const XML_Char **atts, const XML_Char *attrName) +bool AdbParser::checkAttrExist(const XML_Char** atts, const XML_Char* attrName) { int i = 0; - while(atts[i]) + while (atts[i]) { if (!strcmp(atts[i], attrName)) { @@ -525,7 +536,7 @@ bool AdbParser::checkAttrExist(const XML_Char **atts, const XML_Char *attrName) /** * Function: AdbParser::attrName **/ -string AdbParser::attrName(const XML_Char **atts, int i) +string AdbParser::attrName(const XML_Char** atts, int i) { return string(atts[i * 2]); } @@ -533,7 +544,7 @@ string AdbParser::attrName(const XML_Char **atts, int i) /** * Function: AdbParser::attrName **/ -string AdbParser::attrValue(const XML_Char **atts, int i) +string AdbParser::attrValue(const XML_Char** atts, int i) { return string(atts[i * 2 + 1]); } @@ -543,7 +554,7 @@ string AdbParser::attrValue(const XML_Char **atts, int i) **/ string AdbParser::findFile(string fileName) { - FILE *f; + FILE* f; for (size_t i = 0; i < _adbCtxt->includePaths.size(); i++) { @@ -570,13 +581,13 @@ string AdbParser::findFile(string fileName) /** * Function: AdbParser::addr2int **/ -u_int32_t AdbParser::addr2int(string &s) +u_int32_t AdbParser::addr2int(string& s) { try { u_int32_t res; boost::algorithm::to_lower(s); - char *end; + char* end; vector words; boost::algorithm::split(words, s, boost::is_any_of(string("."))); @@ -588,53 +599,52 @@ u_int32_t AdbParser::addr2int(string &s) switch (words.size()) { - case 1: - res = strtoul(words[0].c_str(), &end, 0); - if (*end != '\0') - { - throw AdbException(); - } - - res *= 8; - break; - - case 2: - if (words[0].empty()) - { - // .DDD form - res = strtoul(words[1].c_str(), &end, 0); - if (*end != '\0') - { - throw AdbException(); - } - } - else - { - // 0xHHHHH.DDD or DDDDD.DDD form + case 1: res = strtoul(words[0].c_str(), &end, 0); if (*end != '\0') { throw AdbException(); } + res *= 8; - res += strtoul(words[1].c_str(), &end, 0); - if (*end != '\0') + break; + + case 2: + if (words[0].empty()) { - throw AdbException(); + // .DDD form + res = strtoul(words[1].c_str(), &end, 0); + if (*end != '\0') + { + throw AdbException(); + } } - } - break; + else + { + // 0xHHHHH.DDD or DDDDD.DDD form + res = strtoul(words[0].c_str(), &end, 0); + if (*end != '\0') + { + throw AdbException(); + } + res *= 8; + res += strtoul(words[1].c_str(), &end, 0); + if (*end != '\0') + { + throw AdbException(); + } + } + break; - default: - throw AdbException("Invalid size: " + s); + default: + throw AdbException("Invalid size: " + s); } return res; } - catch (AdbException &exp) + catch (AdbException& exp) { - throw AdbException( - "Failed to retrieve integer from string: " + exp.what_s()); + throw AdbException("Failed to retrieve integer from string: " + exp.what_s()); } } @@ -657,13 +667,12 @@ u_int32_t AdbParser::startBit(u_int32_t offset) /** * Function: AdbParser::descXmlToNative **/ -string AdbParser::descXmlToNative(const string &desc) +string AdbParser::descXmlToNative(const string& desc) { return boost::replace_all_copy(desc, "\\;", "\n"); } - -bool AdbParser::is_inst_ifdef_exist_and_correct_project(const XML_Char **atts, AdbParser *adbParser) +bool AdbParser::is_inst_ifdef_exist_and_correct_project(const XML_Char** atts, AdbParser* adbParser) { bool cond = true; string definedProject = attrValue(atts, "inst_ifdef"); @@ -672,13 +681,11 @@ bool AdbParser::is_inst_ifdef_exist_and_correct_project(const XML_Char **atts, A bool found = false; for (size_t i = 0; i < adbParser->_adbCtxt->configs.size(); i++) { - AttrsMap::iterator it_def = - adbParser->_adbCtxt->configs[i]->attrs.find("define"); + AttrsMap::iterator it_def = adbParser->_adbCtxt->configs[i]->attrs.find("define"); if (it_def != adbParser->_adbCtxt->configs[i]->attrs.end()) { vector defVal; - boost::algorithm::split(defVal, it_def->second, - boost::is_any_of(string("="))); + boost::algorithm::split(defVal, it_def->second, boost::is_any_of(string("="))); if (defVal[0] == definedProject) { @@ -699,12 +706,11 @@ bool AdbParser::is_inst_ifdef_exist_and_correct_project(const XML_Char **atts, A /** * Function: AdbParser::includeFile **/ -void AdbParser::includeFile(AdbParser *adbParser, string fileName, - int lineNumber) +void AdbParser::includeFile(AdbParser* adbParser, string fileName, int lineNumber) { // add this file to the included files map string filePath; - FILE *probeFile = NULL; + FILE* probeFile = NULL; if (!boost::filesystem::path(fileName).is_relative()) { @@ -735,9 +741,8 @@ void AdbParser::includeFile(AdbParser *adbParser, string fileName, adbParser->_adbCtxt->includedFiles[fileName] = info; // parse the included file - AdbParser p(filePath, adbParser->_adbCtxt, adbParser->_addReserved, - adbParser->_strict, - "", adbParser->_enforceExtraChecks); + AdbParser p(filePath, adbParser->_adbCtxt, adbParser->_addReserved, adbParser->_strict, "", + adbParser->_enforceExtraChecks); if (!p.load()) { throw AdbException(p.getError()); @@ -748,15 +753,14 @@ void AdbParser::includeFile(AdbParser *adbParser, string fileName, /** * Function: AdbParser::includeAllFilesInDir **/ -void AdbParser::includeAllFilesInDir(AdbParser *adbParser, string dirPath, - int lineNumber) +void AdbParser::includeAllFilesInDir(AdbParser* adbParser, string dirPath, int lineNumber) { vector paths; boost::filesystem::path mainFile(adbParser->_fileName); boost::algorithm::split(paths, dirPath, boost::is_any_of(string(";"))); for (StringVector::iterator pathIt = paths.begin(); pathIt != paths.end(); pathIt++) { - //first look in the main file's path + // first look in the main file's path boost::filesystem::path fsPath(mainFile.parent_path().string() + "/" + *pathIt); if (!boost::filesystem::exists(fsPath)) { @@ -773,10 +777,9 @@ void AdbParser::includeAllFilesInDir(AdbParser *adbParser, string dirPath, { try { - includeFile(adbParser, filesIter->path().string(), - lineNumber); + includeFile(adbParser, filesIter->path().string(), lineNumber); } - catch (AdbException &e) + catch (AdbException& e) { throw(e); } @@ -843,7 +846,7 @@ bool AdbParser::checkBigger32(string num) return false; } -void AdbParser::startNodesDefElement(const XML_Char **atts, AdbParser *adbParser) +void AdbParser::startNodesDefElement(const XML_Char** atts, AdbParser* adbParser) { if (adbParser->_adbCtxt->version == "") { @@ -852,7 +855,8 @@ void AdbParser::startNodesDefElement(const XML_Char **atts, AdbParser *adbParser string adbVersion = attrValue(atts, 0); if (adbVersion != "1" && adbVersion != "1.0" && adbVersion != "2") { - throw AdbException("Requested Adb Version (%s) is not supported. Supporting only version 1 or 2", adbVersion.c_str()); + throw AdbException("Requested Adb Version (%s) is not supported. Supporting only version 1 or 2", + adbVersion.c_str()); } if (adbVersion == "1.0") { @@ -874,17 +878,17 @@ void AdbParser::startNodesDefElement(const XML_Char **atts, AdbParser *adbParser } } -void AdbParser::startEnumElement(const XML_Char **atts, AdbParser *adbParser, const int lineNumber) +void AdbParser::startEnumElement(const XML_Char** atts, AdbParser* adbParser, const int lineNumber) { bool expFound = false; - if (!adbParser->_currentConfig || - !adbParser->_currentConfig->attrs.count("type") || + if (!adbParser->_currentConfig || !adbParser->_currentConfig->attrs.count("type") || TAG_ATTR_ENUM.compare(adbParser->_currentConfig->attrs["type"])) { - expFound = raiseException(allowMultipleExceptions, - "\"enum\" tag must be inside relevant \"config\" tag", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::ERROR_EXCEPTION); + expFound = + raiseException(allowMultipleExceptions, + "\"enum\" tag must be inside relevant \"config\" tag", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::ERROR_EXCEPTION); } string tagName = attrValue(atts, "name"); @@ -893,18 +897,20 @@ void AdbParser::startEnumElement(const XML_Char **atts, AdbParser *adbParser, co { if (!AdbParser::checkSpecialChars(tagName)) { - expFound = raiseException(allowMultipleExceptions, - "Invalid character in enum name, in enum: \"" + tagName + "\"", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::WARN_EXCEPTION); + expFound = raiseException( + allowMultipleExceptions, + "Invalid character in enum name, in enum: \"" + tagName + "\"", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::WARN_EXCEPTION); } } if (tagName.empty() || value.empty()) { - expFound = raiseException(allowMultipleExceptions, - "Both \"name\" and \"value\" attributes must be specified", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::ERROR_EXCEPTION); + expFound = + raiseException(allowMultipleExceptions, + "Both \"name\" and \"value\" attributes must be specified", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::ERROR_EXCEPTION); } if (!expFound) { @@ -912,15 +918,16 @@ void AdbParser::startEnumElement(const XML_Char **atts, AdbParser *adbParser, co } } -void AdbParser::startConfigElement(const XML_Char **atts, AdbParser *adbParser, const int lineNumber) +void AdbParser::startConfigElement(const XML_Char** atts, AdbParser* adbParser, const int lineNumber) { bool expFound = false; if (adbParser->_currentConfig) { - expFound = raiseException(allowMultipleExceptions, - "config tag can't appear within other config", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::FATAL_EXCEPTION); + expFound = + raiseException(allowMultipleExceptions, + "config tag can't appear within other config", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::FATAL_EXCEPTION); } adbParser->_currentConfig = new AdbConfig; @@ -929,42 +936,44 @@ void AdbParser::startConfigElement(const XML_Char **atts, AdbParser *adbParser, // First add this config to context string aName = attrName(atts, i); string aValue = attrValue(atts, i); - adbParser->_currentConfig->attrs.insert( - pair(aName, aValue)); + adbParser->_currentConfig->attrs.insert(pair(aName, aValue)); // checks that was imported from the gui-parser - if(adbParser->_enforceGuiChecks) + if (adbParser->_enforceGuiChecks) { // check if the attribute is mandatory - if(!aName.compare("field_mand")) + if (!aName.compare("field_mand")) { aValue = regex_replace(aValue, regex("\\s+"), ""); boost::split(adbParser->field_mand_attr, aValue, boost::is_any_of(",")); } // check the define statement is according to format - else if(!aName.compare("define")) + else if (!aName.compare("define")) { smatch result; regex pattern(TAG_ATTR_DEFINE_PATTERN); - if(!regex_match(aValue, result, pattern)) + if (!regex_match(aValue, result, pattern)) { - expFound = raiseException(allowMultipleExceptions, - string("Bad define format: \"") + aName + "\" attribute value: \"" + aValue + "\"", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::ERROR_EXCEPTION); + expFound = raiseException( + allowMultipleExceptions, + string("Bad define format: \"") + aName + "\" attribute value: \"" + aValue + "\"", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::ERROR_EXCEPTION); } else { // check for define duplication string define_key = result[1], define_value = result[2]; - if(adbParser->defines_map.find(define_key) != adbParser->defines_map.end()) + if (adbParser->defines_map.find(define_key) != adbParser->defines_map.end()) { expFound = raiseException(allowMultipleExceptions, - string("Multiple definition of preprocessor variable: \"") + define_key + "\" attribute name: \"" + aName + "\"", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::ERROR_EXCEPTION); + string("Multiple definition of preprocessor variable: \"") + + define_key + "\" attribute name: \"" + aName + "\"", + ", in file: \"" + adbParser->_fileName + + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::ERROR_EXCEPTION); } else { @@ -973,15 +982,16 @@ void AdbParser::startConfigElement(const XML_Char **atts, AdbParser *adbParser, } } - else if(!expFound && !aName.compare("field_attr")) + else if (!expFound && !aName.compare("field_attr")) { // check that the field_attr is unique - if(adbParser->field_attr_names_set.find(aValue) != adbParser->field_attr_names_set.end()) + if (adbParser->field_attr_names_set.find(aValue) != adbParser->field_attr_names_set.end()) { - expFound = raiseException(allowMultipleExceptions, - string("Redefinition of field_attr: \"") + aName + "\" attribute name: \"" + aValue + "\"", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::ERROR_EXCEPTION); + expFound = raiseException( + allowMultipleExceptions, + string("Redefinition of field_attr: \"") + aName + "\" attribute name: \"" + aValue + "\"", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::ERROR_EXCEPTION); } else { @@ -991,38 +1001,43 @@ void AdbParser::startConfigElement(const XML_Char **atts, AdbParser *adbParser, string attr_type = attrValue(atts, "type"); // check that attr 'type' was provided and not empty - if(attr_type.empty()) + if (attr_type.empty()) { - expFound = raiseException(allowMultipleExceptions, - string("field_attr type must be specified: \"") + aName + "\" attribute value: \"" + aValue + "\"", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::ERROR_EXCEPTION); + expFound = raiseException( + allowMultipleExceptions, + string("field_attr type must be specified: \"") + aName + "\" attribute value: \"" + aValue + "\"", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::ERROR_EXCEPTION); } else { // check that type 'multival' has a 'fw_label' value - if(!attr_type.compare("multival") && aValue.compare("fw_label")) + if (!attr_type.compare("multival") && aValue.compare("fw_label")) { - expFound = raiseException(allowMultipleExceptions, - string("Type \"multival\" is supported only for \"fw_label\" not for: \"") + aName + "\" attribute value: \"" + aValue + "\"", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::ERROR_EXCEPTION); + expFound = + raiseException(allowMultipleExceptions, + string("Type \"multival\" is supported only for \"fw_label\" not for: \"") + + aName + "\" attribute value: \"" + aValue + "\"", + ", in file: \"" + adbParser->_fileName + + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::ERROR_EXCEPTION); } } string attr_used_for = attrValue(atts, "used_for"); // check that attr 'used_for' was not provided empty - if(checkAttrExist(atts, "used_for") && attr_used_for.empty()) + if (checkAttrExist(atts, "used_for") && attr_used_for.empty()) { - expFound = raiseException(allowMultipleExceptions, - string("used_for is invalid: \"") + aName + "\" attribute value: \"" + aValue + "\"", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::ERROR_EXCEPTION); + expFound = raiseException( + allowMultipleExceptions, + string("used_for is invalid: \"") + aName + "\" attribute value: \"" + aValue + "\"", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::ERROR_EXCEPTION); } // check if 'pattern' was provided - if(checkAttrExist(atts, "pattern")) + if (checkAttrExist(atts, "pattern")) { // check if the given pattern is a valid reg expression. try @@ -1031,19 +1046,20 @@ void AdbParser::startConfigElement(const XML_Char **atts, AdbParser *adbParser, regex r(pattern_value); adbParser->attr_pattern.insert(pair(aValue, pattern_value)); } - catch(...) + catch (...) { - expFound = raiseException( - allowMultipleExceptions, - string("Bad attribute pattern: \"") + aValue + "\" name Pattern: \"" + attrValue(atts, "pattern") + "\"", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::ERROR_EXCEPTION); + expFound = raiseException(allowMultipleExceptions, + string("Bad attribute pattern: \"") + aValue + "\" name Pattern: \"" + + attrValue(atts, "pattern") + "\"", + ", in file: \"" + adbParser->_fileName + + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::ERROR_EXCEPTION); } } } // check if nname_pattern was provided - else if(!expFound && checkAttrExist(atts, "nname_pattern")) + else if (!expFound && checkAttrExist(atts, "nname_pattern")) { // check if the given pattern is a valid reg expression. try @@ -1052,18 +1068,19 @@ void AdbParser::startConfigElement(const XML_Char **atts, AdbParser *adbParser, regex r(nname_pattern); adbParser->_nname_pattern = nname_pattern; } - catch(...) + catch (...) { expFound = raiseException( allowMultipleExceptions, - string("Bad node name pattern: \"") + aValue + "\" pattern: \"" + attrValue(atts, "nname_pattern") + "\"", + string("Bad node name pattern: \"") + aValue + "\" pattern: \"" + + attrValue(atts, "nname_pattern") + "\"", ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), ExceptionHolder::ERROR_EXCEPTION); } } // check if fname_pattern was provided and the name of the field is compatible with that pattern - else if(!expFound && checkAttrExist(atts, "fname_pattern")) + else if (!expFound && checkAttrExist(atts, "fname_pattern")) { // check if the given pattern is a valid reg expression. try @@ -1072,12 +1089,12 @@ void AdbParser::startConfigElement(const XML_Char **atts, AdbParser *adbParser, regex r(fname_pattern); adbParser->_fname_pattern = fname_pattern; } - catch(...) + catch (...) { expFound = raiseException( allowMultipleExceptions, - string("Bad field name pattern: \"") + aValue + "\" pattern: \"" + attrValue(atts, "fname_pattern") + - "\"", + string("Bad field name pattern: \"") + aValue + "\" pattern: \"" + + attrValue(atts, "fname_pattern") + "\"", ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), ExceptionHolder::ERROR_EXCEPTION); } @@ -1092,12 +1109,13 @@ void AdbParser::startConfigElement(const XML_Char **atts, AdbParser *adbParser, int val = boost::lexical_cast(aValue); adbParser->_adbCtxt->bigEndianArr = val != 0; } - catch (std::exception &) + catch (std::exception&) { - expFound = raiseException(allowMultipleExceptions, - string("Filed to parse the \"") + aName + "\" attribute value: \"" + aValue + "\"", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::ERROR_EXCEPTION); + expFound = raiseException( + allowMultipleExceptions, + string("Filed to parse the \"") + aName + "\" attribute value: \"" + aValue + "\"", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::ERROR_EXCEPTION); } } @@ -1108,12 +1126,13 @@ void AdbParser::startConfigElement(const XML_Char **atts, AdbParser *adbParser, int val = boost::lexical_cast(aValue); adbParser->_adbCtxt->singleEntryArrSupp = val != 0; } - catch (std::exception &) + catch (std::exception&) { - expFound = raiseException(allowMultipleExceptions, - string("Filed to parse the \"") + aName + "\" attribute value: \"" + aValue + "\"", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::ERROR_EXCEPTION); + expFound = raiseException( + allowMultipleExceptions, + string("Filed to parse the \"") + aName + "\" attribute value: \"" + aValue + "\"", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::ERROR_EXCEPTION); } } @@ -1121,19 +1140,15 @@ void AdbParser::startConfigElement(const XML_Char **atts, AdbParser *adbParser, { vector paths; boost::algorithm::split(paths, aValue, boost::is_any_of(string(";"))); - adbParser->_adbCtxt->includePaths.insert(adbParser->_adbCtxt->includePaths.end(), - paths.begin(), paths.end()); + adbParser->_adbCtxt->includePaths.insert(adbParser->_adbCtxt->includePaths.end(), paths.begin(), + paths.end()); StringVector relatives; - string - projPath = boost::filesystem::path( - adbParser->_adbCtxt->mainFileName) - .parent_path() - .string(); + string projPath = boost::filesystem::path(adbParser->_adbCtxt->mainFileName).parent_path().string(); - for (StringVector::iterator it = - adbParser->_adbCtxt->includePaths.begin(); - it != adbParser->_adbCtxt->includePaths.end(); it++) + for (StringVector::iterator it = adbParser->_adbCtxt->includePaths.begin(); + it != adbParser->_adbCtxt->includePaths.end(); + it++) { if (boost::filesystem::path(*it).is_relative()) { @@ -1141,14 +1156,13 @@ void AdbParser::startConfigElement(const XML_Char **atts, AdbParser *adbParser, } } - adbParser->_adbCtxt->includePaths.insert( - adbParser->_adbCtxt->includePaths.end(), - relatives.begin(), relatives.end()); + adbParser->_adbCtxt->includePaths.insert(adbParser->_adbCtxt->includePaths.end(), relatives.begin(), + relatives.end()); } } } -void AdbParser::startInfoElement(const XML_Char **atts, AdbParser *adbParser) +void AdbParser::startInfoElement(const XML_Char** atts, AdbParser* adbParser) { string docName = attrValue(atts, "source_doc_name"); string docVer = attrValue(atts, "source_doc_version"); @@ -1156,11 +1170,12 @@ void AdbParser::startInfoElement(const XML_Char **atts, AdbParser *adbParser) adbParser->_adbCtxt->srcDocVer = docVer; } -void AdbParser::startIncludeElement(const XML_Char **atts, AdbParser *adbParser, const int lineNumber) +void AdbParser::startIncludeElement(const XML_Char** atts, AdbParser* adbParser, const int lineNumber) { bool cond = is_inst_ifdef_exist_and_correct_project(atts, adbParser); - - if (cond) { + + if (cond) + { string includeAttr = attrName(atts, 0); boost::algorithm::trim(includeAttr); @@ -1171,10 +1186,11 @@ void AdbParser::startIncludeElement(const XML_Char **atts, AdbParser *adbParser, boost::algorithm::trim(fname); if (fname.empty()) { - expFound = raiseException(allowMultipleExceptions, - string() + "File attribute isn't given within " + TAG_INCLUDE + " tag", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::FATAL_EXCEPTION); + expFound = raiseException( + allowMultipleExceptions, + string() + "File attribute isn't given within " + TAG_INCLUDE + " tag", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::FATAL_EXCEPTION); } if (!expFound) includeFile(adbParser, fname, lineNumber); @@ -1185,10 +1201,11 @@ void AdbParser::startIncludeElement(const XML_Char **atts, AdbParser *adbParser, boost::algorithm::trim(includeAllDirPath); if (includeAllDirPath.empty()) { - expFound = raiseException(allowMultipleExceptions, - string() + "Directory to include isn't given within " + TAG_INCLUDE + " tag", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::FATAL_EXCEPTION); + expFound = raiseException( + allowMultipleExceptions, + string() + "Directory to include isn't given within " + TAG_INCLUDE + " tag", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::FATAL_EXCEPTION); } if (!expFound) @@ -1196,32 +1213,35 @@ void AdbParser::startIncludeElement(const XML_Char **atts, AdbParser *adbParser, } else { - expFound = raiseException(allowMultipleExceptions, - string() + "Include is called without file or dir attribute.", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::ERROR_EXCEPTION); + expFound = raiseException( + allowMultipleExceptions, + string() + "Include is called without file or dir attribute.", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::ERROR_EXCEPTION); } } } -void AdbParser::startInstOpAttrReplaceElement(const XML_Char **atts, AdbParser *adbParser, const int lineNumber) +void AdbParser::startInstOpAttrReplaceElement(const XML_Char** atts, AdbParser* adbParser, const int lineNumber) { bool expFound = false; if (!adbParser->_instanceOps) { - expFound = raiseException(allowMultipleExceptions, - "Operation attr_replace must be defined within element only.", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::FATAL_EXCEPTION); + expFound = + raiseException(allowMultipleExceptions, + "Operation attr_replace must be defined within element only.", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::FATAL_EXCEPTION); } string path = attrValue(atts, "path"); if (path.empty()) { - expFound = raiseException(allowMultipleExceptions, - "path attribute is missing in attr_replace operation", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::ERROR_EXCEPTION); + expFound = + raiseException(allowMultipleExceptions, + "path attribute is missing in attr_replace operation", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::ERROR_EXCEPTION); } if (!expFound) @@ -1241,7 +1261,7 @@ void AdbParser::startInstOpAttrReplaceElement(const XML_Char **atts, AdbParser * } } -void AdbParser::startNodeElement(const XML_Char **atts, AdbParser *adbParser, const int lineNumber) +void AdbParser::startNodeElement(const XML_Char** atts, AdbParser* adbParser, const int lineNumber) { if (adbParser->_currentNode || adbParser->skipNode) { @@ -1252,20 +1272,21 @@ void AdbParser::startNodeElement(const XML_Char **atts, AdbParser *adbParser, co } bool cond = is_inst_ifdef_exist_and_correct_project(atts, adbParser); - if (cond) { - + if (cond) + { string nodeName = attrValue(atts, "name"); boost::algorithm::trim(nodeName); string size = attrValue(atts, "size"); - if(adbParser->_enforceGuiChecks) + if (adbParser->_enforceGuiChecks) { // check the node name is compatible with the nname_pattern - if(!regex_match(nodeName, regex(adbParser->_nname_pattern))) + if (!regex_match(nodeName, regex(adbParser->_nname_pattern))) { raiseException(allowMultipleExceptions, "Illegal node name: \"" + nodeName + "\" doesn't match the given node name pattern: \"", - adbParser->_nname_pattern + "\", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + adbParser->_nname_pattern + "\", in file: \"" + adbParser->_fileName + + "\" line: " + boost::lexical_cast(lineNumber), ExceptionHolder::WARN_EXCEPTION); } } @@ -1274,24 +1295,27 @@ void AdbParser::startNodeElement(const XML_Char **atts, AdbParser *adbParser, co { if (!AdbParser::checkSpecialChars(nodeName)) { - raiseException(allowMultipleExceptions, - "Invalid character in node name, in Node: \"" + nodeName + "\"", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::WARN_EXCEPTION); + raiseException( + allowMultipleExceptions, + "Invalid character in node name, in Node: \"" + nodeName + "\"", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::WARN_EXCEPTION); } if (AdbParser::checkBigger32(size)) { // the second part of the size after the . max to be 32 0x0.0 - raiseException(allowMultipleExceptions, - "Invalid size format, valid format 0x0.0 not allowed to be more than 0x0.31", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::WARN_EXCEPTION); + raiseException( + allowMultipleExceptions, + "Invalid size format, valid format 0x0.0 not allowed to be more than 0x0.31", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::WARN_EXCEPTION); } if (addr2int(size) == 0) { - raiseException(allowMultipleExceptions, - "Node Size is not allowed to be 0, in Node: \"" + nodeName + "\"", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::ERROR_EXCEPTION); + raiseException( + allowMultipleExceptions, + "Node Size is not allowed to be 0, in Node: \"" + nodeName + "\"", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::ERROR_EXCEPTION); } } string desc = descXmlToNative(attrValue(atts, "descr")); @@ -1299,25 +1323,30 @@ void AdbParser::startNodeElement(const XML_Char **atts, AdbParser *adbParser, co // Check for mandatory attrs if (nodeName.empty()) { - raiseException(allowMultipleExceptions, - "Missing node name", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::FATAL_EXCEPTION); + raiseException( + allowMultipleExceptions, + "Missing node name", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::FATAL_EXCEPTION); } if (size.empty()) { - raiseException(allowMultipleExceptions, - "Missing node size", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::FATAL_EXCEPTION); + raiseException( + allowMultipleExceptions, + "Missing node size", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::FATAL_EXCEPTION); } // Check for duplications if (adbParser->_adbCtxt->nodesMap.count(nodeName)) { - raiseException(allowMultipleExceptions, - "node \"" + nodeName + "\" is already defined in file: \"" + adbParser->_adbCtxt->nodesMap[nodeName]->fileName + "\" line: " + boost::lexical_cast(adbParser->_adbCtxt->nodesMap[nodeName]->lineNumber), - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::FATAL_EXCEPTION); + raiseException( + allowMultipleExceptions, + "node \"" + nodeName + "\" is already defined in file: \"" + + adbParser->_adbCtxt->nodesMap[nodeName]->fileName + + "\" line: " + boost::lexical_cast(adbParser->_adbCtxt->nodesMap[nodeName]->lineNumber), + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::FATAL_EXCEPTION); } adbParser->_currentNode = new AdbNode; @@ -1331,7 +1360,7 @@ void AdbParser::startNodeElement(const XML_Char **atts, AdbParser *adbParser, co if (adbParser->_strict && adbParser->_currentNode->isUnion && adbParser->_currentNode->size % 32) { - //throw AdbException("union must be dword aligned"); + // throw AdbException("union must be dword aligned"); } // Add all node attributes @@ -1343,30 +1372,34 @@ void AdbParser::startNodeElement(const XML_Char **atts, AdbParser *adbParser, co } adbParser->_currentNode->attrs[attrName(atts, i)] = attrValue(atts, i); } - } else { + } + else + { adbParser->skipNode = true; } } -void AdbParser::startFieldElement(const XML_Char **atts, AdbParser *adbParser, const int lineNumber) +void AdbParser::startFieldElement(const XML_Char** atts, AdbParser* adbParser, const int lineNumber) { bool expFound = false; if (!adbParser->_currentNode && !adbParser->skipNode) { - expFound = raiseException(allowMultipleExceptions, - "Field definition outside of node", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::FATAL_EXCEPTION); + expFound = + raiseException(allowMultipleExceptions, + "Field definition outside of node", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::FATAL_EXCEPTION); } - if (!adbParser->skipNode) { - + if (!adbParser->skipNode) + { if (adbParser->_currentField) { - expFound = raiseException(allowMultipleExceptions, - "Nested fields are not allowed", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::FATAL_EXCEPTION); + expFound = raiseException( + allowMultipleExceptions, + "Nested fields are not allowed", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::FATAL_EXCEPTION); } string fieldName = attrValue(atts, "name"); @@ -1378,52 +1411,59 @@ void AdbParser::startFieldElement(const XML_Char **atts, AdbParser *adbParser, c { if (addr2int(size) % 32 == 0 && !AdbParser::checkHEXFormat(size)) { - expFound = raiseException(allowMultipleExceptions, - "Invalid size format", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::WARN_EXCEPTION); + expFound = raiseException( + allowMultipleExceptions, + "Invalid size format", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::WARN_EXCEPTION); } if (!AdbParser::checkHEXFormat(offset)) { - expFound = raiseException(allowMultipleExceptions, - "Invalid offset format", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::WARN_EXCEPTION); + expFound = raiseException( + allowMultipleExceptions, + "Invalid offset format", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::WARN_EXCEPTION); } if (!AdbParser::checkSpecialChars(fieldName)) { - expFound = raiseException(allowMultipleExceptions, - "Invalid character in field name, in Field: \"" + fieldName + "\"", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::WARN_EXCEPTION); + expFound = raiseException( + allowMultipleExceptions, + "Invalid character in field name, in Field: \"" + fieldName + "\"", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::WARN_EXCEPTION); } if (!expFound && adbParser->_currentNode->isUnion && addr2int(offset) != 0) { - expFound = raiseException(allowMultipleExceptions, - "Offset must be 0x0.0 in Union fields", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::WARN_EXCEPTION); + expFound = raiseException( + allowMultipleExceptions, + "Offset must be 0x0.0 in Union fields", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::WARN_EXCEPTION); } if (AdbParser::checkBigger32(size)) { // the second part of the size after the . max to be 32 0x0.0 - expFound = raiseException(allowMultipleExceptions, - "Invalid size format, valid format 0x0.0 not allowed to be more than 0x0.31", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::WARN_EXCEPTION); + expFound = raiseException( + allowMultipleExceptions, + "Invalid size format, valid format 0x0.0 not allowed to be more than 0x0.31", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::WARN_EXCEPTION); } if (AdbParser::checkBigger32(offset)) { // the second part of the size after the . max to be 32 0x0.0 - expFound = raiseException(allowMultipleExceptions, - "Invalid offset format, valid format 0x0.0 not allowed to be more than 0x0.31", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::WARN_EXCEPTION); + expFound = raiseException( + allowMultipleExceptions, + "Invalid offset format, valid format 0x0.0 not allowed to be more than 0x0.31", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::WARN_EXCEPTION); } if (addr2int(size) == 0) { - expFound = raiseException(allowMultipleExceptions, - "Field Size is not allowed to be 0, in Field: \"" + fieldName + "\"", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::WARN_EXCEPTION); + expFound = raiseException( + allowMultipleExceptions, + "Field Size is not allowed to be 0, in Field: \"" + fieldName + "\"", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::WARN_EXCEPTION); } } @@ -1443,45 +1483,50 @@ void AdbParser::startFieldElement(const XML_Char **atts, AdbParser *adbParser, c int entrySize = isize / (high - low + 1); if (entrySize % 8 != 0 && entrySize > 8) { - expFound = raiseException(allowMultipleExceptions, - "Invalid size of array entries", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::ERROR_EXCEPTION); + expFound = raiseException( + allowMultipleExceptions, + "Invalid size of array entries", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::ERROR_EXCEPTION); } - if (entrySize < 8 && entrySize != 4 && entrySize != 2 && entrySize != 1 && ((isize > 32 && highBound != "VARIABLE") || highBound == "VARIABLE")) + if (entrySize < 8 && entrySize != 4 && entrySize != 2 && entrySize != 1 && + ((isize > 32 && highBound != "VARIABLE") || highBound == "VARIABLE")) { - expFound = raiseException(allowMultipleExceptions, - "Array with entry size 3, 5, 6 or 7 bits and array size is larger than 32bit", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::ERROR_EXCEPTION); + expFound = raiseException( + allowMultipleExceptions, + "Array with entry size 3, 5, 6 or 7 bits and array size is larger than 32bit", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::ERROR_EXCEPTION); } } - else if(adbParser->_enforceGuiChecks && !(lowBound == "" && highBound == "")) + else if (adbParser->_enforceGuiChecks && !(lowBound == "" && highBound == "")) { - expFound = raiseException(allowMultipleExceptions, - "Field: \"" + adbParser->_currentField->name + "\": both low_bound or high_bound must be specified", - ", in file: \"" + adbParser->_fileName + - "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::WARN_EXCEPTION); + expFound = raiseException( + allowMultipleExceptions, + "Field: \"" + adbParser->_currentField->name + "\": both low_bound or high_bound must be specified", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::WARN_EXCEPTION); } string subNode = attrValue(atts, "subnode"); // Check for mandatory attrs - if (fieldName.empty()) + if (fieldName.empty()) { - expFound = raiseException(allowMultipleExceptions, - "Missing field name", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::FATAL_EXCEPTION); + expFound = raiseException( + allowMultipleExceptions, + "Missing field name", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::FATAL_EXCEPTION); } if (size.empty()) { - expFound = raiseException(allowMultipleExceptions, - "Missing field size", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::FATAL_EXCEPTION); + expFound = raiseException( + allowMultipleExceptions, + "Missing field size", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::FATAL_EXCEPTION); } // Create new fields @@ -1510,8 +1555,7 @@ void AdbParser::startFieldElement(const XML_Char **atts, AdbParser *adbParser, c adbParser->_currentField->definedAsArr = false; } - adbParser->_currentField->lowBound = lowBound.empty() ? 0 - : boost::lexical_cast(lowBound); + adbParser->_currentField->lowBound = lowBound.empty() ? 0 : boost::lexical_cast(lowBound); if (highBound == "VARIABLE") { adbParser->_currentField->highBound = 0; @@ -1519,25 +1563,21 @@ void AdbParser::startFieldElement(const XML_Char **atts, AdbParser *adbParser, c } else { - adbParser->_currentField->highBound = highBound.empty() ? 0 - : boost::lexical_cast(highBound); + adbParser->_currentField->highBound = highBound.empty() ? 0 : boost::lexical_cast(highBound); } adbParser->_currentField->subNode = subNode; // Check array element size - if (adbParser->_currentField->isArray() && !adbParser->_currentField->isUnlimitedArr() && adbParser->_currentField->size % (adbParser->_currentField->arrayLen())) + if (adbParser->_currentField->isArray() && !adbParser->_currentField->isUnlimitedArr() && + adbParser->_currentField->size % (adbParser->_currentField->arrayLen())) { char exceptionTxt[1000]; - sprintf(exceptionTxt, - "In field \"%s\" invalid array element size\"%0.2f\" in file: \"%s\" line: %d", + sprintf(exceptionTxt, "In field \"%s\" invalid array element size\"%0.2f\" in file: \"%s\" line: %d", fieldName.c_str(), ((double)adbParser->_currentField->size / (adbParser->_currentField->arrayLen())), adbParser->_fileName.c_str(), lineNumber); - expFound = raiseException(allowMultipleExceptions, - exceptionTxt, - "", - ExceptionHolder::FATAL_EXCEPTION); + expFound = raiseException(allowMultipleExceptions, exceptionTxt, "", ExceptionHolder::FATAL_EXCEPTION); } if (offset.empty()) { @@ -1547,7 +1587,7 @@ void AdbParser::startFieldElement(const XML_Char **atts, AdbParser *adbParser, c } else { - AdbField *lastField = adbParser->_currentNode->fields.back(); + AdbField* lastField = adbParser->_currentNode->fields.back(); adbParser->_currentField->offset = lastField->offset + lastField->size; } } @@ -1562,80 +1602,96 @@ void AdbParser::startFieldElement(const XML_Char **atts, AdbParser *adbParser, c u_int32_t offset = adbParser->_currentField->offset; u_int32_t size = adbParser->_currentField->eSize(); - adbParser->_currentField->offset = ((offset >> 5) << 5) + ((MIN(32, adbParser->_currentNode->size) - ((offset + size) % 32)) % 32); + adbParser->_currentField->offset = + ((offset >> 5) << 5) + ((MIN(32, adbParser->_currentNode->size) - ((offset + size) % 32)) % 32); } // For DS alignment check u_int32_t esize = adbParser->_currentField->eSize(); - if ((adbParser->_currentField->isLeaf() || adbParser->_currentField->subNode == "uint64") && (esize == 16 || esize == 32 || esize == 64) && esize > adbParser->_currentNode->_maxLeafSize) { - adbParser->_currentNode->_maxLeafSize = esize; + if ((adbParser->_currentField->isLeaf() || adbParser->_currentField->subNode == "uint64") && + (esize == 16 || esize == 32 || esize == 64) && esize > adbParser->_currentNode->_maxLeafSize) + { + adbParser->_currentNode->_maxLeafSize = esize; } if (!expFound && adbParser->_strict && adbParser->_currentNode->isUnion && adbParser->_currentField->isLeaf()) { - expFound = raiseException(allowMultipleExceptions, - "Fields are not allowed in unions (only subnodes)", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::FATAL_EXCEPTION); + expFound = raiseException( + allowMultipleExceptions, + "Fields are not allowed in unions (only subnodes)", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::FATAL_EXCEPTION); } if (!expFound && adbParser->_strict && adbParser->_currentNode->isUnion && adbParser->_currentField->size % 32) { - expFound = raiseException(allowMultipleExceptions, - "Union is allowed to contains only dword aligned subnodes", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::FATAL_EXCEPTION); + expFound = raiseException( + allowMultipleExceptions, + "Union is allowed to contains only dword aligned subnodes", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::FATAL_EXCEPTION); } - if (!expFound && adbParser->_currentNode->isUnion && adbParser->_currentField->size > adbParser->_currentNode->size) + if (!expFound && adbParser->_currentNode->isUnion && + adbParser->_currentField->size > adbParser->_currentNode->size) { - expFound = raiseException(allowMultipleExceptions, - "Field size is greater than the parent node size", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::FATAL_EXCEPTION); + expFound = raiseException( + allowMultipleExceptions, + "Field size is greater than the parent node size", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::FATAL_EXCEPTION); } - if (!expFound && adbParser->_strict && !adbParser->_currentField->isArray() && adbParser->_currentField->isLeaf() && adbParser->_currentField->size > 32) + if (!expFound && adbParser->_strict && !adbParser->_currentField->isArray() && + adbParser->_currentField->isLeaf() && adbParser->_currentField->size > 32) { - expFound = raiseException(allowMultipleExceptions, - "Leaf fields can't be > 32 bits", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::FATAL_EXCEPTION); + expFound = raiseException( + allowMultipleExceptions, + "Leaf fields can't be > 32 bits", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::FATAL_EXCEPTION); } - if (!expFound && adbParser->_checkDsAlign) { + if (!expFound && adbParser->_checkDsAlign) + { u_int32_t esize = adbParser->_currentField->eSize(); - if ((adbParser->_currentField->isLeaf() || adbParser->_currentField->subNode == "uint64") && (esize == 16 || esize == 32 || esize ==64) && adbParser->_currentField->offset % esize != 0) { - expFound = raiseException(allowMultipleExceptions, - "Field: " + adbParser->_currentField->name + " in Node: " + adbParser->_currentNode->name + " offset(" + boost::lexical_cast(adbParser->_currentField->offset) + ") is not aligned to size(" + boost::lexical_cast(esize) + ")", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::ERROR_EXCEPTION); + if ((adbParser->_currentField->isLeaf() || adbParser->_currentField->subNode == "uint64") && + (esize == 16 || esize == 32 || esize == 64) && adbParser->_currentField->offset % esize != 0) + { + expFound = raiseException( + allowMultipleExceptions, + "Field: " + adbParser->_currentField->name + " in Node: " + adbParser->_currentNode->name + + " offset(" + boost::lexical_cast(adbParser->_currentField->offset) + + ") is not aligned to size(" + boost::lexical_cast(esize) + ")", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::ERROR_EXCEPTION); } } - if(adbParser->_enforceGuiChecks) + if (adbParser->_enforceGuiChecks) { // check if all mandatory attributes were supplied - for(unsigned int i = 0; i < adbParser->field_mand_attr.size(); i++) + for (unsigned int i = 0; i < adbParser->field_mand_attr.size(); i++) { - if(attrValue(atts, adbParser->field_mand_attr[i].c_str()) == "") + if (attrValue(atts, adbParser->field_mand_attr[i].c_str()) == "") { - expFound = raiseException(allowMultipleExceptions, - "Atrribute: \"" + adbParser->field_mand_attr[i] + "\" for field must be specified.", - " in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::ERROR_EXCEPTION); + expFound = raiseException( + allowMultipleExceptions, + "Atrribute: \"" + adbParser->field_mand_attr[i] + "\" for field must be specified.", + " in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::ERROR_EXCEPTION); } } // check if the field name is compatible with the fname pattern - if(!regex_match(adbParser->_currentField->name, regex(adbParser->_fname_pattern))) + if (!regex_match(adbParser->_currentField->name, regex(adbParser->_fname_pattern))) { - expFound = raiseException(allowMultipleExceptions, - "Illegal field name: \"" + adbParser->_currentField->name + - "\" doesn't match the given field name pattern", - ", in file: \"" + adbParser->_fileName + - "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::WARN_EXCEPTION); + expFound = raiseException( + allowMultipleExceptions, + "Illegal field name: \"" + adbParser->_currentField->name + + "\" doesn't match the given field name pattern", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::WARN_EXCEPTION); } } @@ -1644,50 +1700,53 @@ void AdbParser::startFieldElement(const XML_Char **atts, AdbParser *adbParser, c { for (int i = 0; i < attrCount(atts); i++) { - if(adbParser->_enforceGuiChecks) + if (adbParser->_enforceGuiChecks) { string aName = attrName(atts, i); string aValue = attrValue(atts, i); // check if the field contains illegal attribute - if(!aName.compare("inst_if") && !aName.compare("inst_ifdef") && !aName.compare("subnode") && + if (!aName.compare("inst_if") && !aName.compare("inst_ifdef") && !aName.compare("subnode") && adbParser->field_attr_names_set.find(aName) != adbParser->field_attr_names_set.end() && adbParser->field_spec_attr.find(aName) != adbParser->field_spec_attr.end()) { - expFound = raiseException(allowMultipleExceptions, - "Unknown attribute: " + aName + " at field: " + adbParser->_currentField->name, - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::ERROR_EXCEPTION); + expFound = + raiseException(allowMultipleExceptions, + "Unknown attribute: " + aName + " at field: " + adbParser->_currentField->name, + ", in file: \"" + adbParser->_fileName + + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::ERROR_EXCEPTION); } - if(!aName.compare("enum")) + if (!aName.compare("enum")) { // check the enum attribute is compatible with the enum pattern - if(!regex_match(aValue, regex(adbParser->_enum_pattern))) + if (!regex_match(aValue, regex(adbParser->_enum_pattern))) { - expFound = raiseException(allowMultipleExceptions, - "Illegal value: \"" + aValue + "\" for attribute: \"" + aName + "\" ", - "doesn't match the given attribute pattern, in file: \"" + adbParser->_fileName + - "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::WARN_EXCEPTION); + expFound = raiseException( + allowMultipleExceptions, + "Illegal value: \"" + aValue + "\" for attribute: \"" + aName + "\" ", + "doesn't match the given attribute pattern, in file: \"" + adbParser->_fileName + + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::WARN_EXCEPTION); } } else { // check the attribute name is compatible with the attribute pattern - if(adbParser->attr_pattern.find(aName) != adbParser->attr_pattern.end() && - !regex_match(aValue, regex(adbParser->attr_pattern[aName]))) + if (adbParser->attr_pattern.find(aName) != adbParser->attr_pattern.end() && + !regex_match(aValue, regex(adbParser->attr_pattern[aName]))) { - expFound = raiseException(allowMultipleExceptions, - "Illegal value: \"" + aValue + "\" for attribute: \"" + aName + "\" ", - "doesn't match the given attribute pattern, in file: \"" + adbParser->_fileName + - "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::WARN_EXCEPTION); + expFound = raiseException( + allowMultipleExceptions, + "Illegal value: \"" + aValue + "\" for attribute: \"" + aName + "\" ", + "doesn't match the given attribute pattern, in file: \"" + adbParser->_fileName + + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::WARN_EXCEPTION); } } } - adbParser->_currentField->attrs[attrName(atts, i)] = attrValue( - atts, i); + adbParser->_currentField->attrs[attrName(atts, i)] = attrValue(atts, i); } } } @@ -1696,9 +1755,9 @@ void AdbParser::startFieldElement(const XML_Char **atts, AdbParser *adbParser, c /** * Function: AdbParser::startElement **/ -void AdbParser::startElement(void *_adbParser, const XML_Char *name, const XML_Char **atts) +void AdbParser::startElement(void* _adbParser, const XML_Char* name, const XML_Char** atts) { - AdbParser *adbParser = static_cast(_adbParser); + AdbParser* adbParser = static_cast(_adbParser); int lineNumber = XML_GetCurrentLineNumber(adbParser->_xmlParser); adbParser->_currentTagValue = ""; @@ -1748,7 +1807,8 @@ void AdbParser::startElement(void *_adbParser, const XML_Char *name, const XML_C string exceptionTxt = "Unsupported tag: " + string(name); if (allowMultipleExceptions) { - exceptionTxt = exceptionTxt + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber); + exceptionTxt = exceptionTxt + ", in file: \"" + adbParser->_fileName + + "\" line: " + boost::lexical_cast(lineNumber); ExceptionHolder::insertNewException(ExceptionHolder::FATAL_EXCEPTION, exceptionTxt); return; } @@ -1762,34 +1822,33 @@ void AdbParser::startElement(void *_adbParser, const XML_Char *name, const XML_C /** * Function: AdbParser::addReserved **/ -void AdbParser::addReserved(vector &reserveds, u_int32_t offset, - u_int32_t size) +void AdbParser::addReserved(vector& reserveds, u_int32_t offset, u_int32_t size) { u_int32_t numOfDwords = (dword(offset + size - 1) - dword(offset)) / 4 + 1; - //printf("==> %s\n", formatAddr(offset, size).c_str()); - //printf("numOfDwords = %d\n", numOfDwords); + // printf("==> %s\n", formatAddr(offset, size).c_str()); + // printf("numOfDwords = %d\n", numOfDwords); if (numOfDwords == 1 || ((offset % 32) == 0 && ((offset + size) % 32) == 0)) { - AdbField *f1 = new AdbField; + AdbField* f1 = new AdbField; f1->name = "reserved"; f1->offset = offset; f1->isReserved = true; f1->size = size; reserveds.push_back(f1); - //printf("case1: reserved0: %s\n", formatAddr(f1->offset, f1->size).c_str()); + // printf("case1: reserved0: %s\n", formatAddr(f1->offset, f1->size).c_str()); } else if (numOfDwords == 2) { - AdbField *f1 = new AdbField; + AdbField* f1 = new AdbField; f1->name = "reserved"; f1->offset = offset; f1->isReserved = true; f1->size = 32 - startBit(offset); - AdbField *f2 = new AdbField; + AdbField* f2 = new AdbField; f2->name = "reserved"; f2->offset = dword(offset + 32) * 8; f2->isReserved = true; @@ -1802,13 +1861,13 @@ void AdbParser::addReserved(vector &reserveds, u_int32_t offset, } else { - AdbField *f1 = new AdbField; + AdbField* f1 = new AdbField; f1->name = "reserved"; f1->offset = offset; f1->isReserved = true; f1->size = 32 - startBit(offset); - AdbField *f2 = new AdbField; + AdbField* f2 = new AdbField; f2->name = "reserved"; f2->offset = dword(offset + 32) * 8; f2->isReserved = true; @@ -1841,7 +1900,7 @@ void AdbParser::addReserved(vector &reserveds, u_int32_t offset, else { f2->size = (numOfDwords - 2) * 32; - AdbField *f3 = new AdbField; + AdbField* f3 = new AdbField; f3->name = "reserved"; f3->offset = f2->offset + f2->size; f3->isReserved = true; @@ -1862,9 +1921,9 @@ void AdbParser::addReserved(vector &reserveds, u_int32_t offset, /** * Function: AdbParser::endElement **/ -void AdbParser::endElement(void *_adbParser, const XML_Char *name) +void AdbParser::endElement(void* _adbParser, const XML_Char* name) { - AdbParser *adbParser = static_cast(_adbParser); + AdbParser* adbParser = static_cast(_adbParser); int lineNumber = XML_GetCurrentLineNumber(adbParser->_xmlParser); /* * Config @@ -1890,9 +1949,12 @@ void AdbParser::endElement(void *_adbParser, const XML_Char *name) else if (TAG_NODE == name) { // Sort the fields by offset - if (adbParser->skipNode) { + if (adbParser->skipNode) + { adbParser->skipNode = false; - } else { + } + else + { if (!adbParser->_currentNode->isUnion) { stable_sort(adbParser->_currentNode->fields.begin(), @@ -1901,24 +1963,27 @@ void AdbParser::endElement(void *_adbParser, const XML_Char *name) } // Check overlapping - vector reserveds; + vector reserveds; AdbField prevFieldDummy; prevFieldDummy.offset = 0; prevFieldDummy.size = 0; - AdbField *prevField = &prevFieldDummy; + AdbField* prevField = &prevFieldDummy; if (!adbParser->_currentNode->isUnion) { for (size_t i = 0; i < adbParser->_currentNode->fields.size(); i++) { - AdbField *field = adbParser->_currentNode->fields[i]; + AdbField* field = adbParser->_currentNode->fields[i]; long int delta = (long)field->offset - (long)(prevField->offset + prevField->size); if (delta < 0) { // Overlapping - string exceptionTxt = "Field: " + field->name + " " + formatAddr(field->offset, field->size) + " overlaps with Field: " + prevField->name + " " + formatAddr(prevField->offset, prevField->size); + string exceptionTxt = "Field: " + field->name + " " + formatAddr(field->offset, field->size) + + " overlaps with Field: " + prevField->name + " " + + formatAddr(prevField->offset, prevField->size); if (allowMultipleExceptions) { - exceptionTxt = exceptionTxt + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber); + exceptionTxt = exceptionTxt + ", in file: \"" + adbParser->_fileName + + "\" line: " + boost::lexical_cast(lineNumber); ExceptionHolder::insertNewException(ExceptionHolder::ERROR_EXCEPTION, exceptionTxt); } else @@ -1928,8 +1993,7 @@ void AdbParser::endElement(void *_adbParser, const XML_Char *name) } if (delta > 0 && adbParser->_addReserved) { // Need reserved - addReserved(reserveds, prevField->offset + prevField->size, - delta); + addReserved(reserveds, prevField->offset + prevField->size, delta); } prevField = field; @@ -1957,23 +2021,25 @@ void AdbParser::endElement(void *_adbParser, const XML_Char *name) if (delta > 0) { - addReserved(reserveds, prevField->offset + prevField->size, - delta); + addReserved(reserveds, prevField->offset + prevField->size, delta); } } - adbParser->_currentNode->fields.insert( - adbParser->_currentNode->fields.end(), reserveds.begin(), - reserveds.end()); + adbParser->_currentNode->fields.insert(adbParser->_currentNode->fields.end(), reserveds.begin(), + reserveds.end()); } - if (adbParser->_checkDsAlign && adbParser->_currentNode->_maxLeafSize != 0 && adbParser->_currentNode->_maxLeafSize != 0 && adbParser->_currentNode->size % adbParser->_currentNode->_maxLeafSize != 0) { - - - raiseException(allowMultipleExceptions, - "Node: " + adbParser->_currentNode->name + " size(" + boost::lexical_cast(adbParser->_currentNode->size) + ") is not aligned with largest leaf(" + boost::lexical_cast(adbParser->_currentNode->_maxLeafSize) + ")", - ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), - ExceptionHolder::ERROR_EXCEPTION); + if (adbParser->_checkDsAlign && adbParser->_currentNode->_maxLeafSize != 0 && + adbParser->_currentNode->_maxLeafSize != 0 && + adbParser->_currentNode->size % adbParser->_currentNode->_maxLeafSize != 0) + { + raiseException( + allowMultipleExceptions, + "Node: " + adbParser->_currentNode->name + " size(" + + boost::lexical_cast(adbParser->_currentNode->size) + ") is not aligned with largest leaf(" + + boost::lexical_cast(adbParser->_currentNode->_maxLeafSize) + ")", + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber), + ExceptionHolder::ERROR_EXCEPTION); } // Re-fix fields offset @@ -1984,9 +2050,8 @@ void AdbParser::endElement(void *_adbParser, const XML_Char *name) u_int32_t offset = adbParser->_currentNode->fields[i]->offset; u_int32_t size = adbParser->_currentNode->fields[i]->eSize(); - adbParser->_currentNode->fields[i]->offset = ((offset >> 5) - << 5) + - ((MIN(32, adbParser->_currentNode->size) - ((offset + size) % 32)) % 32); + adbParser->_currentNode->fields[i]->offset = + ((offset >> 5) << 5) + ((MIN(32, adbParser->_currentNode->size) - ((offset + size) % 32)) % 32); } } @@ -2000,8 +2065,7 @@ void AdbParser::endElement(void *_adbParser, const XML_Char *name) // Add this node to AdbCtxt adbParser->_adbCtxt->nodesMap.insert( - pair(adbParser->_currentNode->name, - adbParser->_currentNode)); + pair(adbParser->_currentNode->name, adbParser->_currentNode)); adbParser->_currentNode = 0; } } @@ -2012,7 +2076,8 @@ void AdbParser::endElement(void *_adbParser, const XML_Char *name) else if (TAG_FIELD == name) { // Add this field to current node - if (!adbParser->skipNode) { + if (!adbParser->skipNode) + { if (adbParser->_currentNode->name == "root") { adbParser->_adbCtxt->rootNode = adbParser->_currentField->subNode; @@ -2027,13 +2092,11 @@ void AdbParser::endElement(void *_adbParser, const XML_Char *name) bool found = false; for (size_t i = 0; i < adbParser->_adbCtxt->configs.size(); i++) { - AttrsMap::iterator it_def = - adbParser->_adbCtxt->configs[i]->attrs.find("define"); + AttrsMap::iterator it_def = adbParser->_adbCtxt->configs[i]->attrs.find("define"); if (it_def != adbParser->_adbCtxt->configs[i]->attrs.end()) { vector defVal; - boost::algorithm::split(defVal, it_def->second, - boost::is_any_of(string("="))); + boost::algorithm::split(defVal, it_def->second, boost::is_any_of(string("="))); if (defVal[0] == it->second) { @@ -2053,13 +2116,11 @@ void AdbParser::endElement(void *_adbParser, const XML_Char *name) map vars; for (size_t i = 0; i < adbParser->_adbCtxt->configs.size(); i++) { - AttrsMap::iterator it_def = - adbParser->_adbCtxt->configs[i]->attrs.find("define"); + AttrsMap::iterator it_def = adbParser->_adbCtxt->configs[i]->attrs.find("define"); if (it_def != adbParser->_adbCtxt->configs[i]->attrs.end()) { vector defVal; - boost::algorithm::split(defVal, it_def->second, - boost::is_any_of(string("="))); + boost::algorithm::split(defVal, it_def->second, boost::is_any_of(string("="))); if (defVal.size() == 1) { @@ -2073,8 +2134,8 @@ void AdbParser::endElement(void *_adbParser, const XML_Char *name) } AdbExpr adbExpr; - char *expOrg = new char[it->second.size() + 1]; - char *exp = expOrg; + char* expOrg = new char[it->second.size() + 1]; + char* exp = expOrg; if (!exp) { throw AdbException("Memory allocation error"); @@ -2089,10 +2150,12 @@ void AdbParser::endElement(void *_adbParser, const XML_Char *name) if (status < 0) { - string exceptionTxt = string("Error evaluating expression \"") + it->second.c_str() + "\" : " + AdbExpr::statusStr(status); + string exceptionTxt = string("Error evaluating expression \"") + it->second.c_str() + + "\" : " + AdbExpr::statusStr(status); if (allowMultipleExceptions) { - exceptionTxt = exceptionTxt + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber); + exceptionTxt = exceptionTxt + ", in file: \"" + adbParser->_fileName + + "\" line: " + boost::lexical_cast(lineNumber); ExceptionHolder::insertNewException(ExceptionHolder::ERROR_EXCEPTION, exceptionTxt); } else @@ -2110,13 +2173,14 @@ void AdbParser::endElement(void *_adbParser, const XML_Char *name) { for (size_t i = 0; i < adbParser->_currentNode->fields.size(); i++) { - if (!adbParser->_currentNode->fields[i]->name.compare( - adbParser->_currentField->name)) + if (!adbParser->_currentNode->fields[i]->name.compare(adbParser->_currentField->name)) { - string exceptionTxt = "The field \"" + adbParser->_currentField->name + "\" isn't unique in node"; + string exceptionTxt = + "The field \"" + adbParser->_currentField->name + "\" isn't unique in node"; if (allowMultipleExceptions) { - exceptionTxt = exceptionTxt + ", in file: \"" + adbParser->_fileName + "\" line: " + boost::lexical_cast(lineNumber); + exceptionTxt = exceptionTxt + ", in file: \"" + adbParser->_fileName + + "\" line: " + boost::lexical_cast(lineNumber); ExceptionHolder::insertNewException(ExceptionHolder::ERROR_EXCEPTION, exceptionTxt); } else @@ -2136,8 +2200,7 @@ void AdbParser::endElement(void *_adbParser, const XML_Char *name) } else { - adbParser->_currentNode->condFields.push_back( - adbParser->_currentField); + adbParser->_currentNode->condFields.push_back(adbParser->_currentField); } adbParser->_currentField = 0; } @@ -2147,8 +2210,7 @@ void AdbParser::endElement(void *_adbParser, const XML_Char *name) /** * Function: AdbParser::raiseException **/ -bool AdbParser::raiseException(bool allowMultipleExceptions, string exceptionTxt, - string addedMsg, const string expType) +bool AdbParser::raiseException(bool allowMultipleExceptions, string exceptionTxt, string addedMsg, const string expType) { if (allowMultipleExceptions) { @@ -2212,9 +2274,6 @@ int main() } #endif - - - Adb::Adb() : bigEndianArr(false), singleEntryArrSupp(false), _checkDsAlign(false), _enforceGuiChecks(false) { _logFile = new LogFile; @@ -2314,9 +2373,16 @@ string Adb::printAdbExceptionMap() /** * Function: Adb::load **/ -bool Adb::load(string fname, bool addReserved, - bool strict, string includePath, string includeDir, - bool enforceExtraChecks, bool allowMultipleExceptions, string logFileStr, bool checkDsAlign, bool enforceGuiChecks) +bool Adb::load(string fname, + bool addReserved, + bool strict, + string includePath, + string includeDir, + bool enforceExtraChecks, + bool allowMultipleExceptions, + string logFileStr, + bool checkDsAlign, + bool enforceGuiChecks) { try { @@ -2327,9 +2393,8 @@ bool Adb::load(string fname, bool addReserved, AdbParser::setAllowMultipleExceptionsTrue(); } _logFile->init(logFileStr, allowMultipleExceptions); - AdbParser p(fname, this, addReserved, strict, includePath, - enforceExtraChecks, checkDsAlign, enforceGuiChecks); - _checkDsAlign=checkDsAlign; + AdbParser p(fname, this, addReserved, strict, includePath, enforceExtraChecks, checkDsAlign, enforceGuiChecks); + _checkDsAlign = checkDsAlign; _enforceGuiChecks = enforceGuiChecks; if (!p.load()) { @@ -2351,9 +2416,7 @@ bool Adb::load(string fname, bool addReserved, } if (status) { - bool checkSizeConsistency = strict ? checkInstSizeConsistency( - allowMultipleExceptions) - : true; + bool checkSizeConsistency = strict ? checkInstSizeConsistency(allowMultipleExceptions) : true; status = status && checkSizeConsistency; } if (allowMultipleExceptions && ExceptionHolder::getNumberOfExceptions() > 0) @@ -2363,7 +2426,7 @@ bool Adb::load(string fname, bool addReserved, } return status; } - catch (AdbException &e) + catch (AdbException& e) { _lastError = e.what_s(); if (allowMultipleExceptions) @@ -2377,13 +2440,11 @@ bool Adb::load(string fname, bool addReserved, /** * Function: Adb::loadFromString **/ -bool Adb::loadFromString(const char *adbContents, bool addReserved, - bool strict, bool enforceExtraChecks) +bool Adb::loadFromString(const char* adbContents, bool addReserved, bool strict, bool enforceExtraChecks) { try { - AdbParser p(string(), this, addReserved, strict, "", - enforceExtraChecks); + AdbParser p(string(), this, addReserved, strict, "", enforceExtraChecks); mainFileName = OS_PATH_SEP; if (!p.loadFromString(adbContents)) { @@ -2399,7 +2460,7 @@ bool Adb::loadFromString(const char *adbContents, bool addReserved, return strict ? checkInstSizeConsistency() : true; } - catch (AdbException &e) + catch (AdbException& e) { _lastError = e.what_s(); return false; @@ -2409,8 +2470,7 @@ bool Adb::loadFromString(const char *adbContents, bool addReserved, /** * Function: Adb::toXml **/ -string Adb::toXml(vector nodeNames, bool addRootNode, string rootName, - string addPrefix) +string Adb::toXml(vector nodeNames, bool addRootNode, string rootName, string addPrefix) { try { @@ -2438,13 +2498,14 @@ string Adb::toXml(vector nodeNames, bool addRootNode, string rootName, } // Add source info - xml += "\n"; + xml += "\n"; if (nodeNames.empty()) { for (NodesMap::iterator it = nodesMap.begin(); it != nodesMap.end(); it++) { - AdbNode *node = it->second; + AdbNode* node = it->second; xml += node->toXml(addPrefix); } } @@ -2460,7 +2521,7 @@ string Adb::toXml(vector nodeNames, bool addRootNode, string rootName, return ""; } - AdbNode *node = it->second; + AdbNode* node = it->second; xml += node->toXml(addPrefix) + "\n\n"; maxSize = TOOLS_MAX(node->size, maxSize); @@ -2469,25 +2530,21 @@ string Adb::toXml(vector nodeNames, bool addRootNode, string rootName, if (addRootNode) { stringstream buf; - buf << "> 5) << 2) << "." << dec - << (maxSize % 32) << "\" descr=\"\" >\n"; + buf << "> 5) << 2) << "." << dec << (maxSize % 32) + << "\" descr=\"\" >\n"; buf << "\t> 5) << 2) << "." - << dec << (maxSize % 32) << "\" subnode=\"" << addPrefix + rootName << "\" descr=\"\" />\n"; + << " size=\"0x" << hex << ((maxSize >> 5) << 2) << "." << dec << (maxSize % 32) << "\" subnode=\"" + << addPrefix + rootName << "\" descr=\"\" />\n"; buf << "\n\n"; - buf << "> 5) << 2) << "." << dec - << (maxSize % 32) - << "\" attr_is_union=\"1\" descr=\"\" >\n"; + buf << "> 5) << 2) << "." + << dec << (maxSize % 32) << "\" attr_is_union=\"1\" descr=\"\" >\n"; for (size_t i = 0; i < nodeNames.size(); i++) { - AdbNode *node = nodesMap[nodeNames[i]]; - buf << "\tname - << "\" offset=\"0x0.0\" size=\"0x" << hex - << ((node->size >> 5) << 2) << "." << dec - << (node->size % 32) << "\" subnode=\"" + addPrefix + node->name + "\" descr=\"\" />\n"; + AdbNode* node = nodesMap[nodeNames[i]]; + buf << "\tname << "\" offset=\"0x0.0\" size=\"0x" << hex + << ((node->size >> 5) << 2) << "." << dec << (node->size % 32) + << "\" subnode=\"" + addPrefix + node->name + "\" descr=\"\" />\n"; } buf << "\n"; xml += buf.str(); @@ -2497,7 +2554,7 @@ string Adb::toXml(vector nodeNames, bool addRootNode, string rootName, xml += "\n"; return xml; } - catch (AdbException &exp) + catch (AdbException& exp) { _lastError = exp.what_s(); return ""; @@ -2508,17 +2565,17 @@ string Adb::toXml(vector nodeNames, bool addRootNode, string rootName, * Function: Adb::addMissingNodes **/ -AdbInstance *Adb::addMissingNodes(int depth, bool allowMultipleExceptions) +AdbInstance* Adb::addMissingNodes(int depth, bool allowMultipleExceptions) { try { NodesMap::iterator it; for (it = nodesMap.begin(); it != nodesMap.end(); it++) { - AdbNode *nodeDesc = it->second; + AdbNode* nodeDesc = it->second; for (size_t i = 0; (depth == -1 || depth > 0) && i < nodeDesc->fields.size(); i++) { - AdbField *fieldDesc = nodeDesc->fields[i]; + AdbField* fieldDesc = nodeDesc->fields[i]; for (u_int32_t i = 0; i < fieldDesc->arrayLen(); i++) { if (fieldDesc->isStruct()) @@ -2527,28 +2584,27 @@ AdbInstance *Adb::addMissingNodes(int depth, bool allowMultipleExceptions) if (it2 == nodesMap.end()) { // If in ignore missing nodes mode, it should create temporary node with placeholder - AdbNode *tmpNode = new AdbNode; + AdbNode* tmpNode = new AdbNode; tmpNode->name = fieldDesc->subNode; tmpNode->size = fieldDesc->eSize(); tmpNode->desc = fieldDesc->desc + " ***MISSING NODE***"; tmpNode->isUnion = false; tmpNode->fileName = "tempForMissingNodes.adb"; tmpNode->lineNumber = 0; - AdbField *tmpField = new AdbField; + AdbField* tmpField = new AdbField; tmpField->name = "placeholder"; tmpField->desc = "This field is part of auto generated node for missing node."; tmpField->size = tmpNode->size; tmpField->offset = 0; tmpNode->fields.push_back(tmpField); - nodesMap.insert( - pair(tmpNode->name, tmpNode)); + nodesMap.insert(pair(tmpNode->name, tmpNode)); } } } } } } - catch (AdbException &exp) + catch (AdbException& exp) { _lastError = exp.what_s(); if (allowMultipleExceptions) @@ -2580,13 +2636,15 @@ void Adb::cleanInstAttrs() /** * Function: Adb::createLayout **/ -AdbInstance *Adb::createLayout(string rootNodeName, bool isExprEval, - int depth, bool ignoreMissingNodes, +AdbInstance* Adb::createLayout(string rootNodeName, + bool isExprEval, + int depth, + bool ignoreMissingNodes, bool allowMultipleExceptions) { try { - //find root in nodes map + // find root in nodes map NodesMap::iterator it; it = nodesMap.find(rootNodeName); if (it == nodesMap.end()) @@ -2596,9 +2654,9 @@ AdbInstance *Adb::createLayout(string rootNodeName, bool isExprEval, ExceptionHolder::FATAL_EXCEPTION); } - AdbNode *nodeDesc = it->second; + AdbNode* nodeDesc = it->second; nodeDesc->inLayout = true; - AdbInstance *rootItem = new AdbInstance(); + AdbInstance* rootItem = new AdbInstance(); rootItem->fieldDesc = NULL; rootItem->nodeDesc = nodeDesc; rootItem->parent = NULL; @@ -2616,12 +2674,10 @@ AdbInstance *Adb::createLayout(string rootNodeName, bool isExprEval, for (size_t i = 0; (depth == -1 || depth > 0) && i < nodeDesc->fields.size(); i++) { - vector subItems = createInstance(nodeDesc->fields[i], - rootItem, emptyVars, isExprEval, - depth == -1 ? -1 : depth - 1, ignoreMissingNodes, - allowMultipleExceptions); - rootItem->subItems.insert(rootItem->subItems.end(), - subItems.begin(), subItems.end()); + vector subItems = + createInstance(nodeDesc->fields[i], rootItem, emptyVars, isExprEval, depth == -1 ? -1 : depth - 1, + ignoreMissingNodes, allowMultipleExceptions); + rootItem->subItems.insert(rootItem->subItems.end(), subItems.begin(), subItems.end()); } // Now set the instance attributes (override field attrs), only if this is root node instantiation @@ -2630,10 +2686,9 @@ AdbInstance *Adb::createLayout(string rootNodeName, bool isExprEval, for (InstanceAttrs::iterator it = instAttrs.begin(); it != instAttrs.end(); it++) { size_t idx = it->first.find("."); - string path = idx == string::npos ? string() - : it->first.substr(idx + 1); + string path = idx == string::npos ? string() : it->first.substr(idx + 1); - AdbInstance *inst = rootItem->getChildByPath(path); + AdbInstance* inst = rootItem->getChildByPath(path); if (!inst) { raiseException(allowMultipleExceptions, @@ -2653,13 +2708,14 @@ AdbInstance *Adb::createLayout(string rootNodeName, bool isExprEval, } /* Evaluate unions selector fields*/ - for (list::iterator it = _unionSelectorEvalDeffered.begin(); - it != _unionSelectorEvalDeffered.end(); it++) + for (list::iterator it = _unionSelectorEvalDeffered.begin(); + it != _unionSelectorEvalDeffered.end(); + it++) { bool foundSelector = true; vector path; - AdbInstance *inst = *it; - AdbInstance *curInst = inst; + AdbInstance* inst = *it; + AdbInstance* curInst = inst; const string splitVal = inst->getInstanceAttr("union_selector"); boost::algorithm::split(path, splitVal, boost::is_any_of(string("."))); for (size_t i = 0; i < path.size(); i++) @@ -2667,13 +2723,16 @@ AdbInstance *Adb::createLayout(string rootNodeName, bool isExprEval, if (path[i] == "#(parent)" || path[i] == "$(parent)") { curInst = curInst->parent; - if (curInst == NULL || i == path.size()-1) { + if (curInst == NULL || i == path.size() - 1) + { foundSelector = false; if (rootNodeName == rootNode) { // give this warning only if this root instantiation - if (allowMultipleExceptions) cout << "allow multiple"; + if (allowMultipleExceptions) + cout << "allow multiple"; raiseException(allowMultipleExceptions, - "Invalid union selector (" + inst->fullName() + "), must be a leaf field, cannot be a parent of root", + "Invalid union selector (" + inst->fullName() + + "), must be a leaf field, cannot be a parent of root", ExceptionHolder::ERROR_EXCEPTION); } break; @@ -2699,7 +2758,8 @@ AdbInstance *Adb::createLayout(string rootNodeName, bool isExprEval, if (rootNodeName == rootNode) { // give this warning only if this root instantiation raiseException(allowMultipleExceptions, - "Failed to find union selector for union (" + inst->fullName() + ") Can't find field (" + path[i] + ") under (" + curInst->fullName() + ")", + "Failed to find union selector for union (" + inst->fullName() + + ") Can't find field (" + path[i] + ") under (" + curInst->fullName() + ")", ExceptionHolder::ERROR_EXCEPTION); } break; @@ -2707,11 +2767,13 @@ AdbInstance *Adb::createLayout(string rootNodeName, bool isExprEval, } } - if (foundSelector) { + if (foundSelector) + { inst->unionSelector = curInst; for (size_t i = 0; i < inst->subItems.size(); i++) { - //printf("Field %s, isResered=%d\n", inst->subItems[i]->fullName().c_str(), inst->subItems[i]->isReserved()); + // printf("Field %s, isResered=%d\n", inst->subItems[i]->fullName().c_str(), + // inst->subItems[i]->isReserved()); if (inst->subItems[i]->isReserved()) { continue; @@ -2723,8 +2785,9 @@ AdbInstance *Adb::createLayout(string rootNodeName, bool isExprEval, if (!found) { raiseException(allowMultipleExceptions, - "In union (" + inst->fullName() + ") the union subnode (" + inst->subItems[i]->name + ") doesn't define selection value", - ExceptionHolder::ERROR_EXCEPTION); + "In union (" + inst->fullName() + ") the union subnode (" + + inst->subItems[i]->name + ") doesn't define selection value", + ExceptionHolder::ERROR_EXCEPTION); } // make sure that all union subnodes selector values are defined in the selector field enum @@ -2733,11 +2796,11 @@ AdbInstance *Adb::createLayout(string rootNodeName, bool isExprEval, continue; } - if (!inst->unionSelector->isEnumExists()) { - string exceptionTxt = "In union (" + inst->fullName() + ") the union selector (" + inst->unionSelector->fullName() + ") is not an enum"; - raiseException(allowMultipleExceptions, - exceptionTxt, - ExceptionHolder::ERROR_EXCEPTION); + if (!inst->unionSelector->isEnumExists()) + { + string exceptionTxt = "In union (" + inst->fullName() + ") the union selector (" + + inst->unionSelector->fullName() + ") is not an enum"; + raiseException(allowMultipleExceptions, exceptionTxt, ExceptionHolder::ERROR_EXCEPTION); break; } @@ -2751,13 +2814,14 @@ AdbInstance *Adb::createLayout(string rootNodeName, bool isExprEval, } } - //if not found in map throw exeption + // if not found in map throw exeption if (it == selectorValMap.end()) { - string exceptionTxt = "In union (" + inst->fullName() + ") the union subnode (" + inst->subItems[i]->name + ") uses a selector value (" + selectorValIt->second + ") which isn't defined in the selector field (" + inst->unionSelector->fullName() + ")"; - raiseException(allowMultipleExceptions, - exceptionTxt, - ExceptionHolder::ERROR_EXCEPTION); + string exceptionTxt = "In union (" + inst->fullName() + ") the union subnode (" + + inst->subItems[i]->name + ") uses a selector value (" + + selectorValIt->second + ") which isn't defined in the selector field (" + + inst->unionSelector->fullName() + ")"; + raiseException(allowMultipleExceptions, exceptionTxt, ExceptionHolder::ERROR_EXCEPTION); } } } @@ -2770,7 +2834,7 @@ AdbInstance *Adb::createLayout(string rootNodeName, bool isExprEval, } return rootItem; } - catch (AdbException &exp) + catch (AdbException& exp) { _lastError = exp.what_s(); if (allowMultipleExceptions) @@ -2797,7 +2861,7 @@ vector Adb::getNodeDeps(string nodeName) throw AdbException("Can't find node definition for: " + nodeName); } - AdbNode *node = it->second; + AdbNode* node = it->second; vector deps(1, node->name); for (size_t i = 0; i < node->fields.size(); i++) @@ -2818,19 +2882,21 @@ vector Adb::getNodeDeps(string nodeName) /** * Function: Adb::createInstance **/ -vector Adb::createInstance(AdbField *field, - AdbInstance *parent, map vars, bool isExprEval, - int depth, bool ignoreMissingNodes, - bool allowMultipleExceptions) +vector Adb::createInstance(AdbField* field, + AdbInstance* parent, + map vars, + bool isExprEval, + int depth, + bool ignoreMissingNodes, + bool allowMultipleExceptions) { - static const regex EXP_PATTERN( - "\\s*([a-zA-Z0-9_]+)=((\\$\\(.*?\\)|\\S+|$)*)\\s*"); + static const regex EXP_PATTERN("\\s*([a-zA-Z0-9_]+)=((\\$\\(.*?\\)|\\S+|$)*)\\s*"); // if array create instance for each item. else - create 1 - vector instList; + vector instList; for (u_int32_t i = 0; i < field->arrayLen(); i++) { - AdbInstance *inst = new AdbInstance; + AdbInstance* inst = new AdbInstance; inst->fieldDesc = field; // if field is struct - find field->subNode in nodes map and addto instance not desc @@ -2873,7 +2939,8 @@ vector Adb::createInstance(AdbField *field, inst->name += "[" + boost::lexical_cast(i + field->lowBound) + "]"; inst->arrIdx = i; } - //printf("field: %s, offset: %s (%d)\n", inst->name.c_str(),formatAddr(inst->offset, inst->size).c_str(), inst->offset); + // printf("field: %s, offset: %s (%d)\n", inst->name.c_str(),formatAddr(inst->offset, inst->size).c_str(), + // inst->offset); if (isExprEval) { @@ -2883,8 +2950,7 @@ vector Adb::createInstance(AdbField *field, char tmpStr[32]; vars["NAME"] = inst->name; vars["ARR_IDX"] = boost::lexical_cast(inst->arrIdx); - sprintf(tmpStr, "[%d:%d]", inst->offset % 32 + inst->size - 1, - inst->offset % 32); + sprintf(tmpStr, "[%d:%d]", inst->offset % 32 + inst->size - 1, inst->offset % 32); vars["BN"] = tmpStr; vars["parent"] = "#(parent)"; // special internal name @@ -2944,10 +3010,10 @@ vector Adb::createInstance(AdbField *field, } inst->setVarsMap(vars); } - catch (AdbException &exp) + catch (AdbException& exp) { string exceptionTxt = - "Failed to evaluate expression for field (" + inst->fullName() + "): " + exp.what_s(); + "Failed to evaluate expression for field (" + inst->fullName() + "): " + exp.what_s(); if (allowMultipleExceptions) { insertNewException(ExceptionHolder::ERROR_EXCEPTION, exceptionTxt); @@ -2974,14 +3040,15 @@ vector Adb::createInstance(AdbField *field, if (field->isStruct() && !inst->nodeDesc->fields.empty() && (depth == -1 || depth > 0)) { - if (inst->nodeDesc->inLayout) { + if (inst->nodeDesc->inLayout) + { delete inst; raiseException(false, - "Cyclic definition of nodes, node: " + field->name + " was already added to the layout", - ExceptionHolder::ERROR_EXCEPTION); + "Cyclic definition of nodes, node: " + field->name + " was already added to the layout", + ExceptionHolder::ERROR_EXCEPTION); } inst->nodeDesc->inLayout = true; - + // validation 2 if (inst->size != inst->nodeDesc->size) { @@ -2991,49 +3058,56 @@ vector Adb::createInstance(AdbField *field, ") (" + boost::lexical_cast(inst->nodeDesc->size) + ")";*/ } - vector::iterator it; + vector::iterator it; for (it = inst->nodeDesc->fields.begin(); it != inst->nodeDesc->fields.end(); it++) { map varsCopy = vars; - vector subItems = createInstance(*it, inst, vars, - isExprEval, depth == -1 ? -1 : depth - 1, - ignoreMissingNodes, allowMultipleExceptions); - inst->subItems.insert(inst->subItems.end(), subItems.begin(), - subItems.end()); - if (subItems[0]->maxLeafSize > inst->maxLeafSize) { + vector subItems = + createInstance(*it, inst, vars, isExprEval, depth == -1 ? -1 : depth - 1, ignoreMissingNodes, + allowMultipleExceptions); + inst->subItems.insert(inst->subItems.end(), subItems.begin(), subItems.end()); + if (subItems[0]->maxLeafSize > inst->maxLeafSize) + { inst->maxLeafSize = subItems[0]->maxLeafSize; } } inst->nodeDesc->inLayout = false; - if (_checkDsAlign && inst->maxLeafSize != 0 && inst->size % inst->maxLeafSize != 0) { + if (_checkDsAlign && inst->maxLeafSize != 0 && inst->size % inst->maxLeafSize != 0) + { raiseException(allowMultipleExceptions, - "Node: " + inst->nodeDesc->name + " size(" + boost::lexical_cast(inst->size) + ") is not aligned with largest leaf(" + boost::lexical_cast(inst->maxLeafSize) + ")", - ExceptionHolder::ERROR_EXCEPTION); + "Node: " + inst->nodeDesc->name + " size(" + boost::lexical_cast(inst->size) + + ") is not aligned with largest leaf(" + + boost::lexical_cast(inst->maxLeafSize) + ")", + ExceptionHolder::ERROR_EXCEPTION); } if (!inst->isUnion()) { - stable_sort(inst->subItems.begin(), inst->subItems.end(), - compareFieldsPtr); + stable_sort(inst->subItems.begin(), inst->subItems.end(), compareFieldsPtr); for (size_t j = 0; j < inst->subItems.size() - 1; j++) { - //printf("field: %s, offset: %s\n", inst->subItems[j+1]->name.c_str(),formatAddr(inst->subItems[j+1]->offset, inst->subItems[j+1]->size).c_str()); - //printf("field: %s, offset: %s\n", inst->subItems[j]->name.c_str(),formatAddr(inst->subItems[j]->offset, inst->subItems[j]->size).c_str()); + // printf("field: %s, offset: %s\n", + // inst->subItems[j+1]->name.c_str(),formatAddr(inst->subItems[j+1]->offset, + // inst->subItems[j+1]->size).c_str()); printf("field: %s, offset: %s\n", + // inst->subItems[j]->name.c_str(),formatAddr(inst->subItems[j]->offset, + // inst->subItems[j]->size).c_str()); if (inst->subItems[j + 1]->offset < inst->subItems[j]->offset + inst->subItems[j]->size) { - string exceptionTxt = "Field (" + inst->subItems[j + 1]->name + ") (" + formatAddr(inst->subItems[j + 1]->offset, inst->subItems[j + 1]->size).c_str() + ") overlaps with (" + inst->subItems[j]->name + ") (" + formatAddr(inst->subItems[j]->offset, inst->subItems[j]->size).c_str() + ")"; - raiseException(allowMultipleExceptions, - exceptionTxt, - ExceptionHolder::ERROR_EXCEPTION); + string exceptionTxt = + "Field (" + inst->subItems[j + 1]->name + ") (" + + formatAddr(inst->subItems[j + 1]->offset, inst->subItems[j + 1]->size).c_str() + + ") overlaps with (" + inst->subItems[j]->name + ") (" + + formatAddr(inst->subItems[j]->offset, inst->subItems[j]->size).c_str() + ")"; + raiseException(allowMultipleExceptions, exceptionTxt, ExceptionHolder::ERROR_EXCEPTION); } } } } u_int32_t esize = inst->fieldDesc->size; - if ((field->isLeaf() || field->subNode == "uint64") && (esize == 16 || esize == 32 || esize == 64))//A leaf + if ((field->isLeaf() || field->subNode == "uint64") && (esize == 16 || esize == 32 || esize == 64)) // A leaf { inst->maxLeafSize = esize; } @@ -3047,11 +3121,13 @@ vector Adb::createInstance(AdbField *field, /** * Function: Adb::checkInstanceOffsetValidity **/ -void Adb::checkInstanceOffsetValidity(AdbInstance *inst, AdbInstance *parent, bool allowMultipleExceptions) +void Adb::checkInstanceOffsetValidity(AdbInstance* inst, AdbInstance* parent, bool allowMultipleExceptions) { if (inst->offset + inst->size > parent->offset + parent->size) { - string exceptionTxt = "Field (" + inst->name + ") " + formatAddr(inst->offset, inst->size) + " crosses its parent node (" + parent->name + ") " + formatAddr(parent->offset, parent->size) + " boundaries"; + string exceptionTxt = "Field (" + inst->name + ") " + formatAddr(inst->offset, inst->size) + + " crosses its parent node (" + parent->name + ") " + + formatAddr(parent->offset, parent->size) + " boundaries"; if (allowMultipleExceptions) { insertNewException(ExceptionHolder::ERROR_EXCEPTION, exceptionTxt); @@ -3066,8 +3142,7 @@ void Adb::checkInstanceOffsetValidity(AdbInstance *inst, AdbInstance *parent, bo /** * Function: Adb::calcArrOffset **/ -u_int32_t Adb::calcArrOffset(AdbField *fieldDesc, AdbInstance *parent, - u_int32_t arrIdx) +u_int32_t Adb::calcArrOffset(AdbField* fieldDesc, AdbInstance* parent, u_int32_t arrIdx) { int offs; @@ -3105,7 +3180,7 @@ u_int32_t Adb::calcArrOffset(AdbField *fieldDesc, AdbInstance *parent, /** * Function: Adb::evalExpr **/ -string Adb::evalExpr(string expr, AttrsMap *vars) +string Adb::evalExpr(string expr, AttrsMap* vars) { if (expr.find('$') == string::npos) { @@ -3120,7 +3195,7 @@ string Adb::evalExpr(string expr, AttrsMap *vars) string vvalue; regex singleVar("^[a-zA-Z_][a-zA-Z0-9_]*$"); - //Need to change to array-like initialization when we'll move to c++11 + // Need to change to array-like initialization when we'll move to c++11 vector specialVars; specialVars.push_back("NAME"); specialVars.push_back("ARR_IDX"); @@ -3158,49 +3233,48 @@ string Adb::evalExpr(string expr, AttrsMap *vars) } char exp[vname.size() + 1]; - char *expPtr = exp; + char* expPtr = exp; strcpy(exp, vname.c_str()); u_int64_t res; _adbExpr.setVars(vars); int status = _adbExpr.expr(&expPtr, &res); string statusStr; - //printf("-D- Eval expr \"%s\" = %ul.\n", vname.ascii(), (u_int32_t)res); + // printf("-D- Eval expr \"%s\" = %ul.\n", vname.ascii(), (u_int32_t)res); if (status < 0) { switch (status) { - case Expr::ERR_RPAR_EXP: - statusStr = "Right parentheses expected"; - break; + case Expr::ERR_RPAR_EXP: + statusStr = "Right parentheses expected"; + break; - case Expr::ERR_VALUE_EXP: - statusStr = "Value expected"; - break; + case Expr::ERR_VALUE_EXP: + statusStr = "Value expected"; + break; - case Expr::ERR_BIN_EXP: - statusStr = "Binary operation expected "; - break; + case Expr::ERR_BIN_EXP: + statusStr = "Binary operation expected "; + break; - case Expr::ERR_DIV_ZERO: - statusStr = "Divide zero attempt"; - break; + case Expr::ERR_DIV_ZERO: + statusStr = "Divide zero attempt"; + break; - case Expr::ERR_BAD_NUMBER: - statusStr = "Bad constant syntax"; - break; + case Expr::ERR_BAD_NUMBER: + statusStr = "Bad constant syntax"; + break; - case Expr::ERR_BAD_NAME: - statusStr = "Variable Name not resolved"; - break; + case Expr::ERR_BAD_NAME: + statusStr = "Variable Name not resolved"; + break; - default: - statusStr = "Unknown error"; + default: + statusStr = "Unknown error"; } - throw AdbException( - "Error evaluating expression " + expr + " : " + statusStr); + throw AdbException("Error evaluating expression " + expr + " : " + statusStr); } vvalue = boost::lexical_cast(res); @@ -3229,8 +3303,7 @@ bool Adb::checkInstSizeConsistency(bool allowMultipleExceptions) { if (it->second->fields[i]->isStruct()) { - NodesMap::iterator iter = nodesMap.find( - it->second->fields[i]->subNode); + NodesMap::iterator iter = nodesMap.find(it->second->fields[i]->subNode); if (iter == nodesMap.end()) { continue; @@ -3240,18 +3313,14 @@ bool Adb::checkInstSizeConsistency(bool allowMultipleExceptions) return false; */ } - AdbNode *node = nodesMap[it->second->fields[i]->subNode]; + AdbNode* node = nodesMap[it->second->fields[i]->subNode]; if (node->size != it->second->fields[i]->size / it->second->fields[i]->arrayLen()) { char tmp[256]; - sprintf( - tmp, - "Node (%s) size 0x%x.%d is not consistent with the instance (%s->%s) size 0x%x.%d", - node->name.c_str(), (node->size >> 5) << 2, - node->size % 32, it->second->name.c_str(), - it->second->fields[i]->name.c_str(), - (it->second->fields[i]->size >> 5) << 2, - it->second->fields[i]->size % 32); + sprintf(tmp, "Node (%s) size 0x%x.%d is not consistent with the instance (%s->%s) size 0x%x.%d", + node->name.c_str(), (node->size >> 5) << 2, node->size % 32, it->second->name.c_str(), + it->second->fields[i]->name.c_str(), (it->second->fields[i]->size >> 5) << 2, + it->second->fields[i]->size % 32); _lastError = tmp; if (allowMultipleExceptions) { @@ -3287,8 +3356,7 @@ void Adb::print(int indent) for (size_t i = 0; i < includePaths.size(); i++) cout << indentString(indent + 1) << includePaths[i] << endl; - cout << indentString(indent) << "Is Big Endian Arrays: " << bigEndianArr - << endl; + cout << indentString(indent) << "Is Big Endian Arrays: " << bigEndianArr << endl; cout << "-------------------------------------" << endl; cout << indentString(indent) << "Configs: " << endl; for (size_t i = 0; i < configs.size(); i++) diff --git a/adb_parser/adb_parser.h b/adb_parser/adb_parser.h index 5edc4b99..c7af067c 100644 --- a/adb_parser/adb_parser.h +++ b/adb_parser/adb_parser.h @@ -35,8 +35,6 @@ #ifndef ADB_ADB_H #define ADB_ADB_H - - class LogFile; #include @@ -81,7 +79,7 @@ class LogFile; #define LC_ALL_HINT "" #endif -#define PROGRESS_NODE_CNT 100 // each 100 parsed node call progress callback +#define PROGRESS_NODE_CNT 100 // each 100 parsed node call progress callback #ifndef MIN #define MIN(a, b) ((a) < (b) ? (a) : (b)) @@ -90,9 +88,10 @@ class LogFile; #define MAX(a, b) ((a) > (b) ? (a) : (b)) #endif -#define CHECK_RUNTIME_ERROR(e) ((strstr(e.what(), "locale::facet::_S_create_c_locale") != NULL) ? \ - string("Encoding error, please set locale encoding to C") + LC_ALL_HINT + "." : \ - string("runtime_error: ") + e.what()) +#define CHECK_RUNTIME_ERROR(e) \ + ((strstr(e.what(), "locale::facet::_S_create_c_locale") != NULL) ? \ + string("Encoding error, please set locale encoding to C") + LC_ALL_HINT + "." : \ + string("runtime_error: ") + e.what()) using namespace std; @@ -111,7 +110,8 @@ using namespace std; typedef map AttrsMap; typedef vector StringVector; -typedef struct { +typedef struct +{ string fullPath; string includedFromFile; int includedFromLine; @@ -121,7 +121,8 @@ typedef map NodesMap; typedef vector ConfigList; typedef map InstanceAttrs; typedef map ExceptionsMap; -class Adb { +class Adb +{ public: // Methods Adb(); @@ -131,21 +132,31 @@ class Adb { // 1- dwrod aligned unions // 2- contains nodes only // 3- check node size vs instance size - bool loadFromString(const char *adbContents, bool addReserved = false, - bool strict = true, - bool enforceExtraChecks = false); - bool load(string fname, bool addReserved = false, - bool strict = true, - string includePath = "", string includeDir = "", - bool enforceExtraChecks = false, bool getAllExceptions = false, - string logFile = "", bool checkDsAlign = false, bool enforceGuiChecks = false); - string toXml(vector nodeNames = vector (), - bool addRootNode = false, string rootName = "MainNode", - string addPrefix = ""); + bool loadFromString(const char* adbContents, + bool addReserved = false, + bool strict = true, + bool enforceExtraChecks = false); + bool load(string fname, + bool addReserved = false, + bool strict = true, + string includePath = "", + string includeDir = "", + bool enforceExtraChecks = false, + bool getAllExceptions = false, + string logFile = "", + bool checkDsAlign = false, + bool enforceGuiChecks = false); + string toXml(vector nodeNames = vector(), + bool addRootNode = false, + string rootName = "MainNode", + string addPrefix = ""); AdbInstance* addMissingNodes(int depth, bool allowMultipleExceptions); - AdbInstance* createLayout(string rootNodeName, bool isExprEval = false, int depth = -1, /* -1 means instantiate full tree */ - bool ignoreMissingNodes = false, bool getAllExceptions = false); + AdbInstance* createLayout(string rootNodeName, + bool isExprEval = false, + int depth = -1, /* -1 means instantiate full tree */ + bool ignoreMissingNodes = false, + bool getAllExceptions = false); vector getNodeDeps(string nodeName); string getLastError(); @@ -177,14 +188,17 @@ class Adb { IncludeFileMap includedFiles; StringVector warnings; ExceptionsMap adbExceptionMap; + private: - vector createInstance(AdbField *fieldDesc, - AdbInstance *parent, map vars, bool isExprEval, - int depth, - bool ignoreMissingNodes = false, bool getAllExceptions = false); - u_int32_t calcArrOffset(AdbField *fieldDesc, AdbInstance *parent, - u_int32_t arrIdx); - string evalExpr(string expr, AttrsMap *vars); + vector createInstance(AdbField* fieldDesc, + AdbInstance* parent, + map vars, + bool isExprEval, + int depth, + bool ignoreMissingNodes = false, + bool getAllExceptions = false); + u_int32_t calcArrOffset(AdbField* fieldDesc, AdbInstance* parent, u_int32_t arrIdx); + string evalExpr(string expr, AttrsMap* vars); bool checkInstSizeConsistency(bool getAllExceptions = false); void cleanInstAttrs(); @@ -194,7 +208,7 @@ class Adb { bool _checkDsAlign; bool _enforceGuiChecks; list _unionSelectorEvalDeffered; - void checkInstanceOffsetValidity(AdbInstance *inst, AdbInstance *parent, bool allowMultipleExceptions); + void checkInstanceOffsetValidity(AdbInstance* inst, AdbInstance* parent, bool allowMultipleExceptions); void throwExeption(bool allowMultipleExceptions, string exceptionTxt, string addedMsgMultiExp); }; diff --git a/adb_parser/adb_xmlCreator.cpp b/adb_parser/adb_xmlCreator.cpp index cacbd53a..5af0d5bc 100644 --- a/adb_parser/adb_xmlCreator.cpp +++ b/adb_parser/adb_xmlCreator.cpp @@ -40,34 +40,34 @@ string xmlCreator::indentString(int i) { - string s; - while (i--) - { - s += "\t"; - } - return s; + string s; + while (i--) + { + s += "\t"; + } + return s; } int xmlCreator::dword(int bits) { - if (bits < 0) - { - bits -= 31; - } + if (bits < 0) + { + bits -= 31; + } - return (bits / 32) * 4; + return (bits / 32) * 4; } int xmlCreator::startBit(int bits) { - return bits % 32; + return bits % 32; } string xmlCreator::formatAddr(u_int32_t offs, u_int32_t size) { - char str[64]; - sprintf(str, "0x%x.%u:%u", dword(offs), startBit(offs), size); - return str; + char str[64]; + sprintf(str, "0x%x.%u:%u", dword(offs), startBit(offs), size); + return str; } /*template @@ -76,44 +76,44 @@ bool xmlCreator::compareFieldsPtr(AdbInstance *f1, AdbInstance *f2) return (*f1) < (*f2); }*/ -string xmlCreator::encodeXml(const string &data) +string xmlCreator::encodeXml(const string& data) { - std::string buffer; - buffer.reserve(data.size()); - for (size_t pos = 0; pos != data.size(); ++pos) - { - switch (data[pos]) + std::string buffer; + buffer.reserve(data.size()); + for (size_t pos = 0; pos != data.size(); ++pos) { - case '&': - buffer.append("&"); - break; + switch (data[pos]) + { + case '&': + buffer.append("&"); + break; - case '\"': - buffer.append("""); - break; + case '\"': + buffer.append("""); + break; - case '\'': - buffer.append("'"); - break; + case '\'': + buffer.append("'"); + break; - case '<': - buffer.append("<"); - break; + case '<': + buffer.append("<"); + break; - case '>': - buffer.append(">"); - break; + case '>': + buffer.append(">"); + break; - default: - buffer.append(1, data.at(pos)); - break; + default: + buffer.append(1, data.at(pos)); + break; + } } - } - return buffer; + return buffer; } -string xmlCreator::descNativeToXml(const string &desc) +string xmlCreator::descNativeToXml(const string& desc) { - return boost::replace_all_copy(desc, "\n", "\\;"); + return boost::replace_all_copy(desc, "\n", "\\;"); } diff --git a/adb_parser/adb_xmlCreator.h b/adb_parser/adb_xmlCreator.h index 3fc95e04..8721912f 100644 --- a/adb_parser/adb_xmlCreator.h +++ b/adb_parser/adb_xmlCreator.h @@ -32,7 +32,6 @@ * */ - #ifndef xmlCreator_H #define xmlCreator_H @@ -43,20 +42,19 @@ using namespace std; namespace xmlCreator { - - template - bool compareFieldsPtr(T *f1, T *f2); - string indentString(int i); - int dword(int bits); - int startBit(int bits); - string formatAddr(u_int32_t offs, u_int32_t size); - string encodeXml(const string &data); - string descNativeToXml(const string &desc); - -} - -template -bool xmlCreator::compareFieldsPtr(T *f1, T *f2) +template +bool compareFieldsPtr(T* f1, T* f2); +string indentString(int i); +int dword(int bits); +int startBit(int bits); +string formatAddr(u_int32_t offs, u_int32_t size); +string encodeXml(const string& data); +string descNativeToXml(const string& desc); + +} // namespace xmlCreator + +template +bool xmlCreator::compareFieldsPtr(T* f1, T* f2) { return (*f1) < (*f2); } diff --git a/adb_parser/buf_ops.cpp b/adb_parser/buf_ops.cpp index f951d285..38ff070f 100644 --- a/adb_parser/buf_ops.cpp +++ b/adb_parser/buf_ops.cpp @@ -36,83 +36,95 @@ #include "buf_ops.h" /************************************ -* Function: calc_array_field_address -************************************/ -static u_int32_t calc_array_field_address(u_int32_t start_bit_offset, u_int32_t arr_elemnt_size, - int arr_idx, u_int32_t parent_node_size, + * Function: calc_array_field_address + ************************************/ +static u_int32_t calc_array_field_address(u_int32_t start_bit_offset, + u_int32_t arr_elemnt_size, + int arr_idx, + u_int32_t parent_node_size, int is_big_endian_arr) { u_int32_t offs; - if (arr_elemnt_size > 32) { + if (arr_elemnt_size > 32) + { assert(!(arr_elemnt_size % 32)); start_bit_offset += arr_elemnt_size * arr_idx; return start_bit_offset; } - if (is_big_endian_arr) { + if (is_big_endian_arr) + { u_int32_t dword_delta; offs = start_bit_offset - arr_elemnt_size * arr_idx; dword_delta = (((start_bit_offset >> 5) << 2) - ((offs >> 5) << 2)) / 4; - if (dword_delta) { + if (dword_delta) + { offs += 64 * dword_delta; } - } else { + } + else + { offs = start_bit_offset + arr_elemnt_size * arr_idx; } - //printf("==> parent_node_size=%d, offs=%d, arr_elemnt_size=%d\n", parent_node_size, offs, arr_elemnt_size); + // printf("==> parent_node_size=%d, offs=%d, arr_elemnt_size=%d\n", parent_node_size, offs, arr_elemnt_size); return TOOLS_MIN(32, parent_node_size) - (offs % 32) - arr_elemnt_size + ((offs >> 5) << 5); } /************************************ -* Function: push_integer_to_buff -************************************/ -static void push_integer_to_buff(u_int8_t *buff, u_int32_t bit_offset, u_int32_t byte_size, u_int64_t field_value) + * Function: push_integer_to_buff + ************************************/ +static void push_integer_to_buff(u_int8_t* buff, u_int32_t bit_offset, u_int32_t byte_size, u_int64_t field_value) { field_value = CPU_TO_BE64(field_value); memcpy(buff + bit_offset / 8, (u_int8_t*)&field_value + (8 - byte_size), byte_size); } /************************************ -* Function: push_bits_to_buff -************************************/ -//the next function will push the field into the buffer by inserting it's MSB bits first -//and therefore by doing it we save the CPU_TO_BE operation -static void push_bits_to_buff(u_int8_t *buff, u_int32_t bit_offset, u_int32_t field_size, u_int32_t field_value) + * Function: push_bits_to_buff + ************************************/ +// the next function will push the field into the buffer by inserting it's MSB bits first +// and therefore by doing it we save the CPU_TO_BE operation +static void push_bits_to_buff(u_int8_t* buff, u_int32_t bit_offset, u_int32_t field_size, u_int32_t field_value) { - u_int32_t i = 0; - u_int32_t byte_n = bit_offset / 8; + u_int32_t i = 0; + u_int32_t byte_n = bit_offset / 8; u_int32_t byte_n_offset = bit_offset % 8; u_int32_t to_push; - //going over all bits in field - while (i < field_size) { + // going over all bits in field + while (i < field_size) + { to_push = TOOLS_MIN(8 - byte_n_offset, field_size - i); i += to_push; - BYTE_N(buff, byte_n) = INSERTF(BYTE_N(buff, byte_n), 8 - to_push - byte_n_offset, field_value, field_size - i, to_push); - byte_n_offset = 0; //(byte_n_offset + to_push) % 8; + BYTE_N(buff, byte_n) = + INSERTF(BYTE_N(buff, byte_n), 8 - to_push - byte_n_offset, field_value, field_size - i, to_push); + byte_n_offset = 0; //(byte_n_offset + to_push) % 8; byte_n++; } } /************************************ -* Function: push_to_buf -************************************/ -void push_to_buf(u_int8_t *buff, u_int32_t bit_offset, u_int32_t field_size, u_int64_t field_value) + * Function: push_to_buf + ************************************/ +void push_to_buf(u_int8_t* buff, u_int32_t bit_offset, u_int32_t field_size, u_int64_t field_value) { bit_offset = calc_array_field_address(bit_offset, field_size, 0, field_size + 32, 0); - if (field_size <= 32) { + if (field_size <= 32) + { push_bits_to_buff(buff, bit_offset, field_size, field_value); - } else { - push_integer_to_buff(buff, bit_offset, field_size / 8, field_value); + } + else + { + push_integer_to_buff(buff, bit_offset, field_size / 8, field_value); } } /************************************ -* Function: pop_integer_from_buff -************************************/ -static u_int64_t pop_integer_from_buff(const u_int8_t *buff, u_int32_t bit_offset, u_int32_t byte_size) + * Function: pop_integer_from_buff + ************************************/ +static u_int64_t pop_integer_from_buff(const u_int8_t* buff, u_int32_t bit_offset, u_int32_t byte_size) { u_int64_t val = 0; memcpy((u_int8_t*)&val + (8 - byte_size), buff + bit_offset / 8, byte_size); @@ -120,24 +132,25 @@ static u_int64_t pop_integer_from_buff(const u_int8_t *buff, u_int32_t bit_offse } /************************************ -* Function: pop_bits_from_buff -************************************/ -//the next function will pop the field into the buffer by removing it's MSB bits first -//and therefore by doing it we save the BE_TO_CPU operation -static u_int32_t pop_bits_from_buff(const u_int8_t *buff, u_int32_t bit_offset, u_int32_t field_size) + * Function: pop_bits_from_buff + ************************************/ +// the next function will pop the field into the buffer by removing it's MSB bits first +// and therefore by doing it we save the BE_TO_CPU operation +static u_int32_t pop_bits_from_buff(const u_int8_t* buff, u_int32_t bit_offset, u_int32_t field_size) { - u_int32_t i = 0; - u_int32_t byte_n = bit_offset / 8; + u_int32_t i = 0; + u_int32_t byte_n = bit_offset / 8; u_int32_t byte_n_offset = bit_offset % 8; - u_int32_t field_32 = 0; + u_int32_t field_32 = 0; u_int32_t to_pop; - //going over all bits in field - while (i < field_size) { - to_pop = TOOLS_MIN(8 - byte_n_offset, field_size - i); + // going over all bits in field + while (i < field_size) + { + to_pop = TOOLS_MIN(8 - byte_n_offset, field_size - i); i += to_pop; field_32 = INSERTF(field_32, field_size - i, BYTE_N(buff, byte_n), 8 - to_pop - byte_n_offset, to_pop); - byte_n_offset = 0; //(byte_n_offset + to_pop) % 8; + byte_n_offset = 0; //(byte_n_offset + to_pop) % 8; byte_n++; } @@ -145,40 +158,46 @@ static u_int32_t pop_bits_from_buff(const u_int8_t *buff, u_int32_t bit_offset, } /************************************ -* Function: pop_from_buf -************************************/ -u_int64_t pop_from_buf(const u_int8_t *buff, u_int32_t bit_offset, u_int32_t field_size) + * Function: pop_from_buf + ************************************/ +u_int64_t pop_from_buf(const u_int8_t* buff, u_int32_t bit_offset, u_int32_t field_size) { bit_offset = calc_array_field_address(bit_offset, field_size, 0, field_size + 32, 0); - if (field_size <= 32) { + if (field_size <= 32) + { return pop_bits_from_buff(buff, bit_offset, field_size); - } else { + } + else + { return pop_integer_from_buff(buff, bit_offset, field_size / 8); } } /************************************ -* Function: add_indentation -************************************/ -static void add_indentation(FILE *file, int indent_level) + * Function: add_indentation + ************************************/ +static void add_indentation(FILE* file, int indent_level) { - while (indent_level) { + while (indent_level) + { fprintf(file, "\\t"); indent_level--; } } /************************************ -* Function: print_raw -************************************/ -void print_raw(FILE *file, void *buff, int buff_len) + * Function: print_raw + ************************************/ +void print_raw(FILE* file, void* buff, int buff_len) { - u_int8_t *data = (u_int8_t*)buff; + u_int8_t* data = (u_int8_t*)buff; int i; add_indentation(file, 0); - for (i = 0; i < buff_len; i++) { - if (!(i % 4)) { + for (i = 0; i < buff_len; i++) + { + if (!(i % 4)) + { fprintf(file, "\n0x%08x: ", i); } diff --git a/adb_parser/buf_ops.h b/adb_parser/buf_ops.h index 5ebf05c2..3d9c08f0 100644 --- a/adb_parser/buf_ops.h +++ b/adb_parser/buf_ops.h @@ -47,7 +47,7 @@ /************************************/ /************************************/ /************************************/ -void print_raw(FILE *file, void *buff, int buff_len); -u_int64_t pop_from_buf(const u_int8_t *buff, u_int32_t bit_offset, u_int32_t field_size); -void push_to_buf(u_int8_t *buff, u_int32_t bit_offset, u_int32_t field_size, u_int64_t field_value); +void print_raw(FILE* file, void* buff, int buff_len); +u_int64_t pop_from_buf(const u_int8_t* buff, u_int32_t bit_offset, u_int32_t field_size); +void push_to_buf(u_int8_t* buff, u_int32_t bit_offset, u_int32_t field_size, u_int64_t field_value); #endif // BIT_OPS_H diff --git a/adb_parser/expr.cpp b/adb_parser/expr.cpp index bf1d73a2..c63c3546 100644 --- a/adb_parser/expr.cpp +++ b/adb_parser/expr.cpp @@ -38,9 +38,8 @@ #include #include "expr.h" - -char*Expr::str; -char*Expr::initial_arg; +char* Expr::str; +char* Expr::initial_arg; Expr::status Expr::state; /* @@ -51,51 +50,51 @@ Expr::status Expr::state; /* * Unary prefixes which present radix */ -#define RADIX16 "0x" -#define RADIX2 "0b" +#define RADIX16 "0x" +#define RADIX2 "0b" /* * Unary operations */ -#define ULOGNOT 71 /* ! */ -#define UMINUS 72 /* - */ -#define UNOT 73 /* ~ */ -#define UPLUS 74 /* + */ -#define U2POW 75 /* : */ -#define U2POW_ALT 76 /* POW2 */ -#define ULOG2 77 /* ' */ -#define ULOG2_ALT 78 /* LOG2 */ -#define SWAP32 79 /* SWAP32 */ -#define SWAP16 80 /* SWAP16 */ +#define ULOGNOT 71 /* ! */ +#define UMINUS 72 /* - */ +#define UNOT 73 /* ~ */ +#define UPLUS 74 /* + */ +#define U2POW 75 /* : */ +#define U2POW_ALT 76 /* POW2 */ +#define ULOG2 77 /* ' */ +#define ULOG2_ALT 78 /* LOG2 */ +#define SWAP32 79 /* SWAP32 */ +#define SWAP16 80 /* SWAP16 */ /* * Binary operations */ -#define AND 1 /* && */ -#define BIT_AND 2 /* & */ -#define BIT_OR 3 /* | */ -#define BIT_XOR 4 /* ^ */ -#define DIVID 5 /* / */ -#define EQ 6 /* == */ -#define GREAT 7 /* > */ -#define GREAT_EQ 8 /* >= */ -#define LESS 9 /* < */ -#define LESS_EQ 10 /* <= */ -#define MINUS 11 /* - */ -#define MODUL 12 /* % */ -#define MULT 13 /* * */ -#define NOTEQ 14 /* != */ -#define OR 15 /* || */ -#define PLUS 16 /* + */ -#define SHIFT_L 17 /* << */ -#define SHIFT_R 18 /* >> */ -#define XOR 19 /* log.xor*/ +#define AND 1 /* && */ +#define BIT_AND 2 /* & */ +#define BIT_OR 3 /* | */ +#define BIT_XOR 4 /* ^ */ +#define DIVID 5 /* / */ +#define EQ 6 /* == */ +#define GREAT 7 /* > */ +#define GREAT_EQ 8 /* >= */ +#define LESS 9 /* < */ +#define LESS_EQ 10 /* <= */ +#define MINUS 11 /* - */ +#define MODUL 12 /* % */ +#define MULT 13 /* * */ +#define NOTEQ 14 /* != */ +#define OR 15 /* || */ +#define PLUS 16 /* + */ +#define SHIFT_L 17 /* << */ +#define SHIFT_R 18 /* >> */ +#define XOR 19 /* log.xor*/ /* * Other token types */ -#define VALUE 103 /* Name or constant */ -#define EXPR_OK 0 /* Expression getted successfully */ +#define VALUE 103 /* Name or constant */ +#define EXPR_OK 0 /* Expression getted successfully */ /* * Miscellaneous constant @@ -103,146 +102,112 @@ Expr::status Expr::state; #ifdef IGNORE #undef IGNORE #endif -#define IGNORE " \t\n\r" /* Ignore in parsing */ -#define HIGH_PRI 1 -#define LOW_PRI 9 +#define IGNORE " \t\n\r" /* Ignore in parsing */ +#define HIGH_PRI 1 +#define LOW_PRI 9 /* * Unary operations. Priority not applicable, * all unary operations have same priority. */ -static Expr::table unar[] = { - { U2POW, 0, ":" }, - { U2POW_ALT, 0, "POW2" }, - { ULOG2, 0, "'" }, - { ULOG2_ALT, 0, "LOG2" }, - { ULOGNOT, 0, "!" }, - { UMINUS, 0, "-" }, - { UNOT, 0, "~" }, - { UPLUS, 0, "+" }, - { SWAP32, 0, "SWAP32" }, - { SWAP16, 0, "SWAP16" } -}; +static Expr::table unar[] = {{U2POW, 0, ":"}, {U2POW_ALT, 0, "POW2"}, {ULOG2, 0, "'"}, {ULOG2_ALT, 0, "LOG2"}, + {ULOGNOT, 0, "!"}, {UMINUS, 0, "-"}, {UNOT, 0, "~"}, {UPLUS, 0, "+"}, + {SWAP32, 0, "SWAP32"}, {SWAP16, 0, "SWAP16"}}; static int Lunar = numbel(unar); /* * Binary operations. */ static Expr::table binar[] = { - { MODUL, 1, "%" }, - { MULT, 1, "*" }, - { DIVID, 1, "/" }, - { PLUS, 2, "+" }, - { MINUS, 2, "-" }, - { SHIFT_L, 3, "<<" }, - { SHIFT_L, 3, "SHIFT_L" }, - { SHIFT_R, 3, ">>" }, - { SHIFT_R, 3, "SHIFT_R" }, - { GREAT, 4, ">" }, - { GREAT, 4, "GREAT" }, - { GREAT_EQ, 4, ">=" }, - { GREAT_EQ, 4, "GREAT_EQ" }, - { LESS, 4, "<" }, - { LESS, 4, "LESS" }, - { LESS_EQ, 4, "<=" }, - { LESS_EQ, 4, "LESS_EQ" }, - { EQ, 5, "==" }, - { EQ, 5, "EQ" }, - { NOTEQ, 5, "!=" }, - { NOTEQ, 5, "NOTEQ" }, - { BIT_AND, 6, "&" }, - { BIT_AND, 6, "BIT_AND" }, - { BIT_OR, 7, "|" }, - { BIT_OR, 7, "BIT_OR" }, - { BIT_XOR, 7, "^" }, - { BIT_XOR, 7, "BIT_XOR" }, - { AND, 8, "&&" }, - { AND, 8, "AND" }, - { OR, 9, "||" }, - { OR, 9, "OR" }, - { XOR, 9, "XOR" } -}; + {MODUL, 1, "%"}, {MULT, 1, "*"}, {DIVID, 1, "/"}, {PLUS, 2, "+"}, + {MINUS, 2, "-"}, {SHIFT_L, 3, "<<"}, {SHIFT_L, 3, "SHIFT_L"}, {SHIFT_R, 3, ">>"}, + {SHIFT_R, 3, "SHIFT_R"}, {GREAT, 4, ">"}, {GREAT, 4, "GREAT"}, {GREAT_EQ, 4, ">="}, + {GREAT_EQ, 4, "GREAT_EQ"}, {LESS, 4, "<"}, {LESS, 4, "LESS"}, {LESS_EQ, 4, "<="}, + {LESS_EQ, 4, "LESS_EQ"}, {EQ, 5, "=="}, {EQ, 5, "EQ"}, {NOTEQ, 5, "!="}, + {NOTEQ, 5, "NOTEQ"}, {BIT_AND, 6, "&"}, {BIT_AND, 6, "BIT_AND"}, {BIT_OR, 7, "|"}, + {BIT_OR, 7, "BIT_OR"}, {BIT_XOR, 7, "^"}, {BIT_XOR, 7, "BIT_XOR"}, {AND, 8, "&&"}, + {AND, 8, "AND"}, {OR, 9, "||"}, {OR, 9, "OR"}, {XOR, 9, "XOR"}}; static int Lbinar = numbel(binar); - /******************************************************** -* routine: expr -* -* description: -* Main routine for expression evaluation. Do some interface -* functions and call binary operation evaluation with lowest -* priority. -* -* arguments: -* pstr pointer to string which contains expression to -* evaluation. After successfully evaluation expr -* moves this pointer to end of expression (first -* unparsed character). -* result pointer to unsigned long to put result of expression. -* dr default radix for numbers. -* ErrorRep pointer to callbeck routine for error reporting. -* arguments - like printf. -* -* return code: -* >0 length of evaluated expression. -* <0 error code, one of following: -* ERR_RPAR_EXP - Right parentheses expected. -* ERR_VALUE_EXP - Value expected. -* ERR_BIN_EXP - Binary operation expected. It is a normal situation -* on experssion end. -* ERR_DIV_ZERO - Divide zero attempt. -* ERR_BAD_NUMBER - Bad constant syntax. -* ERR_BAD_NAME - Name not found in symbol table. -* -********************************************************/ -int Expr::expr(char **pstr, u_int64_t *result) + * routine: expr + * + * description: + * Main routine for expression evaluation. Do some interface + * functions and call binary operation evaluation with lowest + * priority. + * + * arguments: + * pstr pointer to string which contains expression to + * evaluation. After successfully evaluation expr + * moves this pointer to end of expression (first + * unparsed character). + * result pointer to unsigned long to put result of expression. + * dr default radix for numbers. + * ErrorRep pointer to callbeck routine for error reporting. + * arguments - like printf. + * + * return code: + * >0 length of evaluated expression. + * <0 error code, one of following: + * ERR_RPAR_EXP - Right parentheses expected. + * ERR_VALUE_EXP - Value expected. + * ERR_BIN_EXP - Binary operation expected. It is a normal situation + * on experssion end. + * ERR_DIV_ZERO - Divide zero attempt. + * ERR_BAD_NUMBER - Bad constant syntax. + * ERR_BAD_NAME - Name not found in symbol table. + * + ********************************************************/ +int Expr::expr(char** pstr, u_int64_t* result) { int rc = 0; int len = 0; - str = *pstr; + str = *pstr; initial_arg = *pstr; - state = was_bin; + state = was_bin; /* Operation(s) found, do really evaluation. */ rc = GetBinaryOp(result, LOW_PRI); - if (rc == EXPR_OK || - rc == ERR_BIN_EXP) { + if (rc == EXPR_OK || rc == ERR_BIN_EXP) + { len = (int)(str - *pstr); *pstr = str; return len; - } else { + } + else + { return rc; } } - /******************************************************** -* routine: GetBinaryOp -* -* description: -* Executes binary operations with current priority level. -* If priority great then constant HIGH_PRI, calls itself -* recursive with decreased priority to get operands for -* expression, otherwise calls GetUnaryOp to get operands. -* -* arguments: -* val Pointer to unsigned long where result of -* operation will be placed. -* priority Execute operation only with this priority -* -* return code: -* EXPR_OK Binary operation was calculated successfully -* ERR_DIV_ZERO Zero divide attempt -* otherwise Error code from GetUnaryOp (see) -* -* side effects: -* Attention, deep recursion... -* -********************************************************/ -int Expr::GetBinaryOp(u_int64_t *val, int priority) + * routine: GetBinaryOp + * + * description: + * Executes binary operations with current priority level. + * If priority great then constant HIGH_PRI, calls itself + * recursive with decreased priority to get operands for + * expression, otherwise calls GetUnaryOp to get operands. + * + * arguments: + * val Pointer to unsigned long where result of + * operation will be placed. + * priority Execute operation only with this priority + * + * return code: + * EXPR_OK Binary operation was calculated successfully + * ERR_DIV_ZERO Zero divide attempt + * otherwise Error code from GetUnaryOp (see) + * + * side effects: + * Attention, deep recursion... + * + ********************************************************/ +int Expr::GetBinaryOp(u_int64_t* val, int priority) { - char *str_old; + char* str_old; int rc = 0; int i = 0; u_int64_t left = 0; @@ -250,21 +215,24 @@ int Expr::GetBinaryOp(u_int64_t *val, int priority) token curr; status stat_old; - rc = priority > HIGH_PRI ? GetBinaryOp(&left, priority - 1) : - GetUnaryOp(&left); - if (rc != EXPR_OK) { + rc = priority > HIGH_PRI ? GetBinaryOp(&left, priority - 1) : GetUnaryOp(&left); + if (rc != EXPR_OK) + { return rc; } - for (;;) { + for (;;) + { str_old = str; stat_old = state; GetToken(&curr); - for (i = 0; i < Lbinar; i++) { - if (binar[i].type == curr.type && binar[i].pri == priority) { - rc = priority > HIGH_PRI ? GetBinaryOp(&right, priority - 1) : - GetUnaryOp(&right); - if (rc != EXPR_OK) { + for (i = 0; i < Lbinar; i++) + { + if (binar[i].type == curr.type && binar[i].pri == priority) + { + rc = priority > HIGH_PRI ? GetBinaryOp(&right, priority - 1) : GetUnaryOp(&right); + if (rc != EXPR_OK) + { str = str_old; state = stat_old; return rc; @@ -272,94 +240,97 @@ int Expr::GetBinaryOp(u_int64_t *val, int priority) switch (curr.type) { - case MODUL: - if (right == 0) { - ErrorReport("Zero modulo attempt.\n"); - return ERR_DIV_ZERO; - } - left = left % right; - break; - - case MULT: - left = left * right; - break; - - case DIVID: - if (right == 0) { - ErrorReport("Zero divide attempt.\n"); - return ERR_DIV_ZERO; - } - left = left / right; - break; - - case PLUS: - left = left + right; - break; - - case MINUS: - left = left - right; - break; - - case SHIFT_L: - left = (left << (int)right); - break; - - case SHIFT_R: - left = (left >> (int)right); - break; - - case GREAT: - left = (left > right); - break; - - case GREAT_EQ: - left = (left >= right); - break; - - case LESS: - left = (left < right); - break; - - case LESS_EQ: - left = (left <= right); - break; - - case EQ: - left = (left == right); - break; - - case NOTEQ: - left = (left != right); - break; - - case BIT_AND: - left = left & right; - break; - - case BIT_OR: - left = left | right; - break; - - case BIT_XOR: - left = left ^ right; - break; - - case AND: - left = (left && right); - break; - - case OR: - left = (left || right); - break; - - case XOR: - left = (left && !right) || (!left && right); - break; + case MODUL: + if (right == 0) + { + ErrorReport("Zero modulo attempt.\n"); + return ERR_DIV_ZERO; + } + left = left % right; + break; + + case MULT: + left = left * right; + break; + + case DIVID: + if (right == 0) + { + ErrorReport("Zero divide attempt.\n"); + return ERR_DIV_ZERO; + } + left = left / right; + break; + + case PLUS: + left = left + right; + break; + + case MINUS: + left = left - right; + break; + + case SHIFT_L: + left = (left << (int)right); + break; + + case SHIFT_R: + left = (left >> (int)right); + break; + + case GREAT: + left = (left > right); + break; + + case GREAT_EQ: + left = (left >= right); + break; + + case LESS: + left = (left < right); + break; + + case LESS_EQ: + left = (left <= right); + break; + + case EQ: + left = (left == right); + break; + + case NOTEQ: + left = (left != right); + break; + + case BIT_AND: + left = left & right; + break; + + case BIT_OR: + left = left | right; + break; + + case BIT_XOR: + left = left ^ right; + break; + + case AND: + left = (left && right); + break; + + case OR: + left = (left || right); + break; + + case XOR: + left = (left && !right) || (!left && right); + break; } break; } } - if (i >= Lbinar) { + if (i >= Lbinar) + { UngetToken(curr); *val = left; return EXPR_OK; @@ -367,23 +338,22 @@ int Expr::GetBinaryOp(u_int64_t *val, int priority) } } - /******************************************************** -* routine: GetUnaryOp -* -* description: -* Executes unary operations. -* -* arguments: -* val Pointer to unsigned long where result of -* operation will be placed. -* -* return code: -* EXPR_OK Binary operation was calculated successfully -* otherwise Error code from GetToken (see) -* -********************************************************/ -int Expr::GetUnaryOp(u_int64_t *val) + * routine: GetUnaryOp + * + * description: + * Executes unary operations. + * + * arguments: + * val Pointer to unsigned long where result of + * operation will be placed. + * + * return code: + * EXPR_OK Binary operation was calculated successfully + * otherwise Error code from GetToken (see) + * + ********************************************************/ +int Expr::GetUnaryOp(u_int64_t* val) { int rc, unary_op; u_int64_t tmp = 0; @@ -394,112 +364,110 @@ int Expr::GetUnaryOp(u_int64_t *val) GetToken(&curr); switch (unary_op = curr.type) { - case U2POW: - case U2POW_ALT: - case ULOG2: - case ULOG2_ALT: - case ULOGNOT: - case UMINUS: - case UNOT: - case UPLUS: - case SWAP32: - case SWAP16: - /* - * Was unary operation - retrieve more token. - */ - rc = GetUnaryOp(val); - if (rc != EXPR_OK) { - return rc; - } - - /* OK, execute required unary operation. */ - switch (unary_op) - { - case U2POW_ALT: case U2POW: - *val = (u_int64_t)1 << (int)(*val); - break; - - case ULOG2_ALT: + case U2POW_ALT: case ULOG2: - if (*val != 0) { - for (tmp = 1, tmp1 = 0; tmp < *val; tmp = tmp << 1) - ++tmp1; - *val = tmp1; + case ULOG2_ALT: + case ULOGNOT: + case UMINUS: + case UNOT: + case UPLUS: + case SWAP32: + case SWAP16: + /* + * Was unary operation - retrieve more token. + */ + rc = GetUnaryOp(val); + if (rc != EXPR_OK) + { + return rc; } - break; - case ULOGNOT: - *val = !(*val); - break; + /* OK, execute required unary operation. */ + switch (unary_op) + { + case U2POW_ALT: + case U2POW: + *val = (u_int64_t)1 << (int)(*val); + break; - case UMINUS: - *val = (u_int64_t)(-((int64_t)(*val))); - break; + case ULOG2_ALT: + case ULOG2: + if (*val != 0) + { + for (tmp = 1, tmp1 = 0; tmp < *val; tmp = tmp << 1) + ++tmp1; + *val = tmp1; + } + break; - case UNOT: - *val = ~(*val); - break; + case ULOGNOT: + *val = !(*val); + break; - case UPLUS: - break; + case UMINUS: + *val = (u_int64_t)(-((int64_t)(*val))); + break; - case SWAP32: - *val = ((tmpVal & 0x000000FFUL) << 24) | - ((tmpVal & 0x0000FF00UL) << 8) | - ((tmpVal & 0x00FF0000UL) >> 8) | - ((tmpVal & 0xFF000000UL) >> 24); - break; + case UNOT: + *val = ~(*val); + break; - case SWAP16: - *val = ((tmpVal & 0xFF000000U) >> 8) | - ((tmpVal & 0x00FF0000U) << 8) | - ((tmpVal & 0x0000FF00U) >> 8) | - ((tmpVal & 0x000000FFU) << 8); + case UPLUS: + break; + + case SWAP32: + *val = ((tmpVal & 0x000000FFUL) << 24) | ((tmpVal & 0x0000FF00UL) << 8) | + ((tmpVal & 0x00FF0000UL) >> 8) | ((tmpVal & 0xFF000000UL) >> 24); + break; + + case SWAP16: + *val = ((tmpVal & 0xFF000000U) >> 8) | ((tmpVal & 0x00FF0000U) << 8) | + ((tmpVal & 0x0000FF00U) >> 8) | ((tmpVal & 0x000000FFU) << 8); + break; + } break; - } - break; - case VALUE: - /* - * Unary operation is omitted. Assume no unary operations. - */ - *val = curr.value; - break; + case VALUE: + /* + * Unary operation is omitted. Assume no unary operations. + */ + *val = curr.value; + break; - default: - /* - * Here we expect only unary operation or value. - * Something other - error. Bring error code witch - * present by curr.type to caller. - */ - UngetToken(curr); - return curr.type; + default: + /* + * Here we expect only unary operation or value. + * Something other - error. Bring error code witch + * present by curr.type to caller. + */ + UngetToken(curr); + return curr.type; } return EXPR_OK; } /******************************************************** -* routine: GetToken -* -* description: -* Gets next token from static pointer str. -* -* arguments: -* pt pointer to token. GetToken fills in all -* field by this pointer. -* -* return code: -* None -* -* side effects: -* 1. May insrease pointer str (if token getted successfully). -* 2. May change static variable state (if token getted -* successfully and state was changed). -* -********************************************************/ -void Expr::GetToken(token *pt) + * routine: GetToken + * + * description: + * Gets next token from static pointer str. + * + * arguments: + * pt pointer to token. GetToken fills in all + * field by this pointer. + * + * return code: + * None + * + * side effects: + * 1. May insrease pointer str (if token getted successfully). + * 2. May change static variable state (if token getted + * successfully and state was changed). + * + ********************************************************/ +void Expr::GetToken(token* pt) { char *old_str, *p; int i, rc, oplen; @@ -507,10 +475,12 @@ void Expr::GetToken(token *pt) /* * Skip all leading ignorable characters */ - do { + do + { old_str = str; for (p = (char*)IGNORE; *p; p++) - if (*str == *p) { + if (*str == *p) + { str++; } } while ((old_str != str) && *str); @@ -519,215 +489,248 @@ void Expr::GetToken(token *pt) pt->sta = state; switch (state) { - case was_bin: - /* - * Was binary operation (or begin of experssion). - * Unary operation expected. - * Try find unary operation with maximal length. - */ - oplen = 0; - for (i = 0; i < Lunar; i++) - if (!strncmp(unar[i].st, str, strlen(unar[i].st))) { - if ((int)strlen(unar[i].st) > oplen) { - pt->type = unar[i].type; - oplen = strlen(unar[i].st); - } - } - if (oplen) { - /* Unary operation found. */ - str += oplen; - state = was_bin; - return; - } - - /* - * Unary operation not found. - * Number or name expected. - */ - if (!strncmp(str, RADIX16, strlen(RADIX16)) - || !strncmp(str, RADIX2, strlen(RADIX2))) { + case was_bin: /* - * Number expected. + * Was binary operation (or begin of experssion). + * Unary operation expected. + * Try find unary operation with maximal length. */ - rc = GetNumb(&pt->value); - if (rc == EXPR_OK) { - pt->type = VALUE; - } else { - pt->type = rc; + oplen = 0; + for (i = 0; i < Lunar; i++) + if (!strncmp(unar[i].st, str, strlen(unar[i].st))) + { + if ((int)strlen(unar[i].st) > oplen) + { + pt->type = unar[i].type; + oplen = strlen(unar[i].st); + } + } + if (oplen) + { + /* Unary operation found. */ + str += oplen; + state = was_bin; return; } - } else if (valid_name(*str) || valid_digit(*str, def_radix)) { + /* - * Name or number expected. + * Unary operation not found. + * Number or name expected. */ - rc = GetName(&pt->value); - if (rc == EXPR_OK) { - pt->type = VALUE; - } else { - pt->type = rc; - return; + if (!strncmp(str, RADIX16, strlen(RADIX16)) || !strncmp(str, RADIX2, strlen(RADIX2))) + { + /* + * Number expected. + */ + rc = GetNumb(&pt->value); + if (rc == EXPR_OK) + { + pt->type = VALUE; + } + else + { + pt->type = rc; + return; + } } - } else if (*str == '(') { - /* - * Parentheses expression expected. - */ - old_str = str++; - rc = GetBinaryOp(&pt->value, LOW_PRI); - if (rc == EXPR_OK) { - pt->type = VALUE; - } else { - pt->type = rc; - return; + else if (valid_name(*str) || valid_digit(*str, def_radix)) + { + /* + * Name or number expected. + */ + rc = GetName(&pt->value); + if (rc == EXPR_OK) + { + pt->type = VALUE; + } + else + { + pt->type = rc; + return; + } } - if (*str == ')') { - str++; - } else { - /* error, right parentheses expected. */ - pt->type = ERR_RPAR_EXP; - if (*str) { - ErrorReport("Instead of\"" + std::string(str) + "\" right parentheses expected.\n"); - } else { - ErrorReport("Unexpected end in expression \"" + std::string(initial_arg) + "\" - right parentheses expected.\n"); + else if (*str == '(') + { + /* + * Parentheses expression expected. + */ + old_str = str++; + rc = GetBinaryOp(&pt->value, LOW_PRI); + if (rc == EXPR_OK) + { + pt->type = VALUE; + } + else + { + pt->type = rc; + return; + } + if (*str == ')') + { + str++; + } + else + { + /* error, right parentheses expected. */ + pt->type = ERR_RPAR_EXP; + if (*str) + { + ErrorReport("Instead of\"" + std::string(str) + "\" right parentheses expected.\n"); + } + else + { + ErrorReport("Unexpected end in expression \"" + std::string(initial_arg) + + "\" - right parentheses expected.\n"); + } + str = old_str; + return; } - str = old_str; - return; } - } else { - /* error, number or name or unary operation expected. */ - pt->type = ERR_VALUE_EXP; - if (*str) { - ErrorReport("Instead of \"" + std::string(str) + "\" value or unary operation expected.\n"); - } else { - ErrorReport("Unexpected end in expression \"" + std::string(initial_arg) + "\" - value or unary operation expected.\n"); + else + { + /* error, number or name or unary operation expected. */ + pt->type = ERR_VALUE_EXP; + if (*str) + { + ErrorReport("Instead of \"" + std::string(str) + "\" value or unary operation expected.\n"); + } + else + { + ErrorReport("Unexpected end in expression \"" + std::string(initial_arg) + + "\" - value or unary operation expected.\n"); + } + return; } + state = was_opr; return; - } - state = was_opr; - return; - case was_opr: - /* - * Was operand. Binary operation expected - * Try find binary operation with maximal length. - */ - oplen = 0; - for (i = 0; i < Lbinar; i++) - if (!strncmp(binar[i].st, str, strlen(binar[i].st))) { - if ((int)strlen(binar[i].st) > oplen) { - oplen = strlen(binar[i].st); - pt->type = binar[i].type; + case was_opr: + /* + * Was operand. Binary operation expected + * Try find binary operation with maximal length. + */ + oplen = 0; + for (i = 0; i < Lbinar; i++) + if (!strncmp(binar[i].st, str, strlen(binar[i].st))) + { + if ((int)strlen(binar[i].st) > oplen) + { + oplen = strlen(binar[i].st); + pt->type = binar[i].type; + } } + if (oplen) + { + /* Binary operation found. */ + str += oplen; + state = was_bin; + return; } - if (oplen) { - /* Binary operation found. */ - str += oplen; - state = was_bin; - return; - } - /* error, binary operation expected. */ - pt->type = ERR_BIN_EXP; - return; + /* error, binary operation expected. */ + pt->type = ERR_BIN_EXP; + return; } } /******************************************************** -* routine: UngetToken -* -* description: -* Ungets previously getted token. -* -* arguments: -* t token to unget -* -* return code: -* None -* -* side effects: -* 1. Restores str as was before token. -* 2. Restores state as was before token -* -********************************************************/ + * routine: UngetToken + * + * description: + * Ungets previously getted token. + * + * arguments: + * t token to unget + * + * return code: + * None + * + * side effects: + * 1. Restores str as was before token. + * 2. Restores state as was before token + * + ********************************************************/ void Expr::UngetToken(token t) { str = t.beg; state = t.sta; } - /******************************************************** -* routine: GetNumb -* -* description: -* Gets constant from str. First character of constant may -* be special value to set radix (% for 2, & for 10 and $ for 16). -* -* arguments: -* val pointer to unsigned long to put constatnt value. -* -* return code: -* EXPR_OK - Constant OK -* ERR_BAD_NUMBER - Bad constant syntax -* -* side effects: -* Moves pointer str to end of constant. -* -********************************************************/ -int Expr::GetNumb(u_int64_t *val) + * routine: GetNumb + * + * description: + * Gets constant from str. First character of constant may + * be special value to set radix (% for 2, & for 10 and $ for 16). + * + * arguments: + * val pointer to unsigned long to put constatnt value. + * + * return code: + * EXPR_OK - Constant OK + * ERR_BAD_NUMBER - Bad constant syntax + * + * side effects: + * Moves pointer str to end of constant. + * + ********************************************************/ +int Expr::GetNumb(u_int64_t* val) { int radix = def_radix; - if (!strncmp(str, RADIX16, strlen(RADIX16))) { + if (!strncmp(str, RADIX16, strlen(RADIX16))) + { radix = 16; str += strlen(RADIX16); - } else if (!strncmp(str, RADIX2, strlen(RADIX2))) { + } + else if (!strncmp(str, RADIX2, strlen(RADIX2))) + { radix = 2; str += strlen(RADIX2); } - if (!valid_digit(*str, radix)) { + if (!valid_digit(*str, radix)) + { ErrorReport("\"" + std::string(str) + "\" -- bad constant syntax.\n"); return ERR_BAD_NUMBER; } *val = 0L; for (; valid_digit(*str, radix); str++) - *val = *val * radix + - ( ('a' <= *str && *str <= 'f') ? *str - 'a' + 10 : - ( ('A' <= *str && *str <= 'F') ? *str - 'A' + 10 : - *str - '0')); + *val = + *val * radix + (('a' <= *str && *str <= 'f') ? *str - 'a' + 10 : + (('A' <= *str && *str <= 'F') ? *str - 'A' + 10 : *str - '0')); return EXPR_OK; } - /******************************************************** -* routine: GetName -* -* description: -* Gets name from str and tries to find it in symbol -* table. If name looks as constant in "def_radix", -* interprets it as constant rather than name. -* -* arguments: -* val - pointer to unsigned long to put value -* -* return code: -* EXPR_OK - Name successfully found in symbol table and -* substituted by its value. -* ERR_BAD_NAME - Name not found in symbol table. -* -* side effects: -* Moves pointer str to end of name. -* -********************************************************/ + * routine: GetName + * + * description: + * Gets name from str and tries to find it in symbol + * table. If name looks as constant in "def_radix", + * interprets it as constant rather than name. + * + * arguments: + * val - pointer to unsigned long to put value + * + * return code: + * EXPR_OK - Name successfully found in symbol table and + * substituted by its value. + * ERR_BAD_NAME - Name not found in symbol table. + * + * side effects: + * Moves pointer str to end of name. + * + ********************************************************/ #define MAXNAM 100 -int Expr::GetName(u_int64_t *val) +int Expr::GetName(u_int64_t* val) { static char name[MAXNAM]; - char *p, *old_str; + char *p, *old_str; - old_str = str; /* Save start name position. */ + old_str = str; /* Save start name position. */ /* Get name. */ for (p = name; valid_name(*str);) @@ -736,10 +739,12 @@ int Expr::GetName(u_int64_t *val) /* Try interpret as constant first. */ for (p = name; *p; p++) - if (!valid_digit(*p, def_radix)) { + if (!valid_digit(*p, def_radix)) + { break; } - if (!*p) { + if (!*p) + { /* * All characters of this name are valid digit in radix * "def_radix". So, interpret this name as constant. @@ -750,79 +755,80 @@ int Expr::GetName(u_int64_t *val) /* Retrieve name from symbol table. */ /* -------------------------------- */ - if (ResolveName(name, val) == 0) { + if (ResolveName(name, val) == 0) + { return EXPR_OK; - } else { - ErrorReport("Symbolic name \"" + std::string(name) + "\" not resolved.\n"); + } + else + { + ErrorReport("Symbolic name \"" + std::string(name) + "\" not resolved.\n"); return ERR_BAD_NAME; } } /******************************************************** -* routine: valid_name -* -* description: -* Function checks if character may be part of symbolic name. -* -* arguments: -* ch - character to check -* -* return code: -* 0 - character is not valid -* 1 - character is valid -* -********************************************************/ + * routine: valid_name + * + * description: + * Function checks if character may be part of symbolic name. + * + * arguments: + * ch - character to check + * + * return code: + * 0 - character is not valid + * 1 - character is valid + * + ********************************************************/ int Expr::valid_name(char ch) { return (ch == '_' || ch == '.') ? 1 : isalnum(ch); } /******************************************************** -* routine: valid_digit -* -* description: -* Check validity of digit ch (in ASCII, ex. '1') according to radix 'radix'. -* -* arguments: -* ch - character to check -* radix - radix -* -* return code: -* 0 - character is not valid -* 1 - character is valid -* -********************************************************/ + * routine: valid_digit + * + * description: + * Check validity of digit ch (in ASCII, ex. '1') according to radix 'radix'. + * + * arguments: + * ch - character to check + * radix - radix + * + * return code: + * 0 - character is not valid + * 1 - character is valid + * + ********************************************************/ int Expr::valid_digit(char ch, int radix) { switch (radix) { - case 2: - return (ch == '0' || ch == '1') ? 1 : 0; + case 2: + return (ch == '0' || ch == '1') ? 1 : 0; - case 10: - return isdigit(ch); + case 10: + return isdigit(ch); - case 16: - return isxdigit(ch); + case 16: + return isxdigit(ch); - default: - return 1; + default: + return 1; } } - /******************************************************** -* routine: ErrorReport -* -* description: -* Error reporting -* -* arguments: -* like printf -* -********************************************************/ + * routine: ErrorReport + * + * description: + * Error reporting + * + * arguments: + * like printf + * + ********************************************************/ void Expr::ErrorReport(const std::string& msg) { - Error(msg); + Error(msg); } - diff --git a/adb_parser/expr.h b/adb_parser/expr.h index b99b8b76..a530951d 100644 --- a/adb_parser/expr.h +++ b/adb_parser/expr.h @@ -102,67 +102,69 @@ #include - class Expr { public: // Error codes - enum { - ERR_RPAR_EXP = -1, // Right parentheses expected - ERR_VALUE_EXP = -2, // Value expected - ERR_BIN_EXP = -3, // Binary operation expected (normal at end) - ERR_DIV_ZERO = -4, // Divide zero attempt - ERR_BAD_NUMBER = -5, // Bad constant syntax - ERR_BAD_NAME = -6 // Name not resolved + enum + { + ERR_RPAR_EXP = -1, // Right parentheses expected + ERR_VALUE_EXP = -2, // Value expected + ERR_BIN_EXP = -3, // Binary operation expected (normal at end) + ERR_DIV_ZERO = -4, // Divide zero attempt + ERR_BAD_NUMBER = -5, // Bad constant syntax + ERR_BAD_NAME = -6 // Name not resolved }; - Expr() : def_radix(10) { } - virtual ~Expr() { } + Expr() : def_radix(10) {} + virtual ~Expr() {} - int expr(char **pstr, u_int64_t *result); + int expr(char** pstr, u_int64_t* result); /* Current state of parsing. */ - typedef enum { - was_bin, /* was binary operation */ - was_opr /* was operand */ + typedef enum + { + was_bin, /* was binary operation */ + was_opr /* was operand */ } status; /* Token as it read by parser. */ - typedef struct { - char *beg; /* pointer to token begining */ + typedef struct + { + char* beg; /* pointer to token begining */ status sta; /* state of parser before this token */ int type; /* type of token (any operation, VALUE or error code */ u_int64_t value; /* if type == VALUE value of token */ } token; /* Table of operations. */ - typedef struct { - int type; /* type of operation - internal number */ - int pri; /* priority of this operation */ - const char *st; /* string which cause this operation */ + typedef struct + { + int type; /* type of operation - internal number */ + int pri; /* priority of this operation */ + const char* st; /* string which cause this operation */ } table; private: - - static char *str; - static char *initial_arg; + static char* str; + static char* initial_arg; static status state; int def_radix; - int GetBinaryOp(u_int64_t *val, int priority); - int GetUnaryOp(u_int64_t *val); - void GetToken(token *pt); - void UngetToken(token t); - int GetNumb(u_int64_t *val); - int GetName(u_int64_t *val); - int valid_digit(char ch, int radix); - int valid_name(char ch); + int GetBinaryOp(u_int64_t* val, int priority); + int GetUnaryOp(u_int64_t* val); + void GetToken(token* pt); + void UngetToken(token t); + int GetNumb(u_int64_t* val); + int GetName(u_int64_t* val); + int valid_digit(char ch, int radix); + int valid_name(char ch); - void ErrorReport(const std::string& msg); + void ErrorReport(const std::string& msg); /* * Pure virtual methods. You must define them to use expr. */ - virtual int ResolveName(char *name, u_int64_t *val) = 0; + virtual int ResolveName(char* name, u_int64_t* val) = 0; virtual void Error(const std::string& msg) = 0; }; diff --git a/cmdif/cmdif.py b/cmdif/cmdif.py index afbdd7bc..a6422860 100755 --- a/cmdif/cmdif.py +++ b/cmdif/cmdif.py @@ -28,7 +28,7 @@ # 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. -#-- +# -- from __future__ import print_function import os @@ -37,18 +37,23 @@ import ctypes import mtcr + def ones(n): return (1 << n) - 1 + def extractField(val, start, size): - return (val & (ones(size)<> start + return (val & (ones(size) << start)) >> start + def insertField(val1, start1, val2, start2, size): - return val1 & ~(ones(size)<in), _data); \ - } \ - _rc = icmd_send_command(mf, op, _data, _cmd_size, skip_write); \ - if (_rc) { \ - free(_data); \ - return convert_rc(_rc); \ - } \ - struct_name##_unpack(cmd_struct, _data); \ - free(_data); \ + int _rc; \ + int _cmd_size = struct_name##_size(); \ + u_int8_t* _data = (u_int8_t*)malloc(sizeof(u_int8_t) * _cmd_size); \ + if (!_data) \ + { \ + return GCIF_STATUS_NO_MEM; \ + } \ + memset(_data, 0, sizeof(u_int8_t) * _cmd_size); \ + if (should_pack) \ + { \ + struct_name##_in_pack(&(cmd_struct->in), _data); \ + } \ + _rc = icmd_send_command(mf, op, _data, _cmd_size, skip_write); \ + if (_rc) \ + { \ + free(_data); \ + return convert_rc(_rc); \ + } \ + struct_name##_unpack(cmd_struct, _data); \ + free(_data); \ return GCIF_STATUS_SUCCESS - #endif diff --git a/cmdif/icmd_cif_open.c b/cmdif/icmd_cif_open.c index 74d89b6b..1e061375 100644 --- a/cmdif/icmd_cif_open.c +++ b/cmdif/icmd_cif_open.c @@ -38,14 +38,13 @@ #include "icmd_cif_open.h" #include "icmd_cif_macros.h" -#define MH_SYNC_OPCODE 0x8402 +#define MH_SYNC_OPCODE 0x8402 #define MH_SYNC_STATUS_OPCODE 0x8403 /* * gcif_get_fw_info */ -int gcif_get_fw_info(mfile *mf, - OUT struct connectib_icmd_get_fw_info *fw_info) +int gcif_get_fw_info(mfile* mf, OUT struct connectib_icmd_get_fw_info* fw_info) { SEND_ICMD_FLOW(mf, GET_FW_INFO, connectib_icmd_get_fw_info, fw_info, 0, 1); } @@ -53,29 +52,28 @@ int gcif_get_fw_info(mfile *mf, /* * get_icmd_query_cap */ -int get_icmd_query_cap(mfile *mf, struct icmd_hca_icmd_query_cap_general *icmd_query_caps) +int get_icmd_query_cap(mfile* mf, struct icmd_hca_icmd_query_cap_general* icmd_query_caps) { - SEND_ICMD_FLOW(mf, GET_ICMD_QUERY_CAP, icmd_hca_icmd_query_cap_general, - icmd_query_caps, 1, 0); + SEND_ICMD_FLOW(mf, GET_ICMD_QUERY_CAP, icmd_hca_icmd_query_cap_general, icmd_query_caps, 1, 0); } -int gcif_mh_sync(mfile *mf, struct connectx4_icmd_mh_sync *mh_sync) +int gcif_mh_sync(mfile* mf, struct connectx4_icmd_mh_sync* mh_sync) { SEND_ICMD_FLOW(mf, MH_SYNC_OPCODE, connectx4_icmd_mh_sync, mh_sync, 1, 0); } -int gcif_mh_sync_status(mfile *mf, struct connectx4_icmd_mh_sync *mh_sync_out) +int gcif_mh_sync_status(mfile* mf, struct connectx4_icmd_mh_sync* mh_sync_out) { memset(mh_sync_out, 0x0, sizeof(*mh_sync_out)); SEND_ICMD_FLOW(mf, MH_SYNC_STATUS_OPCODE, connectx4_icmd_mh_sync, mh_sync_out, 1, 0); } -int gcif_set_itrace(mfile *mf, struct connectib_itrace *itrace) +int gcif_set_itrace(mfile* mf, struct connectib_itrace* itrace) { SEND_ICMD_FLOW(mf, SET_ITRACE, connectib_itrace, itrace, 1, 0); } -int gcif_set_port_sniffer(mfile *mf, struct connectib_icmd_set_port_sniffer *set_port_sniffer) +int gcif_set_port_sniffer(mfile* mf, struct connectib_icmd_set_port_sniffer* set_port_sniffer) { SEND_ICMD_FLOW(mf, SET_PORT_SNIFFER, connectib_icmd_set_port_sniffer, set_port_sniffer, 1, 0); } diff --git a/cmdif/icmd_cif_open.h b/cmdif/icmd_cif_open.h index 9544742a..ecf0db5f 100644 --- a/cmdif/icmd_cif_open.h +++ b/cmdif/icmd_cif_open.h @@ -30,11 +30,12 @@ * SOFTWARE. */ -#ifndef _ICMD_OPEN_LIB /* guard */ +#ifndef _ICMD_OPEN_LIB /* guard */ #define _ICMD_OPEN_LIB #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif #include @@ -55,31 +56,31 @@ extern "C" { #define INOUT #endif -enum { - GET_FW_INFO = 0x8007, - FLASH_REG_ACCESS = 0x9001, -}; + enum + { + GET_FW_INFO = 0x8007, + FLASH_REG_ACCESS = 0x9001, + }; #ifdef MST_UL -// instead of cib_cif.h in mstflint -enum { - GET_ICMD_QUERY_CAP = 0x8400, - SET_ITRACE = 0xf003, - SET_PORT_SNIFFER = 0xc002, -}; + // instead of cib_cif.h in mstflint + enum + { + GET_ICMD_QUERY_CAP = 0x8400, + SET_ITRACE = 0xf003, + SET_PORT_SNIFFER = 0xc002, + }; #endif -int gcif_get_fw_info(mfile *mf, - OUT struct connectib_icmd_get_fw_info *fw_info); + int gcif_get_fw_info(mfile* mf, OUT struct connectib_icmd_get_fw_info* fw_info); -int get_icmd_query_cap(mfile *mf, - struct icmd_hca_icmd_query_cap_general *icmd_query_caps); + int get_icmd_query_cap(mfile* mf, struct icmd_hca_icmd_query_cap_general* icmd_query_caps); -int gcif_mh_sync(mfile *mf, struct connectx4_icmd_mh_sync *mh_sync); + int gcif_mh_sync(mfile* mf, struct connectx4_icmd_mh_sync* mh_sync); -int gcif_mh_sync_status(mfile *mf, struct connectx4_icmd_mh_sync *mh_sync); + int gcif_mh_sync_status(mfile* mf, struct connectx4_icmd_mh_sync* mh_sync); -int gcif_set_port_sniffer(mfile *mf, struct connectib_icmd_set_port_sniffer *set_port_sniffer); + int gcif_set_port_sniffer(mfile* mf, struct connectib_icmd_set_port_sniffer* set_port_sniffer); #ifdef __cplusplus } diff --git a/cmdif/tools_cif.c b/cmdif/tools_cif.c index 7070a7a8..f94d6c58 100644 --- a/cmdif/tools_cif.c +++ b/cmdif/tools_cif.c @@ -53,78 +53,81 @@ #define QPC_READ_OP 0x67 #define QPC_WRITE_OP 0x69 -#define CHECK_RC(rc) \ - if (rc) {return (MError)rc;} - -#define BE32_TO_CPU(s, n) do { \ - u_int32_t i; \ - u_int32_t *p = (u_int32_t*)(s); \ - for (i = 0; i < (n); i++, p++) \ - *p = __be32_to_cpu(*p); \ -} while (0) +#define CHECK_RC(rc) \ + if (rc) \ + { \ + return (MError)rc; \ + } + +#define BE32_TO_CPU(s, n) \ + do \ + { \ + u_int32_t i; \ + u_int32_t* p = (u_int32_t*)(s); \ + for (i = 0; i < (n); i++, p++) \ + *p = __be32_to_cpu(*p); \ + } while (0) #if __BYTE_ORDER == __BIG_ENDIAN -#define SWAP_DW_BE(uint64_num) \ - (((uint64_num) & 0xffffffffULL) << 32) | (((uint64_num) >> 32) & 0xffffffffULL) +#define SWAP_DW_BE(uint64_num) (((uint64_num)&0xffffffffULL) << 32) | (((uint64_num) >> 32) & 0xffffffffULL) #else #define SWAP_DW_BE(uint64_num) (uint64_num) #endif -//TODO: adrianc: if we find ourselves adding more and more commands consider using a macro to save code. -//TODO: adrianc: when library expands consider returning its own error code +// TODO: adrianc: if we find ourselves adding more and more commands consider using a macro to save code. +// TODO: adrianc: when library expands consider returning its own error code -MError tcif_query_dev_cap(mfile *dev, u_int32_t offset, u_int64_t *data) +MError tcif_query_dev_cap(mfile* dev, u_int32_t offset, u_int64_t* data) { - int rc = tools_cmdif_send_mbox_command(dev, 0, QUERY_DEV_CAP_OP, 0, offset, (u_int32_t*)data, 8, 1); CHECK_RC(rc); + int rc = tools_cmdif_send_mbox_command(dev, 0, QUERY_DEV_CAP_OP, 0, offset, (u_int32_t*)data, 8, 1); + CHECK_RC(rc); BE32_TO_CPU(data, 2); *data = SWAP_DW_BE(*data); return ME_OK; } - -MError tcif_query_global_def_params(mfile *dev, struct tools_open_query_def_params_global *global_params) +MError tcif_query_global_def_params(mfile* dev, struct tools_open_query_def_params_global* global_params) { u_int8_t data[TOOLS_OPEN_QUERY_DEF_PARAMS_GLOBAL_SIZE] = {0}; - int rc = tools_cmdif_send_mbox_command(dev, 0, QUERY_DEF_PARAMS_OP, 0, 0, data, sizeof(data), 0); CHECK_RC(rc); + int rc = tools_cmdif_send_mbox_command(dev, 0, QUERY_DEF_PARAMS_OP, 0, 0, data, sizeof(data), 0); + CHECK_RC(rc); tools_open_query_def_params_global_unpack(global_params, data); return ME_OK; } - -MError tcif_query_per_port_def_params(mfile *dev, u_int8_t port, struct tools_open_query_def_params_per_port *port_params) +MError + tcif_query_per_port_def_params(mfile* dev, u_int8_t port, struct tools_open_query_def_params_per_port* port_params) { u_int8_t data[TOOLS_OPEN_QUERY_DEF_PARAMS_PER_PORT_SIZE] = {0}; - int rc = tools_cmdif_send_mbox_command(dev, 0, QUERY_DEF_PARAMS_OP, port, 0, data, sizeof(data), 0); CHECK_RC(rc); + int rc = tools_cmdif_send_mbox_command(dev, 0, QUERY_DEF_PARAMS_OP, port, 0, data, sizeof(data), 0); + CHECK_RC(rc); tools_open_query_def_params_per_port_unpack(port_params, data); return ME_OK; } - -MError tcif_qpc_context_read(mfile *dev, u_int32_t qpn, u_int32_t source, u_int8_t *data, u_int32_t len) +MError tcif_qpc_context_read(mfile* dev, u_int32_t qpn, u_int32_t source, u_int8_t* data, u_int32_t len) { u_int32_t input_mod = 0; - input_mod = MERGE(input_mod, source, 24, 8); - input_mod = MERGE(input_mod, qpn, 0, 24); + input_mod = MERGE(input_mod, source, 24, 8); + input_mod = MERGE(input_mod, qpn, 0, 24); int rc = tools_cmdif_send_mbox_command(dev, input_mod, QPC_READ_OP, 0, 0, data, len, 1); CHECK_RC(rc); return ME_OK; } - -MError tcif_qpc_context_write(mfile *dev, u_int32_t qpn, u_int32_t source, u_int8_t *data, u_int32_t len) +MError tcif_qpc_context_write(mfile* dev, u_int32_t qpn, u_int32_t source, u_int8_t* data, u_int32_t len) { u_int32_t input_mod = 0; - input_mod = MERGE(input_mod, source, 24, 8); - input_mod = MERGE(input_mod, qpn, 0, 24); + input_mod = MERGE(input_mod, source, 24, 8); + input_mod = MERGE(input_mod, qpn, 0, 24); int rc = tools_cmdif_send_mbox_command(dev, input_mod, QPC_WRITE_OP, 0, 0, data, len, 0); CHECK_RC(rc); return ME_OK; } - -MError tcif_hw_access(mfile *dev, u_int64_t key, int lock_unlock) +MError tcif_hw_access(mfile* dev, u_int64_t key, int lock_unlock) { return (MError)tools_cmdif_send_inline_cmd(dev, key, NULL, 0, HW_ACCESS_OP, lock_unlock); } @@ -133,8 +136,7 @@ const char* tcif_err2str(MError rc) return m_err2str(rc); } - -MError tcif_cr_mbox_supported(mfile *dev) +MError tcif_cr_mbox_supported(mfile* dev) { #if defined(__FreeBSD__) || defined(UEFI_BUILD) (void)dev; @@ -142,5 +144,4 @@ MError tcif_cr_mbox_supported(mfile *dev) #else return (MError)tools_cmdif_is_cr_mbox_supported(dev); #endif - } diff --git a/cmdif/tools_cif.h b/cmdif/tools_cif.h index 2783044a..5e2a5c9a 100644 --- a/cmdif/tools_cif.h +++ b/cmdif/tools_cif.h @@ -38,92 +38,93 @@ #define TOOLS_CIF_H #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif #include #include - -/** - * tcif_query_dev_cap: - * @param[in] dev A pointer to a device context. - * @param[in] offs offset in even dword to read from the DEV_CAP vector - * @param[out] data Quad-word read from the device capabilities vector from offset: offs - - * @return One of the MError* values, or a raw - **/ -MError tcif_query_dev_cap(mfile *dev, u_int32_t offs, u_int64_t *data); - -/** - * tcif_query_global_def_params: - * @param[in] dev A pointer to a device context. - * @param[in/out] global_params pointer to global params struct - - * @return One of the MError* values, or a raw - **/ -MError tcif_query_global_def_params(mfile *dev, struct tools_open_query_def_params_global *global_params); - -/** - * tcif_query_per_port_def_params: - * @param[in] dev A pointer to a device context. - * @param[in] port Port that the query will be performed on (1 or 2) - * @param[in/out] port_params Pointer to port params struct - - * @return One of the MError* values, or a raw - **/ -MError tcif_query_per_port_def_params(mfile *dev, u_int8_t port, struct tools_open_query_def_params_per_port *port_params); - -/** - * tcif_qpc_context_read: - * @param[in] dev A pointer to a device context. - * @param[in] qpn QP Number - * @param[in] source QP Source - * @param[in] data Data that was read - * - * @return One of the MError* values, or a raw - **/ -MError tcif_qpc_context_read(mfile *dev, u_int32_t qpn, u_int32_t source, u_int8_t *data, u_int32_t len); - -/** - * tcif_qpc_context_write: - * @param[in] dev A pointer to a device context. - * @param[in] qpn QP Number - * @param[in] source QP Source - * @param[in] data Data to be written - * - * @return One of the MError* values, or a raw - **/ -MError tcif_qpc_context_write(mfile *dev, u_int32_t qpn, u_int32_t source, u_int8_t *data, u_int32_t len); - - -/** - * tcif_hw_access: - * @param[in] dev A pointer to a device context. - * @param[in] key key with which we attempt to lock/unlock the cr-space (should be 0 for locking) - * @param[out] lock_unlock 1-lock , 0-unlock - - * @return One of the MError* values, or a raw - **/ -MError tcif_hw_access(mfile *dev, u_int64_t key, int lock_unlock); - -/** - * tcif_cr_mailbox_supported: - * @param[in] dev A pointer to a device context. - - * @return ME_OK - cr mailbox supported - * ME_SEM_LOCKED - tools HCR semaphore locked - * ME_CMDIF_NOT_SUPP - cr mailbox not supported - **/ -MError tcif_cr_mbox_supported(mfile *dev); - -/** - * tcif_err2str: - * @param[in] rc return code from one of the above functions - - * @return string describing the error occurred. - **/ -const char* tcif_err2str(MError rc); + /** + * tcif_query_dev_cap: + * @param[in] dev A pointer to a device context. + * @param[in] offs offset in even dword to read from the DEV_CAP vector + * @param[out] data Quad-word read from the device capabilities vector from offset: offs + + * @return One of the MError* values, or a raw + **/ + MError tcif_query_dev_cap(mfile* dev, u_int32_t offs, u_int64_t* data); + + /** + * tcif_query_global_def_params: + * @param[in] dev A pointer to a device context. + * @param[in/out] global_params pointer to global params struct + + * @return One of the MError* values, or a raw + **/ + MError tcif_query_global_def_params(mfile* dev, struct tools_open_query_def_params_global* global_params); + + /** + * tcif_query_per_port_def_params: + * @param[in] dev A pointer to a device context. + * @param[in] port Port that the query will be performed on (1 or 2) + * @param[in/out] port_params Pointer to port params struct + + * @return One of the MError* values, or a raw + **/ + MError tcif_query_per_port_def_params(mfile* dev, + u_int8_t port, + struct tools_open_query_def_params_per_port* port_params); + + /** + * tcif_qpc_context_read: + * @param[in] dev A pointer to a device context. + * @param[in] qpn QP Number + * @param[in] source QP Source + * @param[in] data Data that was read + * + * @return One of the MError* values, or a raw + **/ + MError tcif_qpc_context_read(mfile* dev, u_int32_t qpn, u_int32_t source, u_int8_t* data, u_int32_t len); + + /** + * tcif_qpc_context_write: + * @param[in] dev A pointer to a device context. + * @param[in] qpn QP Number + * @param[in] source QP Source + * @param[in] data Data to be written + * + * @return One of the MError* values, or a raw + **/ + MError tcif_qpc_context_write(mfile* dev, u_int32_t qpn, u_int32_t source, u_int8_t* data, u_int32_t len); + + /** + * tcif_hw_access: + * @param[in] dev A pointer to a device context. + * @param[in] key key with which we attempt to lock/unlock the cr-space (should be 0 for locking) + * @param[out] lock_unlock 1-lock , 0-unlock + + * @return One of the MError* values, or a raw + **/ + MError tcif_hw_access(mfile* dev, u_int64_t key, int lock_unlock); + + /** + * tcif_cr_mailbox_supported: + * @param[in] dev A pointer to a device context. + + * @return ME_OK - cr mailbox supported + * ME_SEM_LOCKED - tools HCR semaphore locked + * ME_CMDIF_NOT_SUPP - cr mailbox not supported + **/ + MError tcif_cr_mbox_supported(mfile* dev); + + /** + * tcif_err2str: + * @param[in] rc return code from one of the above functions + + * @return string describing the error occurred. + **/ + const char* tcif_err2str(MError rc); #ifdef __cplusplus } diff --git a/cmdparser/cmdparser.cpp b/cmdparser/cmdparser.cpp index 819140f8..c9c29bef 100644 --- a/cmdparser/cmdparser.cpp +++ b/cmdparser/cmdparser.cpp @@ -30,7 +30,6 @@ * SOFTWARE. */ - /*Includes*/ #include #include @@ -42,7 +41,6 @@ #include "my_getopt.h" #include "cmdparser.h" - /*Constants*/ #define IDENT_LENGTH 4 #define PREFIX_SPACE_SIZE 8 @@ -51,45 +49,54 @@ #define COLON_AND_SPACE_SIZE 2 #define TAB_SIZE 4 - /*Declarations*/ -typedef vector < bool > vec_bool; +typedef vector vec_bool; static string CreateIndentFromInt(int ident_size); static void FindAndReplace(string& source, string::size_type pos, string const& find, string const& replace); -static bool FindAndHandleNewLinePos(string& str, int& product_length, int& local_space_size, int& str_type_len, - int& new_line_pos, string newline_and_ident, int deli_is_space); +static bool FindAndHandleNewLinePos(string& str, + int& product_length, + int& local_space_size, + int& str_type_len, + int& new_line_pos, + string newline_and_ident, + int deli_is_space); /****************************************************/ /************class CommandLineRequester**************/ /****************************************************/ /* private methods */ -string CommandLineRequester::BuildOptStr(option_ifc_t &opt) +string CommandLineRequester::BuildOptStr(option_ifc_t& opt) { string str; - str += CreateIndentFromInt(opt.numOfSpaces*4); - if (opt.option_short_name != ' ') { + str += CreateIndentFromInt(opt.numOfSpaces * 4); + if (opt.option_short_name != ' ') + { str += "-"; str += opt.option_short_name; str += "|"; } str += "--"; str += opt.option_name; - if (opt.option_value != "") { + if (opt.option_value != "") + { str += " "; str += opt.option_value; } return str; } -string CommandLineRequester::FormatUsageStr(string str, int str_type_len, int ident_size, - int is_not_description, bool is_left_side) +string CommandLineRequester::FormatUsageStr(string str, + int str_type_len, + int ident_size, + int is_not_description, + bool is_left_side) { string ident = CreateIndentFromInt(ident_size); string newline_and_ident = "\n" + ident; - //replace tabs in spaces + // replace tabs in spaces FindAndReplace(str, 0, "\t", CreateIndentFromInt(TAB_SIZE)); - //helper variables for formatting + // helper variables for formatting int residual = str.size(); int initial_residual = residual; int product_length = 0; @@ -97,38 +104,43 @@ string CommandLineRequester::FormatUsageStr(string str, int str_type_len, int id int new_line_pos = 0; int space_not_exists_count = 0; - //iterate while the remained text is longer then a valid line length - while (residual >= str_type_len + local_space_size) { - //search for a user defined new line. + // iterate while the remained text is longer then a valid line length + while (residual >= str_type_len + local_space_size) + { + // search for a user defined new line. if (FindAndHandleNewLinePos(str, product_length, local_space_size, str_type_len, new_line_pos, - newline_and_ident, 0)) { + newline_and_ident, 0)) + { goto next_iteration; } - //if no such is found. try to find a space to break the line at it's position. + // if no such is found. try to find a space to break the line at it's position. if (FindAndHandleNewLinePos(str, product_length, local_space_size, str_type_len, new_line_pos, - newline_and_ident, 1)) { + newline_and_ident, 1)) + { goto next_iteration; } - //if not found, break the line in a middle of a spaceless word. + // if not found, break the line in a middle of a spaceless word. space_not_exists_count++; new_line_pos = local_space_size + str_type_len + product_length; str.insert(new_line_pos, newline_and_ident); -next_iteration: - //update iteration variables + next_iteration: + // update iteration variables local_space_size = ident_size; initial_residual += ident_size; residual = initial_residual - new_line_pos - 1 + space_not_exists_count; product_length = new_line_pos; } - //handle the last line remained. if it is the left string - add aligned colon. - if (is_left_side) { - while (residual < str_type_len + ident_size) { + // handle the last line remained. if it is the left string - add aligned colon. + if (is_left_side) + { + while (residual < str_type_len + ident_size) + { str += " "; residual++; } str += ": "; } - //Add user defined new lines in last line remained. + // Add user defined new lines in last line remained. FindAndReplace(str, product_length + local_space_size + 1, "\n", newline_and_ident); return str; } @@ -146,20 +158,22 @@ void CommandLineRequester::AddOptionalSectionData(string section_name, string st sec_data.str2 = str2; for (optional_sections_t::iterator it = this->optional_sections_vec.begin(); - it != this->optional_sections_vec.end(); ++it) { - if (it->first == section_name) { + it != this->optional_sections_vec.end(); + ++it) + { + if (it->first == section_name) + { pos = distance(optional_sections_vec.begin(), it); this->optional_sections_vec[pos].second.push_back(sec_data); return; } } - this->optional_sections_vec.push_back(pair < string, vector > - (section_name, vector < struct optional_help_section_data >())); + this->optional_sections_vec.push_back(pair >( + section_name, vector())); pos = optional_sections_vec.size() - 1; this->optional_sections_vec[pos].second.push_back(sec_data); } - string CommandLineRequester::GetUsageSynopsis(bool hidden_options) { string prefix_space = CreateIndentFromInt(PREFIX_SPACE_SIZE); @@ -169,21 +183,29 @@ string CommandLineRequester::GetUsageSynopsis(bool hidden_options) int curr_line_len = PREFIX_SPACE_SIZE; int new_line_pos; - for (vec_option_t::iterator it = this->options.begin(); it != this->options.end(); ++it) { - if (hidden_options == false) { //display only not hidden options - if ((*it).hidden == true) { + for (vec_option_t::iterator it = this->options.begin(); it != this->options.end(); ++it) + { + if (hidden_options == false) + { // display only not hidden options + if ((*it).hidden == true) + { continue; } - } else { //display only hidden options - if ((*it).hidden == false) { + } + else + { // display only hidden options + if ((*it).hidden == false) + { continue; } } curr_str += (*it).is_mandatory ? "<" : "["; curr_str += this->BuildOptStr(*it); curr_str += (*it).is_mandatory ? ">" : "]"; - if (curr_str.size() + curr_line_len < RIGHT_STR_MAX_LEN + LEFT_STR_MAX_LEN) { - if (curr_line_len > PREFIX_SPACE_SIZE) { + if (curr_str.size() + curr_line_len < RIGHT_STR_MAX_LEN + LEFT_STR_MAX_LEN) + { + if (curr_line_len > PREFIX_SPACE_SIZE) + { str += " "; } curr_line_len += curr_str.size(); @@ -191,20 +213,26 @@ string CommandLineRequester::GetUsageSynopsis(bool hidden_options) curr_str = ""; continue; } - while (curr_str.size() + curr_line_len >= RIGHT_STR_MAX_LEN + LEFT_STR_MAX_LEN) { - if (curr_str.size() < RIGHT_STR_MAX_LEN + LEFT_STR_MAX_LEN) { + while (curr_str.size() + curr_line_len >= RIGHT_STR_MAX_LEN + LEFT_STR_MAX_LEN) + { + if (curr_str.size() < RIGHT_STR_MAX_LEN + LEFT_STR_MAX_LEN) + { str += "\n" + prefix_space + curr_str; curr_line_len = PREFIX_SPACE_SIZE + curr_str.size(); curr_str = ""; continue; } new_line_pos = curr_str.find_last_of(" ", RIGHT_STR_MAX_LEN + LEFT_STR_MAX_LEN); - if ((size_t)new_line_pos == curr_str.npos) { + if ((size_t)new_line_pos == curr_str.npos) + { new_line_pos = RIGHT_STR_MAX_LEN + LEFT_STR_MAX_LEN; - } else { + } + else + { new_line_pos += 1; } - if (curr_line_len > PREFIX_SPACE_SIZE) { + if (curr_line_len > PREFIX_SPACE_SIZE) + { str += "\n" + prefix_space; curr_line_len = PREFIX_SPACE_SIZE; } @@ -213,24 +241,26 @@ string CommandLineRequester::GetUsageSynopsis(bool hidden_options) str += "\n" + prefix_space; curr_line_len = PREFIX_SPACE_SIZE; } - if (curr_str != "") { + if (curr_str != "") + { str += curr_str; curr_line_len += PREFIX_SPACE_SIZE + curr_str.size(); curr_str = ""; } } - if (curr_str != prefix_space) { + if (curr_str != prefix_space) + { str += curr_str; str += "\n"; } - if (str != "") { + if (str != "") + { str = prefix_short_space + this->name + "\n" + str; } return str; } - string CommandLineRequester::GetUsageDescription() { optional_sec_data_t desc_data; @@ -241,7 +271,6 @@ string CommandLineRequester::GetUsageDescription() return this->GetUsageOptionalSection(desc_vector); } - string CommandLineRequester::GetUsageOptions(bool hidden_options) { string str = ""; @@ -249,13 +278,19 @@ string CommandLineRequester::GetUsageOptions(bool hidden_options) string prefix_space = CreateIndentFromInt(PREFIX_SPACE_SIZE); string prefix_short_space = CreateIndentFromInt(IDENT_LENGTH); - for (vec_option_t::iterator it = this->options.begin(); it != this->options.end(); ++it) { - if (hidden_options == false) { //display only not hidden options - if ((*it).hidden == true) { + for (vec_option_t::iterator it = this->options.begin(); it != this->options.end(); ++it) + { + if (hidden_options == false) + { // display only not hidden options + if ((*it).hidden == true) + { continue; } - } else { //display only hidden options - if ((*it).hidden == false) { + } + else + { // display only hidden options + if ((*it).hidden == false) + { continue; } } @@ -263,25 +298,27 @@ string CommandLineRequester::GetUsageOptions(bool hidden_options) opt_str += this->BuildOptStr(*it); opt_str = FormatUsageStr(opt_str, LEFT_STR_MAX_LEN, PREFIX_SPACE_SIZE, 1, true); str += opt_str; - desc_str = FormatUsageStr((*it).description, RIGHT_STR_MAX_LEN, LEFT_STR_MAX_LEN + PREFIX_SPACE_SIZE + - COLON_AND_SPACE_SIZE, 0, false); + desc_str = FormatUsageStr((*it).description, RIGHT_STR_MAX_LEN, + LEFT_STR_MAX_LEN + PREFIX_SPACE_SIZE + COLON_AND_SPACE_SIZE, 0, false); str += desc_str; str += "\n"; } - if (str != "") { + if (str != "") + { str = prefix_short_space + this->name + "\n" + str; } return str; } - string CommandLineRequester::GetUsageOptionalSections(vector excluded_sections) { string res = ""; - for (unsigned i = 0; i < optional_sections_vec.size(); ++i) { + for (unsigned i = 0; i < optional_sections_vec.size(); ++i) + { if (find(excluded_sections.begin(), excluded_sections.end(), optional_sections_vec[i].first) != - excluded_sections.end()) { + excluded_sections.end()) + { continue; } res += optional_sections_vec[i].first + "\n"; @@ -294,8 +331,8 @@ string CommandLineRequester::GetUsageOptional1Str(vectorstr1, LEFT_STR_MAX_LEN + RIGHT_STR_MAX_LEN, PREFIX_SPACE_SIZE, 1, - false); + data_string += + FormatUsageStr(prefix_space + it->str1, LEFT_STR_MAX_LEN + RIGHT_STR_MAX_LEN, PREFIX_SPACE_SIZE, 1, false); data_string += "\n"; return data_string; } @@ -306,7 +343,7 @@ string CommandLineRequester::GetUsageOptional2Str(vectorstr1, LEFT_STR_MAX_LEN, PREFIX_SPACE_SIZE, 1, true); data_string += FormatUsageStr(it->str2, RIGHT_STR_MAX_LEN, - LEFT_STR_MAX_LEN + PREFIX_SPACE_SIZE + COLON_AND_SPACE_SIZE, 0, false); + LEFT_STR_MAX_LEN + PREFIX_SPACE_SIZE + COLON_AND_SPACE_SIZE, 0, false); data_string += "\n"; return data_string; } @@ -314,25 +351,29 @@ string CommandLineRequester::GetUsageOptional2Str(vector section_vec) { string section_str(""); - if (section_vec.empty()) { + if (section_vec.empty()) + { return section_str; } - for (vector::iterator it = section_vec.begin(); it != section_vec.end(); ++it) { - if (it->str2 != "") { + for (vector::iterator it = section_vec.begin(); it != section_vec.end(); ++it) + { + if (it->str2 != "") + { section_str += this->GetUsageOptional2Str(it); - } else { + } + else + { section_str += this->GetUsageOptional1Str(it); } } return section_str; } - /****************************************************/ /**************class CommandLineParser***************/ /****************************************************/ /* private methods */ -void CommandLineParser::SetLastError(const char *fmt, ...) +void CommandLineParser::SetLastError(const char* fmt, ...) { char buff[1024]; va_list args; @@ -346,24 +387,23 @@ void CommandLineParser::SetLastError(const char *fmt, ...) return; } - /* public methods */ -int CommandLineParser::AddRequester(CommandLineRequester *p_req) +int CommandLineParser::AddRequester(CommandLineRequester* p_req) { - for (vec_option_t::iterator it = p_req->GetOptions().begin(); - it != p_req->GetOptions().end(); ++it) { - //long option must be valid - if ((*it).option_name == "") { - this->SetLastError("Requester \"%s\" has long option empty", - p_req->GetName().c_str()); + for (vec_option_t::iterator it = p_req->GetOptions().begin(); it != p_req->GetOptions().end(); ++it) + { + // long option must be valid + if ((*it).option_name == "") + { + this->SetLastError("Requester \"%s\" has long option empty", p_req->GetName().c_str()); return 1; } - //check if long option already exists - map_str_p_command_line_req::iterator it2 = - this->long_opt_to_req_map.find((*it).option_name); - if (it2 != this->long_opt_to_req_map.end()) { - this->SetLastError("Option \"%s\" from requester \"%s\" " \ + // check if long option already exists + map_str_p_command_line_req::iterator it2 = this->long_opt_to_req_map.find((*it).option_name); + if (it2 != this->long_opt_to_req_map.end()) + { + this->SetLastError("Option \"%s\" from requester \"%s\" " "already exists in requester \"%s\"", (*it).option_name.c_str(), p_req->GetName().c_str(), @@ -371,12 +411,13 @@ int CommandLineParser::AddRequester(CommandLineRequester *p_req) return 1; } - //check if short option already exists - if ((*it).option_short_name != ' ') { //if space than no short option - map_char_str::iterator it2 = - this->short_opt_to_long_opt.find((*it).option_short_name); - if (it2 != this->short_opt_to_long_opt.end()) { - this->SetLastError("Option \'%c\' from requester \"%s\" " \ + // check if short option already exists + if ((*it).option_short_name != ' ') + { // if space than no short option + map_char_str::iterator it2 = this->short_opt_to_long_opt.find((*it).option_short_name); + if (it2 != this->short_opt_to_long_opt.end()) + { + this->SetLastError("Option \'%c\' from requester \"%s\" " "already exists in requester \"%s\"", (*it).option_short_name, p_req->GetName().c_str(), @@ -386,11 +427,12 @@ int CommandLineParser::AddRequester(CommandLineRequester *p_req) } } - //finally add the requester - for (vec_option_t::iterator it = p_req->GetOptions().begin(); - it != p_req->GetOptions().end(); ++it) { + // finally add the requester + for (vec_option_t::iterator it = p_req->GetOptions().begin(); it != p_req->GetOptions().end(); ++it) + { this->long_opt_to_req_map[(*it).option_name] = p_req; - if ((*it).option_short_name != ' ') { //if space than no short option + if ((*it).option_short_name != ' ') + { // if space than no short option this->short_opt_to_long_opt[(*it).option_short_name] = (*it).option_name; } } @@ -403,16 +445,17 @@ string CommandLineParser::GetSynopsis(bool hidden_options) string res; string prefix_short_space = CreateIndentFromInt(IDENT_LENGTH); - //name + // name res = "NAME\n"; res += prefix_short_space; res += this->name; res += "\n\n"; - //synopsis + // synopsis res += "SYNOPSIS\n"; - for (list_p_command_line_req::iterator it = this->p_requesters_list.begin(); - it != this->p_requesters_list.end(); ++it) { + for (list_p_command_line_req::iterator it = this->p_requesters_list.begin(); it != this->p_requesters_list.end(); + ++it) + { res += (*it)->GetUsageSynopsis(hidden_options); } res += "\n"; @@ -424,39 +467,46 @@ string CommandLineParser::GetUsage(bool hidden_options, vector excluded_ { string res; - //synopsis + // synopsis res = GetSynopsis(hidden_options); - //description - if (hidden_options == false) { + // description + if (hidden_options == false) + { res += "DESCRIPTION\n"; for (list_p_command_line_req::iterator it = this->p_requesters_list.begin(); - it != this->p_requesters_list.end(); ++it) { + it != this->p_requesters_list.end(); + ++it) + { res += (*it)->GetUsageDescription() + "\n"; } } - //options + // options res += "OPTIONS\n"; - for (list_p_command_line_req::iterator it = this->p_requesters_list.begin(); - it != this->p_requesters_list.end(); ++it) { + for (list_p_command_line_req::iterator it = this->p_requesters_list.begin(); it != this->p_requesters_list.end(); + ++it) + { res += (*it)->GetUsageOptions(hidden_options) + "\n"; } - //optinal sections + // optinal sections for (list_p_command_line_req::iterator req_it = this->p_requesters_list.begin(); - req_it != this->p_requesters_list.end(); ++req_it) { + req_it != this->p_requesters_list.end(); + ++req_it) + { res += (*req_it)->GetUsageOptionalSections(excluded_sections); } return res; } - -ParseStatus CommandLineParser::ParseOptions(int argc, char **argv, - bool to_ignore_unknown_options, list_p_command_line_req *p_ignored_requesters_list) +ParseStatus CommandLineParser::ParseOptions(int argc, + char** argv, + bool to_ignore_unknown_options, + list_p_command_line_req* p_ignored_requesters_list) { - char **internal_argv; - struct option *options_arr = NULL; + char** internal_argv; + struct option* options_arr = NULL; string options_str = ""; vec_bool returned_option_types_vec; ParseStatus rc = PARSE_ERROR; @@ -465,18 +515,22 @@ ParseStatus CommandLineParser::ParseOptions(int argc, char **argv, int option_index = 0; unsigned i = 0; - //allocate internal_argv + // allocate internal_argv internal_argv = new char*[argc]; - if (!internal_argv) { + if (!internal_argv) + { this->SetLastError("Fail to allocate internal argv for parsing"); return PARSE_ERROR; } - for (int j = 0; j < argc; ++j) { + for (int j = 0; j < argc; ++j) + { internal_argv[j] = NULL; } - for (int j = 0; j < argc; ++j) { + for (int j = 0; j < argc; ++j) + { internal_argv[j] = new char[strlen(argv[j]) + 1]; - if (!internal_argv[j]) { + if (!internal_argv[j]) + { this->SetLastError("Fail to allocate internal argv[%u] for parsing", j); rc = PARSE_ERROR; goto argv_err_exit; @@ -484,10 +538,11 @@ ParseStatus CommandLineParser::ParseOptions(int argc, char **argv, strcpy(internal_argv[j], argv[j]); } - //allocate long_options_arr + // allocate long_options_arr num_options = this->long_opt_to_req_map.size(); options_arr = new struct option[num_options + 1]; - if (!options_arr) { + if (!options_arr) + { this->SetLastError("Fail to allocate long_options_arr"); rc = PARSE_ERROR; goto parse_exit; @@ -501,87 +556,117 @@ ParseStatus CommandLineParser::ParseOptions(int argc, char **argv, * that can be return by getopt_long_only() */ i = 0; - for (list_p_command_line_req::iterator it = this->p_requesters_list.begin(); - it != this->p_requesters_list.end(); ++it) { - for (vec_option_t::iterator it2 = (*it)->GetOptions().begin(); - it2 != (*it)->GetOptions().end(); ++it2) { + for (list_p_command_line_req::iterator it = this->p_requesters_list.begin(); it != this->p_requesters_list.end(); + ++it) + { + for (vec_option_t::iterator it2 = (*it)->GetOptions().begin(); it2 != (*it)->GetOptions().end(); ++it2) + { options_str += (*it2).option_short_name; options_arr[i].name = (char*)(*it2).option_name.c_str(); - if ((*it2).option_value != "") { + if ((*it2).option_value != "") + { options_arr[i].has_arg = 1; options_str += ":"; - } else { + } + else + { options_arr[i].has_arg = 0; } options_arr[i].flag = 0; - if ((*it2).option_short_name != ' ') { + if ((*it2).option_short_name != ' ') + { options_arr[i].val = (*it2).option_short_name; - } else { + } + else + { options_arr[i].val = 0; } - if (returned_option_types_vec.empty() || (returned_option_types_vec.size() < (unsigned int)options_arr[i].val + 1)) { + if (returned_option_types_vec.empty() || + (returned_option_types_vec.size() < (unsigned int)options_arr[i].val + 1)) + { for (unsigned j = returned_option_types_vec.size(); j < (unsigned int)options_arr[i].val + 1; ++j) returned_option_types_vec.push_back(false); } returned_option_types_vec[options_arr[i].val] = true; - //printf("%c %d ", options_arr[i].val, options_arr[i].val); + // printf("%c %d ", options_arr[i].val, options_arr[i].val); ++i; } } - //finally parse all options - if (to_ignore_unknown_options == true) { + // finally parse all options + if (to_ignore_unknown_options == true) + { tools_opterr = 0; - } else { + } + else + { tools_opterr = 1; } tools_optind = 0; ParseStatus curr_result; - while ((option_type = tools_getopt_long_only(argc, internal_argv, options_str.c_str(), - options_arr, &option_index)) != -1) { - //printf("option_type=\'%c\'\n", option_type); + while ((option_type = + tools_getopt_long_only(argc, internal_argv, options_str.c_str(), options_arr, &option_index)) != -1) + { + // printf("option_type=\'%c\'\n", option_type); string long_opt_name; - if (option_type == 0) { + if (option_type == 0) + { long_opt_name = options_arr[option_index].name; goto do_handle_option; - } else if (option_type == '?') { - if (to_ignore_unknown_options == true) { + } + else if (option_type == '?') + { + if (to_ignore_unknown_options == true) + { continue; } this->SetLastError("Bad input parameter"); rc = PARSE_ERROR_SHOW_USAGE; goto argv_err_exit; - } else if (returned_option_types_vec[option_type] == true) { + } + else if (returned_option_types_vec[option_type] == true) + { long_opt_name = this->short_opt_to_long_opt[option_type]; goto do_handle_option; - } else { + } + else + { this->SetLastError("getopt_long_only() returned character code 0%o", option_type); goto parse_exit; } -do_handle_option: - CommandLineRequester * p_req = this->long_opt_to_req_map[long_opt_name]; + do_handle_option: + CommandLineRequester* p_req = this->long_opt_to_req_map[long_opt_name]; bool ignore_this_req = false; - if (p_ignored_requesters_list) { + if (p_ignored_requesters_list) + { for (list_p_command_line_req::iterator it = p_ignored_requesters_list->begin(); - it != p_ignored_requesters_list->end(); ++it) { - if (p_req == (*it)) { + it != p_ignored_requesters_list->end(); + ++it) + { + if (p_req == (*it)) + { ignore_this_req = true; break; } } } - if (ignore_this_req == false) { - try{ + if (ignore_this_req == false) + { + try + { curr_result = p_req->HandleOption(long_opt_name, (tools_optarg == NULL) ? "" : tools_optarg); - }catch (std::exception &exc){ + } + catch (std::exception& exc) + { this->SetLastError(exc.what()); goto parse_exit; } - if (curr_result) { + if (curr_result) + { rc = curr_result; this->SetLastError("Failed to handle option %s", long_opt_name.c_str()); goto parse_exit; @@ -590,8 +675,10 @@ ParseStatus CommandLineParser::ParseOptions(int argc, char **argv, continue; } - if (tools_optind < argc) { - while (tools_optind < argc) { + if (tools_optind < argc) + { + while (tools_optind < argc) + { this->last_unknown_options += internal_argv[tools_optind]; this->last_unknown_options += " "; ++tools_optind; @@ -599,7 +686,8 @@ ParseStatus CommandLineParser::ParseOptions(int argc, char **argv, /*if (this->last_unknown_options != "") //remove last space this->last_unknown_options.erase(this->last_unknown_options.end() - 1, this->last_unknown_options.end());*/ - if (to_ignore_unknown_options == false) { + if (to_ignore_unknown_options == false) + { string str = "Found some non-option ARGV-elements "; str += this->last_unknown_options; this->SetLastError(str.c_str()); @@ -610,54 +698,62 @@ ParseStatus CommandLineParser::ParseOptions(int argc, char **argv, rc = PARSE_OK; parse_exit: for (int i = 0; i < argc; ++i) - delete [] internal_argv[i]; - delete [] internal_argv; - delete [] options_arr; + delete[] internal_argv[i]; + delete[] internal_argv; + delete[] options_arr; return rc; argv_err_exit: for (int i = 0; i < argc; ++i) - delete [] internal_argv[i]; - delete [] internal_argv; - if (options_arr) { - delete [] options_arr; + delete[] internal_argv[i]; + delete[] internal_argv; + if (options_arr) + { + delete[] options_arr; } return rc; } - /*Static functions*/ static string CreateIndentFromInt(int ident_size) { string ident = ""; int i; - for (i = 0; i < ident_size; i++) { + for (i = 0; i < ident_size; i++) + { ident += " "; } return ident; } - static void FindAndReplace(string& source, string::size_type pos, string const& find, string const& replace) { - for (string::size_type i = pos; (i = source.find(find, i)) != string::npos;) { + for (string::size_type i = pos; (i = source.find(find, i)) != string::npos;) + { source.replace(i, find.length(), replace); i += replace.length(); } } - -static bool FindAndHandleNewLinePos(string& str, int& product_length, int& local_space_size, int& str_type_len, - int& new_line_pos, string newline_and_ident, int deli_is_space) +static bool FindAndHandleNewLinePos(string& str, + int& product_length, + int& local_space_size, + int& str_type_len, + int& new_line_pos, + string newline_and_ident, + int deli_is_space) { int plus_one_for_space = 1 * deli_is_space; - if (!deli_is_space) { + if (!deli_is_space) + { new_line_pos = str.substr(product_length + local_space_size, str_type_len).find("\n"); - } else { - new_line_pos = str.substr(product_length + local_space_size + 1, str.npos). - find_last_of(" ", str_type_len - 1); } - if ((size_t)new_line_pos != str.npos) { + else + { + new_line_pos = str.substr(product_length + local_space_size + 1, str.npos).find_last_of(" ", str_type_len - 1); + } + if ((size_t)new_line_pos != str.npos) + { new_line_pos += local_space_size + product_length + plus_one_for_space; str.replace(new_line_pos, 1, newline_and_ident); return true; diff --git a/cmdparser/cmdparser.h b/cmdparser/cmdparser.h index 5f7cb6be..564e3701 100644 --- a/cmdparser/cmdparser.h +++ b/cmdparser/cmdparser.h @@ -30,11 +30,9 @@ * SOFTWARE. */ - #ifndef _OPT_PARSER_H_ #define _OPT_PARSER_H_ - #include #include #include @@ -42,39 +40,41 @@ #include using namespace std; - /******************************************************/ typedef enum { - //Returns: 0 - OK / 1 - parsing error / 2 - OK but need to exit / 3 - some other error + // Returns: 0 - OK / 1 - parsing error / 2 - OK but need to exit / 3 - some other error PARSE_OK = 0, PARSE_ERROR = 1, PARSE_OK_WITH_EXIT = 3, PARSE_ERROR_SHOW_USAGE = 4 } ParseStatus; -typedef struct option_ifc { - string option_name; //must be valid - char option_short_name; //can be used as short option, if space than no short flag - string option_value; //if "" has no argument - string description; //will be display in usage - int numOfSpaces; - bool hidden; //if hidden than will not be diaplayed in regular usage +typedef struct option_ifc +{ + string option_name; // must be valid + char option_short_name; // can be used as short option, if space than no short flag + string option_value; // if "" has no argument + string description; // will be display in usage + int numOfSpaces; + bool hidden; // if hidden than will not be diaplayed in regular usage bool is_mandatory; } option_ifc_t; -typedef struct optional_help_section_data { +typedef struct optional_help_section_data +{ // format is: // : (with alignments) - string name; //section's name - string str1; //left string - string str2; //right string + string name; // section's name + string str1; // left string + string str2; // right string } optional_sec_data_t; -typedef vector < struct option_ifc > vec_option_t; -typedef vector < pair < string, vector < struct optional_help_section_data > > > optional_sections_t; +typedef vector vec_option_t; +typedef vector > > optional_sections_t; -class CommandLineRequester { +class CommandLineRequester +{ protected: // members vec_option_t options; @@ -83,7 +83,7 @@ class CommandLineRequester { optional_sections_t optional_sections_vec; // methods - string BuildOptStr(option_ifc_t &opt); + string BuildOptStr(option_ifc_t& opt); string FormatUsageStr(string str, int str_type_len, int ident_size, int is_not_description, bool is_left_side); string GetUsageOptionalSection(vector section_vec); string GetUsageOptional1Str(vector::iterator it); @@ -93,10 +93,7 @@ class CommandLineRequester { // methods CommandLineRequester(string req_name) : name(req_name) {} virtual ~CommandLineRequester() {} - inline void setToolName(string req_name) - { - name = req_name; - } + inline void setToolName(string req_name) { name = req_name; } inline void AddOptions(option_ifc_t options[], int arr_size) { for (int i = 0; i < arr_size; ++i) @@ -108,7 +105,7 @@ class CommandLineRequester { string description, bool hidden = false, bool is_mandatory = false, - int numOfSpaces = 0) + int numOfSpaces = 0) { option_ifc_t opt; opt.option_name = option_name; @@ -120,10 +117,7 @@ class CommandLineRequester { opt.is_mandatory = is_mandatory; this->options.push_back(opt); } - inline void AddDescription(string desc) - { - this->description = desc; - } + inline void AddDescription(string desc) { this->description = desc; } inline vec_option_t& GetOptions() { return this->options; } inline string& GetName() { return this->name; } @@ -140,14 +134,13 @@ class CommandLineRequester { virtual ParseStatus HandleOption(string name, string value) = 0; }; - /******************************************************/ -typedef list < CommandLineRequester* > list_p_command_line_req; -typedef map < char, string > map_char_str; -typedef map < string, CommandLineRequester* > map_str_p_command_line_req; - +typedef list list_p_command_line_req; +typedef map map_char_str; +typedef map map_str_p_command_line_req; -class CommandLineParser { +class CommandLineParser +{ private: // members list_p_command_line_req p_requesters_list; @@ -159,30 +152,25 @@ class CommandLineParser { string last_unknown_options; // methods - void SetLastError(const char *fmt, ...); + void SetLastError(const char* fmt, ...); + public: // methods - CommandLineParser(string parser_name) : - name(parser_name), last_error(""), last_unknown_options("") {} + CommandLineParser(string parser_name) : name(parser_name), last_error(""), last_unknown_options("") {} ~CommandLineParser() {} inline const char* GetErrDesc() { return this->last_error.c_str(); } inline const char* GetUnknownOptions() { return this->last_unknown_options.c_str(); } - inline void setParserName(string parser_name) - { - name = parser_name; - } - int AddRequester(CommandLineRequester *p_req); //if multiple option than fail + inline void setParserName(string parser_name) { name = parser_name; } + int AddRequester(CommandLineRequester* p_req); // if multiple option than fail - ParseStatus ParseOptions(int argc, char **argv, + ParseStatus ParseOptions(int argc, + char** argv, bool to_ignore_unknown_options = false, - list_p_command_line_req *p_ignored_requesters_list = NULL); + list_p_command_line_req* p_ignored_requesters_list = NULL); string GetSynopsis(bool hidden_options = false); string GetUsage(bool hidden_options = false, vector excluded_sections = vector()); }; - -#endif /* not defined _OPT_PARSER_H_ */ - - +#endif /* not defined _OPT_PARSER_H_ */ diff --git a/cmdparser/my_getopt.c b/cmdparser/my_getopt.c index 23400cfe..5a3ed01d 100644 --- a/cmdparser/my_getopt.c +++ b/cmdparser/my_getopt.c @@ -23,24 +23,24 @@ /* This tells Alpha OSF/1 not to define a getopt prototype in . Ditto for AIX 3.2 and . */ - #ifndef _NO_PROTO - #define _NO_PROTO - #endif +#ifndef _NO_PROTO +#define _NO_PROTO +#endif - #ifdef HAVE_CONFIG_H - #include - #endif +#ifdef HAVE_CONFIG_H +#include +#endif - #if !defined(__STDC__) || !__STDC__ +#if !defined(__STDC__) || !__STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ - #ifndef const - #define const - #endif - #endif +#ifndef const +#define const +#endif +#endif - #include - #include +#include +#include /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C @@ -50,50 +50,48 @@ program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ - #define GETOPT_INTERFACE_VERSION 2 - #if !defined(_LIBC) && defined(__GLIBC__) && __GLIBC__ >= 2 - #include - #if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION - #define ELIDE_CODE - #endif - #endif - - +#define GETOPT_INTERFACE_VERSION 2 +#if !defined(_LIBC) && defined(__GLIBC__) && __GLIBC__ >= 2 +#include +#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +#define ELIDE_CODE +#endif +#endif /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ - #ifdef __GNU_LIBRARY__ +#ifdef __GNU_LIBRARY__ /* Don't include stdlib.h for non-GNU C libraries because some of them contain conflicting prototypes for getopt. */ - #include - #include - #endif /* GNU C library. */ - - #ifdef HAVE_STRING_H - # include /* strstr / strdup */ - #else - # ifdef HAVE_STRINGS_H - # include /* strstr / strdup */ - # endif - #endif - - #ifdef VMS - #include - #if HAVE_STRING_H - 0 - #include - #endif - #endif +#include +#include +#endif /* GNU C library. */ + +#ifdef HAVE_STRING_H +#include /* strstr / strdup */ +#else +#ifdef HAVE_STRINGS_H +#include /* strstr / strdup */ +#endif +#endif + +#ifdef VMS +#include +#if HAVE_STRING_H - 0 +#include +#endif +#endif #include - #ifndef _ +#ifndef _ /* This is for other GNU distributions with internationalized messages. When compiling libc, the _ macro is predefined. */ - #ifdef HAVE_LIBINTL_H - # include - # define _(msgid) gettext(msgid) - #else - # define _(msgid) (msgid) - #endif - #endif +#ifdef HAVE_LIBINTL_H +#include +#define _(msgid) gettext(msgid) +#else +#define _(msgid) (msgid) +#endif +#endif /* This version of `getopt' appears to the caller like standard Unix `getopt' but it behaves differently for the user, since it allows the user @@ -109,7 +107,7 @@ GNU application programs can use a third alternative mode in which they can distinguish the relative order of options and other arguments. */ - #include "my_getopt.h" +#include "my_getopt.h" /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, @@ -117,7 +115,7 @@ Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ -char *tools_optarg = NULL; +char* tools_optarg = NULL; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller @@ -147,7 +145,7 @@ int __getopt_initialized = 0; If this is zero, or a null string, it means resume the scan by advancing to the next ARGV-element. */ -static char *nextchar; +static char* nextchar; /* Callers store zero here to inhibit the error message for unrecognized options. */ @@ -189,30 +187,30 @@ int tools_optopt = '?'; of the value of `ordering'. In the case of RETURN_IN_ORDER, only `--' can cause `getopt' to return -1 with `tools_optind' != ARGC. */ -static enum -{ - REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER -} ordering; +static enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering; /* Value of POSIXLY_CORRECT environment variable. */ -static char *posixly_correct; +static char* posixly_correct; - #ifdef __GNU_LIBRARY__ +#ifdef __GNU_LIBRARY__ /* We want to avoid inclusion of string.h with non-GNU libraries because there are many ways it can cause trouble. On some systems, it contains special magic macros that don't work in GCC. */ - #include - #define my_index strchr - #else +#include +#define my_index strchr +#else /* Avoid depending on library functions or files whose names are inconsistent. */ -static char* my_index(const char *str, const char chr) { - while (*str) { - if (*str == chr) { - return (char*) str; +static char* my_index(const char* str, const char chr) +{ + while (*str) + { + if (*str == chr) + { + return (char*)str; } str++; } @@ -221,17 +219,17 @@ static char* my_index(const char *str, const char chr) { /* If using GCC, we can safely declare strlen this way. If not using GCC, it is ok not to declare it. */ - #ifdef __GNUC__ +#ifdef __GNUC__ /* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. That was relevant to code that was here before. */ - #if !defined(__STDC__) || !__STDC__ +#if !defined(__STDC__) || !__STDC__ /* gcc with -traditional declares the built-in strlen to return int, and has done so at least since version 2.4.5. -- rms. */ extern int strlen(const char*); - #endif /* not __STDC__ */ - #endif /* __GNUC__ */ +#endif /* not __STDC__ */ +#endif /* __GNUC__ */ - #endif /* not __GNU_LIBRARY__ */ +#endif /* not __GNU_LIBRARY__ */ /* Handle permutation of arguments. */ @@ -242,44 +240,43 @@ extern int strlen(const char*); static int first_nonopt; static int last_nonopt; - #ifdef _LIBC +#ifdef _LIBC /* Bash 2.0 gives us an environment variable containing flags indicating ARGV elements that should not be considered arguments. */ /* Defined in getopt_init.c */ -extern char *__getopt_nonoption_flags; +extern char* __getopt_nonoption_flags; static int nonoption_flags_max_len; static int nonoption_flags_len; static int original_argc; -static char*const *original_argv; +static char* const* original_argv; /* Make sure the environment variable bash 2.0 puts in the environment is valid for the getopt call we must make sure that the ARGV passed to getopt is that one passed to the process. */ -static void -__attribute__ ((unused)) store_args_and_env(int argc, char*const *argv) +static void __attribute__((unused)) store_args_and_env(int argc, char* const* argv) { /* XXX This is no good solution. We should rather copy the args so that we can compare them later. But we must not use malloc(3). */ original_argc = argc; original_argv = argv; } - # ifdef text_set_element +#ifdef text_set_element text_set_element(__libc_subinit, store_args_and_env); - # endif /* text_set_element */ - - # define SWAP_FLAGS(ch1, ch2) \ - if (nonoption_flags_len > 0) \ - { \ - char __tmp = __getopt_nonoption_flags[ch1]; \ - __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ - __getopt_nonoption_flags[ch2] = __tmp; \ +#endif /* text_set_element */ + +#define SWAP_FLAGS(ch1, ch2) \ + if (nonoption_flags_len > 0) \ + { \ + char __tmp = __getopt_nonoption_flags[ch1]; \ + __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ + __getopt_nonoption_flags[ch2] = __tmp; \ } - #else /* !_LIBC */ - # define SWAP_FLAGS(ch1, ch2) - #endif /* _LIBC */ +#else /* !_LIBC */ +#define SWAP_FLAGS(ch1, ch2) +#endif /* _LIBC */ /* Exchange two adjacent subsequences of ARGV. One subsequence is elements [first_nonopt,last_nonopt) @@ -290,50 +287,56 @@ text_set_element(__libc_subinit, store_args_and_env); `first_nonopt' and `last_nonopt' are relocated so that they describe the new indices of the non-options in ARGV after they are moved. */ - #if defined(__STDC__) && __STDC__ +#if defined(__STDC__) && __STDC__ static void exchange(char**); - #endif +#endif -static void exchange(char **argv) +static void exchange(char** argv) { int bottom = first_nonopt; int middle = last_nonopt; int top = tools_optind; - char *tem; + char* tem; /* Exchange the shorter segment with the far end of the longer segment. That puts the shorter segment into the right place. It leaves the longer segment in the right place overall, but it consists of two parts that need to be swapped next. */ - #ifdef _LIBC +#ifdef _LIBC /* First make sure the handling of the `__getopt_nonoption_flags' string can work normally. Our top argument must be in the range of the string. */ - if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) { + if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) + { /* We must extend the array. The user plays games with us and presents new arguments. */ - char *new_str = malloc(top + 1); - if (new_str == NULL) { + char* new_str = malloc(top + 1); + if (new_str == NULL) + { nonoption_flags_len = nonoption_flags_max_len = 0; - } else { - memset(__mempcpy(new_str, __getopt_nonoption_flags, - nonoption_flags_max_len), - '\0', top + 1 - nonoption_flags_max_len); + } + else + { + memset(__mempcpy(new_str, __getopt_nonoption_flags, nonoption_flags_max_len), '\0', + top + 1 - nonoption_flags_max_len); nonoption_flags_max_len = top + 1; __getopt_nonoption_flags = new_str; } } - #endif +#endif - while (top > middle && middle > bottom) { - if (top - middle > middle - bottom) { + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { /* Bottom segment is the short one. */ int len = middle - bottom; register int i; /* Swap it with the top part of the top segment. */ - for (i = 0; i < len; i++) { + for (i = 0; i < len; i++) + { tem = argv[bottom + i]; argv[bottom + i] = argv[top - (middle - bottom) + i]; argv[top - (middle - bottom) + i] = tem; @@ -341,13 +344,16 @@ static void exchange(char **argv) } /* Exclude the moved bottom segment from further swapping. */ top -= len; - } else { + } + else + { /* Top segment is the short one. */ int len = top - middle; register int i; /* Swap it with the bottom part of the bottom segment. */ - for (i = 0; i < len; i++) { + for (i = 0; i < len; i++) + { tem = argv[bottom + i]; argv[bottom + i] = argv[middle + i]; argv[middle + i] = tem; @@ -366,17 +372,17 @@ static void exchange(char **argv) /* Initialize the internal data when the first call is made. */ - #if defined(__STDC__) && __STDC__ -static const char* _getopt_initialize(int, char*const*, const char*); - #endif -static const char* _getopt_initialize(int argc, char* const *argv, const char *optstring) +#if defined(__STDC__) && __STDC__ +static const char* _getopt_initialize(int, char* const*, const char*); +#endif +static const char* _getopt_initialize(int argc, char* const* argv, const char* optstring) { /* Start processing options with ARGV-element 1 (since ARGV-element 0 is the program name); the sequence of previously skipped non-option ARGV-elements is empty. */ // avoid compiler warnings - (void) argc; - (void) argv; + (void)argc; + (void)argv; first_nonopt = last_nonopt = tools_optind; nextchar = NULL; @@ -385,46 +391,60 @@ static const char* _getopt_initialize(int argc, char* const *argv, const char *o /* Determine how to handle the ordering of options and nonoptions. */ - if (optstring[0] == '-') { + if (optstring[0] == '-') + { ordering = RETURN_IN_ORDER; ++optstring; - } else if (optstring[0] == '+') { + } + else if (optstring[0] == '+') + { ordering = REQUIRE_ORDER; ++optstring; - } else if (posixly_correct != NULL) { + } + else if (posixly_correct != NULL) + { ordering = REQUIRE_ORDER; - } else { + } + else + { ordering = PERMUTE; } - #ifdef _LIBC - if (posixly_correct == NULL - && argc == original_argc && argv == original_argv) { - if (nonoption_flags_max_len == 0) { - if (__getopt_nonoption_flags == NULL - || __getopt_nonoption_flags[0] == '\0') { +#ifdef _LIBC + if (posixly_correct == NULL && argc == original_argc && argv == original_argv) + { + if (nonoption_flags_max_len == 0) + { + if (__getopt_nonoption_flags == NULL || __getopt_nonoption_flags[0] == '\0') + { nonoption_flags_max_len = -1; - } else { - const char *orig_str = __getopt_nonoption_flags; + } + else + { + const char* orig_str = __getopt_nonoption_flags; int len = nonoption_flags_max_len = strlen(orig_str); - if (nonoption_flags_max_len < argc) { + if (nonoption_flags_max_len < argc) + { nonoption_flags_max_len = argc; } - __getopt_nonoption_flags = - (char*) malloc(nonoption_flags_max_len); - if (__getopt_nonoption_flags == NULL) { + __getopt_nonoption_flags = (char*)malloc(nonoption_flags_max_len); + if (__getopt_nonoption_flags == NULL) + { nonoption_flags_max_len = -1; - } else { - memset(__mempcpy(__getopt_nonoption_flags, orig_str, len), - '\0', nonoption_flags_max_len - len); + } + else + { + memset(__mempcpy(__getopt_nonoption_flags, orig_str, len), '\0', nonoption_flags_max_len - len); } } } nonoption_flags_len = nonoption_flags_max_len; - } else { + } + else + { nonoption_flags_len = 0; } - #endif +#endif return optstring; } @@ -485,13 +505,20 @@ static const char* _getopt_initialize(int argc, char* const *argv, const char *o If LONG_ONLY is nonzero, '-' as well as '--' can introduce long-named options. */ -int _getopt_internal(int argc, char* const *argv, const char *optstring, const struct option *longopts, int *longind, int long_only) +int _getopt_internal(int argc, + char* const* argv, + const char* optstring, + const struct option* longopts, + int* longind, + int long_only) { tools_optarg = NULL; - if (tools_optind == 0 || !__getopt_initialized) { - if (tools_optind == 0) { - tools_optind = 1; /* Don't scan ARGV[0], the program name. */ + if (tools_optind == 0 || !__getopt_initialized) + { + if (tools_optind == 0) + { + tools_optind = 1; /* Don't scan ARGV[0], the program name. */ } optstring = _getopt_initialize(argc, argv, optstring); __getopt_initialized = 1; @@ -501,40 +528,48 @@ int _getopt_internal(int argc, char* const *argv, const char *optstring, const s Either it does not have option syntax, or there is an environment flag from the shell indicating it is not an option. The later information is only used when the used in the GNU libc. */ - #ifdef _LIBC - #define NONOPTION_P (argv[tools_optind][0] != '-' || argv[tools_optind][1] == '\0' \ - || (tools_optind < nonoption_flags_len \ - && __getopt_nonoption_flags[tools_optind] == '1')) - #else - #define NONOPTION_P (argv[tools_optind][0] != '-' || argv[tools_optind][1] == '\0') - #endif - - if (nextchar == NULL || *nextchar == '\0') { +#ifdef _LIBC +#define NONOPTION_P \ + (argv[tools_optind][0] != '-' || argv[tools_optind][1] == '\0' || \ + (tools_optind < nonoption_flags_len && __getopt_nonoption_flags[tools_optind] == '1')) +#else +#define NONOPTION_P (argv[tools_optind][0] != '-' || argv[tools_optind][1] == '\0') +#endif + + if (nextchar == NULL || *nextchar == '\0') + { /* Advance to the next ARGV-element. */ /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been moved back by the user (who may also have changed the arguments). */ - if (last_nonopt > tools_optind) { + if (last_nonopt > tools_optind) + { last_nonopt = tools_optind; } - if (first_nonopt > tools_optind) { + if (first_nonopt > tools_optind) + { first_nonopt = tools_optind; } - if (ordering == PERMUTE) { + if (ordering == PERMUTE) + { /* If we have just processed some options following some non-options, exchange them so that the options come first. */ - if (first_nonopt != last_nonopt && last_nonopt != tools_optind) { - exchange((char**) argv); - } else if (last_nonopt != tools_optind) { + if (first_nonopt != last_nonopt && last_nonopt != tools_optind) + { + exchange((char**)argv); + } + else if (last_nonopt != tools_optind) + { first_nonopt = tools_optind; } /* Skip any additional non-options and extend the range of non-options previously skipped. */ - while (tools_optind < argc && NONOPTION_P) { + while (tools_optind < argc && NONOPTION_P) + { tools_optind++; } last_nonopt = tools_optind; @@ -545,12 +580,16 @@ int _getopt_internal(int argc, char* const *argv, const char *optstring, const s then exchange with previous non-options as if it were an option, then skip everything else like a non-option. */ - if (tools_optind != argc && !strcmp(argv[tools_optind], "--")) { + if (tools_optind != argc && !strcmp(argv[tools_optind], "--")) + { tools_optind++; - if (first_nonopt != last_nonopt && last_nonopt != tools_optind) { - exchange((char**) argv); - } else if (first_nonopt == last_nonopt) { + if (first_nonopt != last_nonopt && last_nonopt != tools_optind) + { + exchange((char**)argv); + } + else if (first_nonopt == last_nonopt) + { first_nonopt = tools_optind; } last_nonopt = argc; @@ -561,10 +600,12 @@ int _getopt_internal(int argc, char* const *argv, const char *optstring, const s /* If we have done all the ARGV-elements, stop the scan and back over any non-options that we skipped and permuted. */ - if (tools_optind == argc) { + if (tools_optind == argc) + { /* Set the next-arg-index to point at the non-options that we previously skipped, so the caller will digest them. */ - if (first_nonopt != last_nonopt) { + if (first_nonopt != last_nonopt) + { tools_optind = first_nonopt; } return -1; @@ -573,8 +614,10 @@ int _getopt_internal(int argc, char* const *argv, const char *optstring, const s /* If we have come to a non-option and did not permute it, either stop the scan or describe it to the caller and pass it by. */ - if (NONOPTION_P) { - if (ordering == REQUIRE_ORDER) { + if (NONOPTION_P) + { + if (ordering == REQUIRE_ORDER) + { return -1; } tools_optarg = argv[tools_optind++]; @@ -584,8 +627,7 @@ int _getopt_internal(int argc, char* const *argv, const char *optstring, const s /* We have found another option-ARGV-element. Skip the initial punctuation. */ - nextchar = (argv[tools_optind] + 1 - + (longopts != NULL && argv[tools_optind][1] == '-')); + nextchar = (argv[tools_optind] + 1 + (longopts != NULL && argv[tools_optind][1] == '-')); } /* Decode the current option-ARGV-element. */ @@ -603,12 +645,12 @@ int _getopt_internal(int argc, char* const *argv, const char *optstring, const s This distinction seems to be the most useful approach. */ - if (longopts != NULL - && (argv[tools_optind][1] == '-' - || (long_only && (argv[tools_optind][2] || !my_index(optstring, argv[tools_optind][1]))))) { - char *nameend; - const struct option *p; - const struct option *pfound = NULL; + if (longopts != NULL && (argv[tools_optind][1] == '-' || + (long_only && (argv[tools_optind][2] || !my_index(optstring, argv[tools_optind][1]))))) + { + char* nameend; + const struct option* p; + const struct option* pfound = NULL; int exact = 0; int ambig = 0; int indfound = -1; @@ -620,28 +662,34 @@ int _getopt_internal(int argc, char* const *argv, const char *optstring, const s /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) - if (!strncmp(p->name, nextchar, nameend - nextchar)) { - if ((unsigned int) (nameend - nextchar) - == (unsigned int) strlen(p->name)) { + if (!strncmp(p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int)(nameend - nextchar) == (unsigned int)strlen(p->name)) + { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; - } else if (pfound == NULL) { + } + else if (pfound == NULL) + { /* First nonexact match found. */ pfound = p; indfound = option_index; - } else { + } + else + { /* Second or later nonexact match found. */ ambig = 1; } } - if (ambig && !exact) { - if (tools_opterr) { - fprintf(stderr, _("%s: option `%s' is ambiguous\n"), - argv[0], argv[tools_optind]); + if (ambig && !exact) + { + if (tools_opterr) + { + fprintf(stderr, _("%s: option `%s' is ambiguous\n"), argv[0], argv[tools_optind]); } nextchar += strlen(nextchar); tools_optind++; @@ -649,26 +697,32 @@ int _getopt_internal(int argc, char* const *argv, const char *optstring, const s return '?'; } - if (pfound != NULL) { + if (pfound != NULL) + { option_index = indfound; tools_optind++; - if (*nameend) { + if (*nameend) + { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ - if (pfound->has_arg) { + if (pfound->has_arg) + { tools_optarg = nameend + 1; - } else { - if (tools_opterr) { - if (argv[tools_optind - 1][1] == '-') { + } + else + { + if (tools_opterr) + { + if (argv[tools_optind - 1][1] == '-') + { /* --option */ - fprintf(stderr, - _("%s: option `--%s' doesn't allow an argument\n"), - argv[0], pfound->name); - } else { + fprintf(stderr, _("%s: option `--%s' doesn't allow an argument\n"), argv[0], pfound->name); + } + else + { /* +option or -option */ - fprintf(stderr, - _("%s: option `%c%s' doesn't allow an argument\n"), - argv[0], argv[tools_optind - 1][0], pfound->name); + fprintf(stderr, _("%s: option `%c%s' doesn't allow an argument\n"), argv[0], + argv[tools_optind - 1][0], pfound->name); } } nextchar += strlen(nextchar); @@ -676,14 +730,18 @@ int _getopt_internal(int argc, char* const *argv, const char *optstring, const s tools_optopt = pfound->val; return '?'; } - } else if (pfound->has_arg == 1) { - if (tools_optind < argc) { + } + else if (pfound->has_arg == 1) + { + if (tools_optind < argc) + { tools_optarg = argv[tools_optind++]; - } else { - if (tools_opterr) { - fprintf(stderr, - _("%s: option `%s' requires an argument\n"), - argv[0], argv[tools_optind - 1]); + } + else + { + if (tools_opterr) + { + fprintf(stderr, _("%s: option `%s' requires an argument\n"), argv[0], argv[tools_optind - 1]); } nextchar += strlen(nextchar); tools_optopt = pfound->val; @@ -691,10 +749,12 @@ int _getopt_internal(int argc, char* const *argv, const char *optstring, const s } } nextchar += strlen(nextchar); - if (longind != NULL) { + if (longind != NULL) + { *longind = option_index; } - if (pfound->flag) { + if (pfound->flag) + { *(pfound->flag) = pfound->val; return 0; } @@ -705,20 +765,22 @@ int _getopt_internal(int argc, char* const *argv, const char *optstring, const s or the option starts with '--' or is not a valid short option, then it's an error. Otherwise interpret it as a short option. */ - if (!long_only || argv[tools_optind][1] == '-' - || my_index(optstring, *nextchar) == NULL) { - if (tools_opterr) { - if (argv[tools_optind][1] == '-') { + if (!long_only || argv[tools_optind][1] == '-' || my_index(optstring, *nextchar) == NULL) + { + if (tools_opterr) + { + if (argv[tools_optind][1] == '-') + { /* --option */ - fprintf(stderr, _("%s: unrecognized option `--%s'\n"), - argv[0], nextchar); - } else { + fprintf(stderr, _("%s: unrecognized option `--%s'\n"), argv[0], nextchar); + } + else + { /* +option or -option */ - fprintf(stderr, _("%s: unrecognized option `%c%s'\n"), - argv[0], argv[tools_optind][0], nextchar); + fprintf(stderr, _("%s: unrecognized option `%c%s'\n"), argv[0], argv[tools_optind][0], nextchar); } } - nextchar = (char*) ""; + nextchar = (char*)""; tools_optind++; tools_optopt = 0; return '?'; @@ -729,57 +791,70 @@ int _getopt_internal(int argc, char* const *argv, const char *optstring, const s { char c = *nextchar++; - char *temp = my_index(optstring, c); + char* temp = my_index(optstring, c); /* Increment `tools_optind' when we start to process its last character. */ - if (*nextchar == '\0') { + if (*nextchar == '\0') + { ++tools_optind; } - if (temp == NULL || c == ':') { - if (tools_opterr) { - if (posixly_correct) { + if (temp == NULL || c == ':') + { + if (tools_opterr) + { + if (posixly_correct) + { /* 1003.2 specifies the format of this message. */ - fprintf(stderr, _("%s: illegal option -- %c\n"), - argv[0], c); - } else { - fprintf(stderr, _("%s: invalid option -- %c\n"), - argv[0], c); + fprintf(stderr, _("%s: illegal option -- %c\n"), argv[0], c); + } + else + { + fprintf(stderr, _("%s: invalid option -- %c\n"), argv[0], c); } } tools_optopt = c; return '?'; } /* Convenience. Treat POSIX -W foo same as long option --foo */ - if (temp[0] == 'W' && temp[1] == ';') { - char *nameend; - const struct option *p; - const struct option *pfound = NULL; + if (temp[0] == 'W' && temp[1] == ';') + { + char* nameend; + const struct option* p; + const struct option* pfound = NULL; int exact = 0; int ambig = 0; int indfound = 0; int option_index; /* This is an option that requires an argument. */ - if (*nextchar != '\0') { + if (*nextchar != '\0') + { tools_optarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ tools_optind++; - } else if (tools_optind == argc) { - if (tools_opterr) { + } + else if (tools_optind == argc) + { + if (tools_opterr) + { /* 1003.2 specifies the format of this message. */ - fprintf(stderr, _("%s: option requires an argument -- %c\n"), - argv[0], c); + fprintf(stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); } tools_optopt = c; - if (optstring[0] == ':') { + if (optstring[0] == ':') + { c = ':'; - } else { + } + else + { c = '?'; } return c; - } else { + } + else + { /* We already incremented `tools_optind' once; increment it again when taking next ARGV-elt as argument. */ tools_optarg = argv[tools_optind++]; @@ -794,40 +869,53 @@ int _getopt_internal(int argc, char* const *argv, const char *optstring, const s /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) - if (!strncmp(p->name, nextchar, nameend - nextchar)) { - if ((unsigned int) (nameend - nextchar) == strlen(p->name)) { + if (!strncmp(p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int)(nameend - nextchar) == strlen(p->name)) + { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; - } else if (pfound == NULL) { + } + else if (pfound == NULL) + { /* First nonexact match found. */ pfound = p; indfound = option_index; - } else { + } + else + { /* Second or later nonexact match found. */ ambig = 1; } } - if (ambig && !exact) { - if (tools_opterr) { - fprintf(stderr, _("%s: option `-W %s' is ambiguous\n"), - argv[0], argv[tools_optind]); + if (ambig && !exact) + { + if (tools_opterr) + { + fprintf(stderr, _("%s: option `-W %s' is ambiguous\n"), argv[0], argv[tools_optind]); } nextchar += strlen(nextchar); tools_optind++; return '?'; } - if (pfound != NULL) { + if (pfound != NULL) + { option_index = indfound; - if (*nameend) { + if (*nameend) + { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ - if (pfound->has_arg) { + if (pfound->has_arg) + { tools_optarg = nameend + 1; - } else { - if (tools_opterr) { + } + else + { + if (tools_opterr) + { fprintf(stderr, _("\ %s: option `-W %s' doesn't allow an argument\n"), argv[0], pfound->name); @@ -836,63 +924,84 @@ int _getopt_internal(int argc, char* const *argv, const char *optstring, const s nextchar += strlen(nextchar); return '?'; } - } else if (pfound->has_arg == 1) { - if (tools_optind < argc) { + } + else if (pfound->has_arg == 1) + { + if (tools_optind < argc) + { tools_optarg = argv[tools_optind++]; - } else { - if (tools_opterr) { - fprintf(stderr, - _("%s: option `%s' requires an argument\n"), - argv[0], argv[tools_optind - 1]); + } + else + { + if (tools_opterr) + { + fprintf(stderr, _("%s: option `%s' requires an argument\n"), argv[0], + argv[tools_optind - 1]); } nextchar += strlen(nextchar); return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen(nextchar); - if (longind != NULL) { + if (longind != NULL) + { *longind = option_index; } - if (pfound->flag) { + if (pfound->flag) + { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } nextchar = NULL; - return 'W'; /* Let the application handle it. */ + return 'W'; /* Let the application handle it. */ } - if (temp[1] == ':') { - if (temp[2] == ':') { + if (temp[1] == ':') + { + if (temp[2] == ':') + { /* This is an option that accepts an argument optionally. */ - if (*nextchar != '\0') { + if (*nextchar != '\0') + { tools_optarg = nextchar; tools_optind++; - } else { + } + else + { tools_optarg = NULL; } nextchar = NULL; - } else { + } + else + { /* This is an option that requires an argument. */ - if (*nextchar != '\0') { + if (*nextchar != '\0') + { tools_optarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ tools_optind++; - } else if (tools_optind == argc) { - if (tools_opterr) { + } + else if (tools_optind == argc) + { + if (tools_opterr) + { /* 1003.2 specifies the format of this message. */ - fprintf(stderr, - _("%s: option requires an argument -- %c\n"), - argv[0], c); + fprintf(stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); } tools_optopt = c; - if (optstring[0] == ':') { + if (optstring[0] == ':') + { c = ':'; - } else { + } + else + { c = '?'; } - } else { + } + else + { /* We already incremented `tools_optind' once; increment it again when taking next ARGV-elt as argument. */ tools_optarg = argv[tools_optind++]; @@ -904,92 +1013,90 @@ int _getopt_internal(int argc, char* const *argv, const char *optstring, const s } } -int tools_getopt(int argc, char* const *argv, const char *optstring) +int tools_getopt(int argc, char* const* argv, const char* optstring) { - return _getopt_internal(argc, argv, optstring, - (const struct option*) 0, - (int*) 0, - 0); + return _getopt_internal(argc, argv, optstring, (const struct option*)0, (int*)0, 0); } -int tools_getopt_long(int argc, char* const *argv, const char *optstring, const struct option *longopts, int *longindex) +int tools_getopt_long(int argc, char* const* argv, const char* optstring, const struct option* longopts, int* longindex) { - return _getopt_internal(argc, argv, optstring, - longopts, - longindex, - 0); + return _getopt_internal(argc, argv, optstring, longopts, longindex, 0); } - -int tools_getopt_long_only(int argc, char* const *argv, const char *optstring, const struct option *longopts, int *longindex) +int tools_getopt_long_only(int argc, + char* const* argv, + const char* optstring, + const struct option* longopts, + int* longindex) { - return _getopt_internal(argc, argv, optstring, - longopts, - longindex, - 1); + return _getopt_internal(argc, argv, optstring, longopts, longindex, 1); } - - #ifdef TEST +#ifdef TEST /* Compile with -DTEST to make an executable for use in testing the above definition of `getopt'. */ -int main(int argc, char **argv) +int main(int argc, char** argv) { int c; int digit_optind = 0; - while (1) { + while (1) + { int this_option_optind = tools_optind ? tools_optind : 1; c = getopt(argc, argv, "abc:d:0123456789"); - if (c == -1) { + if (c == -1) + { break; } switch (c) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (digit_optind != 0 && digit_optind != this_option_optind) { - printf("digits occur in two different argv-elements.\n"); - } - digit_optind = this_option_optind; - printf("option %c\n", c); - break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + { + printf("digits occur in two different argv-elements.\n"); + } + digit_optind = this_option_optind; + printf("option %c\n", c); + break; - case 'a': - printf("option a\n"); - break; + case 'a': + printf("option a\n"); + break; - case 'b': - printf("option b\n"); - break; + case 'b': + printf("option b\n"); + break; - case 'c': - printf("option c with value `%s'\n", tools_optarg); - break; + case 'c': + printf("option c with value `%s'\n", tools_optarg); + break; - case '?': - break; + case '?': + break; - default: - printf("?? getopt returned character code 0%o ??\n", c); + default: + printf("?? getopt returned character code 0%o ??\n", c); } } - if (tools_optind < argc) { + if (tools_optind < argc) + { printf("non-option ARGV-elements: "); - while (tools_optind < argc) { + while (tools_optind < argc) + { printf("%s ", argv[tools_optind++]); } printf("\n"); @@ -998,7 +1105,7 @@ int main(int argc, char **argv) exit(0); } - #endif /* TEST */ +#endif /* TEST */ int hello() { diff --git a/cmdparser/my_getopt.h b/cmdparser/my_getopt.h index 932563ab..6aa6be27 100644 --- a/cmdparser/my_getopt.h +++ b/cmdparser/my_getopt.h @@ -17,106 +17,99 @@ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - #ifndef _TOOLS_GETOPT_H - #define _TOOLS_GETOPT_H +#ifndef _TOOLS_GETOPT_H +#define _TOOLS_GETOPT_H - #ifdef __cplusplus -extern "C" { - #endif +#ifdef __cplusplus +extern "C" +{ +#endif -/* For communication from `getopt' to the caller. - When `getopt' finds an option that takes an argument, - the argument value is returned here. - Also, when `ordering' is RETURN_IN_ORDER, - each non-option ARGV-element is returned here. */ + /* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ -extern char *tools_optarg; + extern char* tools_optarg; -/* Index in ARGV of the next element to be scanned. - This is used for communication to and from the caller - and for communication between successive calls to `getopt'. + /* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. - On entry to `getopt', zero means this is the first call; initialize. + On entry to `getopt', zero means this is the first call; initialize. - When `getopt' returns -1, this is the index of the first of the - non-option elements that the caller should itself scan. + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. - Otherwise, `optind' communicates from one call to the next - how much of ARGV has been scanned so far. */ + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ -extern int tools_optind; + extern int tools_optind; -/* Callers store zero here to inhibit the error message `getopt' prints - for unrecognized options. */ + /* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ -extern int tools_opterr; + extern int tools_opterr; -/* Set to an option character which was unrecognized. */ + /* Set to an option character which was unrecognized. */ -extern int tools_optopt; + extern int tools_optopt; -/* Describe the long-named options requested by the application. - The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector - of `struct option' terminated by an element containing a name which is - zero. + /* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. - The field `has_arg' is: - no_argument (or 0) if the option does not take an argument, - required_argument (or 1) if the option requires an argument, - optional_argument (or 2) if the option takes an optional argument. + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. - If the field `flag' is not NULL, it points to a variable that is set - to the value given in the field `val' when the option is found, but - left unchanged if the option is not found. + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. - To have a long-named option do something other than set an `int' to - a compiled-in constant, such as set a value from `optarg', set the - option's `flag' field to zero and its `val' field to a nonzero - value (the equivalent single-letter option character, if there is - one). For long options that have a zero `flag' field, `getopt' - returns the contents of the `val' field. */ + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ -struct option -{ - #if defined(__STDC__) && __STDC__ - const char *name; - #else - char *name; - #endif - /* has_arg can't be an enum because some compilers complain about - type mismatches in all the code that assumes it is an int. */ - int has_arg; - int *flag; - int val; -}; - -/* Names for the values of the `has_arg' field of `struct option'. */ - - #define tools_no_argument 0 - #define tools_required_argument 1 - #define tools_optional_argument 2 - -int tools_getopt( - int argc, - char*const *argv, - const char *shortopts); - -int tools_getopt_long( - int argc, - char*const *argv, - const char *shortopts, - const struct option *longopts, - int *longind); - -int tools_getopt_long_only( - int argc, - char*const *argv, - const char *shortopts, - const struct option *longopts, - int *longind); - - #ifdef __cplusplus + struct option + { +#if defined(__STDC__) && __STDC__ + const char* name; +#else + char* name; +#endif + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int* flag; + int val; + }; + + /* Names for the values of the `has_arg' field of `struct option'. */ + +#define tools_no_argument 0 +#define tools_required_argument 1 +#define tools_optional_argument 2 + + int tools_getopt(int argc, char* const* argv, const char* shortopts); + + int + tools_getopt_long(int argc, char* const* argv, const char* shortopts, const struct option* longopts, int* longind); + + int tools_getopt_long_only(int argc, + char* const* argv, + const char* shortopts, + const struct option* longopts, + int* longind); + +#ifdef __cplusplus } - #endif +#endif - #endif /* _TOOLS_GETOPT_H */ +#endif /* _TOOLS_GETOPT_H */ diff --git a/common/autocomplete/mft_help_to_completion.py b/common/autocomplete/mft_help_to_completion.py index 0a9a544a..2fad2a7b 100755 --- a/common/autocomplete/mft_help_to_completion.py +++ b/common/autocomplete/mft_help_to_completion.py @@ -1,4 +1,4 @@ -#-- +# -- # Copyright (c) 2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # # This software is available to you under a choice of one of two @@ -28,7 +28,7 @@ # 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. -#-- +# -- #!/usr/bin/python ### imports ### @@ -37,42 +37,46 @@ import subprocess import argparse -def buildTree( linesList, tabIndex, nodeSons ): + +def buildTree(linesList, tabIndex, nodeSons): if len(linesList) == 0: - return ("" , nodeSons) + return ("", nodeSons) nodeStr = linesList[0] if not isNodeStr(nodeStr): - return buildTree( linesList[1:], tabIndex, nodeSons ) + return buildTree(linesList[1:], tabIndex, nodeSons) nodeTab = getNodeTab(nodeStr) if nodeTab == tabIndex: return (nodeSons, linesList) if (tabIndex - nodeTab) == 1: - nodeName=getNodeName(nodeStr) - remineLines, nodeSons = buildTree(linesList[1:], nodeTab, [] ) - nodeStruct={ 'nodeName' : nodeName , 'nodeSons' : nodeSons } - return buildTree( linesList[1:], nodeTab, nodeSons.add(nodeStruct) ) + nodeName = getNodeName(nodeStr) + remineLines, nodeSons = buildTree(linesList[1:], nodeTab, []) + nodeStruct = {'nodeName': nodeName, 'nodeSons': nodeSons} + return buildTree(linesList[1:], nodeTab, nodeSons.add(nodeStruct)) + def isNewNode(line, queryCommand): if queryCommand: if ":" in line: - index = line.find(":") - charBF = line[index-1] + index = line.find(":") + charBF = line[index - 1] return (charBF == "" or charBF == " ") removeLeadingZero = line.strip(" ") if removeLeadingZero and removeLeadingZero[0] == "-": return True return False + def isInfoFlag(line): if line[0] != " " and line[0] != "-": return True return False + def keepOnlyNodes(filesList): - helpLineOnlyNodes=[] + helpLineOnlyNodes = [] onNodedescription = False queryCommand = False - node="" + node = "" for line in filesList: if line.strip(" ") == "" or line == '\n': continue @@ -87,133 +91,143 @@ def keepOnlyNodes(filesList): onNodedescription = False continue if isNewNode(line, queryCommand): - if node!= "": + if node != "": helpLineOnlyNodes.append(node) onNodedescription = True - node=line + node = line if ":" not in line: - node=node+" :" + node = node + " :" continue if onNodedescription: - node=node+" " + line.strip(" ") + node = node + " " + line.strip(" ") helpLineOnlyNodes.append(node) return helpLineOnlyNodes -#-l |--loopback : Configure Loopback Mode [NO(no loopback)/PH(phy loopback)/EX(external loopback)] +# -l |--loopback : Configure Loopback Mode [NO(no loopback)/PH(phy loopback)/EX(external loopback)] def isShortCutsLine(line): if "|" in line: - lineSplit=line.split("|")[0].strip(" ") - lineSpaceSplit=lineSplit.split(" ") - lineSpaceWords = list(filter( lambda x: x != "" ,lineSpaceSplit)) + lineSplit = line.split("|")[0].strip(" ") + lineSpaceSplit = lineSplit.split(" ") + lineSpaceWords = list(filter(lambda x: x != "", lineSpaceSplit)) return (len(lineSpaceWords) <= 1) return False + def getNodeShortCutsAndName(line): - shortCuts="" - name="" + shortCuts = "" + name = "" line = line.strip(" ") if isShortCutsLine(line): lineSplit = line.split("|") - rightFlag=lineSplit[0].strip(" ") - leftFlag=lineSplit[1].strip(" ").split(" ")[0] + rightFlag = lineSplit[0].strip(" ") + leftFlag = lineSplit[1].strip(" ").split(" ")[0] if len(rightFlag) > len(leftFlag): return leftFlag, rightFlag else: return rightFlag, leftFlag - name=line.split(" ")[0] + name = line.split(" ")[0] return shortCuts, name + def getSonsAndUpperNeededFromVals(sonsValsSplit): - upperNeed="1" - sons="" - lastVal="" + upperNeed = "1" + sons = "" + lastVal = "" if "..." in sonsValsSplit: threePointsIndex = sonsValsSplit.index("...") - if threePointsIndex < len(sonsValsSplit)-1: - numBefore = int(sonsValsSplit[threePointsIndex-1]) + 1 - numAfter = int(sonsValsSplit[threePointsIndex+1]) - arr=range(numBefore,numAfter) - sonsValsSplit[threePointsIndex] = " ".join(map(lambda x : str(x), arr)) + if threePointsIndex < len(sonsValsSplit) - 1: + numBefore = int(sonsValsSplit[threePointsIndex - 1]) + 1 + numAfter = int(sonsValsSplit[threePointsIndex + 1]) + arr = range(numBefore, numAfter) + sonsValsSplit[threePointsIndex] = " ".join(map(lambda x: str(x), arr)) for val in sonsValsSplit: sonVal = val.split('(')[0] - sons=sons+ " " + sonVal + sons = sons + " " + sonVal if not sonVal.isupper(): - upperNeed="" + upperNeed = "" return sons, upperNeed + def getSonsValsFromLine(line): - ret="" + ret = "" lineSplit = line.split("[")[1:] for sons in lineSplit: - ret=ret + sons.split("]")[0] + ret = ret + sons.split("]")[0] return ret + def getNodeTypeSonsUpperNeedAndLastCommandIndex(line): - lastCommandIndex="-1" - sons="" - nodeType="0" - upperNeed="" + lastCommandIndex = "-1" + sons = "" + nodeType = "0" + upperNeed = "" if "[" in line: - lastCommandIndex="1" - sonsVals=getSonsValsFromLine(line) - sonsValsSplit=[] + lastCommandIndex = "1" + sonsVals = getSonsValsFromLine(line) + sonsValsSplit = [] if "/" in sonsVals: - nodeType="3" - sonsValsSplit=sonsVals.split("/") + nodeType = "3" + sonsValsSplit = sonsVals.split("/") elif "," in sonsVals: - nodeType="4" - sonsValsSplit=sonsVals.split(",") + nodeType = "4" + sonsValsSplit = sonsVals.split(",") else: - nodeType="3" - sonsValsSplit=[sonsVals] + nodeType = "3" + sonsValsSplit = [sonsVals] sons, upperNeed = getSonsAndUpperNeededFromVals(sonsValsSplit) return nodeType, sons, upperNeed, lastCommandIndex + def parseLine(line): - node={ 'shortCut': "" , 'name' : "" , 'lastCommandIndex' : "" , 'nodeType' : "" , 'sons' : "" , 'extra' : "" , 'upperNeed' : "" , 'description' : "" } + node = {'shortCut': "", 'name': "", 'lastCommandIndex': "", 'nodeType': "", 'sons': "", 'extra': "", 'upperNeed': "", 'description': ""} lineSplitByColoumn = line.split(":") shortCut, name = getNodeShortCutsAndName(lineSplitByColoumn[0]) - node["shortCut"]=" ".join(shortCut.split()) - node["name"] =" ".join(name.split()) - node["description"]=lineSplitByColoumn[1] - nodeType,sons,upperNeed,lastCommandIndex = getNodeTypeSonsUpperNeedAndLastCommandIndex(line) - node["nodeType"]=nodeType - node["sons"]=sons - node["upperNeed"]=upperNeed - node["lastCommandIndex"]=lastCommandIndex + node["shortCut"] = " ".join(shortCut.split()) + node["name"] = " ".join(name.split()) + node["description"] = lineSplitByColoumn[1] + nodeType, sons, upperNeed, lastCommandIndex = getNodeTypeSonsUpperNeedAndLastCommandIndex(line) + node["nodeType"] = nodeType + node["sons"] = sons + node["upperNeed"] = upperNeed + node["lastCommandIndex"] = lastCommandIndex return node + def getNumOfLeadingZeroFromLine(line): - count=0 + count = 0 for char in line: if char == " ": - count+=1 + count += 1 elif char == "\t": - count+=4 + count += 4 else: return count return count + def getTabLevelFromLine(line): numOfLeadingZeros = getNumOfLeadingZeroFromLine(line) return int(numOfLeadingZeros / 4) + def getUserInput(): my_parser = argparse.ArgumentParser() - my_parser.add_argument('-n','--name', action='store', type=str , help="Tool Name", required=True) - my_parser.add_argument('-o','--output', action='store', type=int, default=1, choices=[1], help="Output: 1- build structs for Auto-Compeletion(Default)") - my_parser.add_argument('-c','--command', action='store', type=str, default="", help="Full Command Line: ") + my_parser.add_argument('-n', '--name', action='store', type=str, help="Tool Name", required=True) + my_parser.add_argument('-o', '--output', action='store', type=int, default=1, choices=[1], help="Output: 1- build structs for Auto-Compeletion(Default)") + my_parser.add_argument('-c', '--command', action='store', type=str, default="", help="Full Command Line: ") args = my_parser.parse_args() return vars(args) + def isCommandNode(node): return node["name"][0] != "-" + def isNeedUpdateNode(prevNode, prevIndex, currNode, CurrIndex): - if prevNode == None: + if prevNode is None: return True if isCommandNode(prevNode): if isCommandNode(currNode): @@ -223,71 +237,73 @@ def isNeedUpdateNode(prevNode, prevIndex, currNode, CurrIndex): else: return CurrIndex > prevIndex + def buildMSTNodesTree(commandLine): - nodesTree=[] + nodesTree = [] filesList = subprocess.check_output("sudo mst help", shell=True).decode().split("\n") - options="" - params="" - sons="" - extra="" - lastNodeStruct={ 'shortCut': "" , 'name' : "" , 'lastCommandIndex' : "1" , 'nodeType' : "0" , 'sons' : "" , 'extra' : "" , 'upperNeed' : "" , 'description' : ""} - mstMainNodeSons="" + options = "" + params = "" + sons = "" + extra = "" + lastNodeStruct = {'shortCut': "", 'name': "", 'lastCommandIndex': "1", 'nodeType': "0", 'sons': "", 'extra': "", 'upperNeed': "", 'description': ""} + mstMainNodeSons = "" for line in reversed(filesList): lineRemovingLeadingZero = line.strip(" ") if len(lineRemovingLeadingZero) == 0: continue if lineRemovingLeadingZero[0:3] == "mst": splitLine = lineRemovingLeadingZero[4:].split(" ") - nodeName=splitLine.pop(0) + nodeName = splitLine.pop(0) if nodeName not in mstMainNodeSons.split(" "): - mstMainNodeSons = mstMainNodeSons + " " + nodeName + mstMainNodeSons = mstMainNodeSons + " " + nodeName if nodeName not in commandLine.split(" "): continue if lastNodeStruct["name"] != nodeName: if lastNodeStruct["name"] != "" and lastNodeStruct["sons"].strip(" ") != "": nodesTree.append(lastNodeStruct) - lastNodeStruct={ 'shortCut': "" , 'name' : nodeName , 'lastCommandIndex' : "1" , 'nodeType' : "0" , 'sons' : "" , 'extra' : "" , 'upperNeed' : "" , 'description' : ""} + lastNodeStruct = {'shortCut': "", 'name': nodeName, 'lastCommandIndex': "1", 'nodeType': "0", 'sons': "", 'extra': "", 'upperNeed': "", 'description': ""} for son in reversed(splitLine): if son[0] == "<": continue if son[0] == "[": - sonName=son.replace("[", "").replace("]","") + sonName = son.replace("[", "").replace("]", "") if sonName == "OPTIONS": - extra=extra+options+sons - sons="" + extra = extra + options + sons + sons = "" elif sonName == "params": - extra=params + extra = params else: - sons=sons+" "+sonName + sons = sons + " " + sonName else: if sons == "": if extra != "": - sons=extra - extra="" + sons = extra + extra = "" if sons != "": - nodesTree.append({ 'shortCut': "" , 'name' : son , 'lastCommandIndex' : "1" , 'nodeType' : "0" , 'sons' : sons , 'extra' : extra , 'upperNeed' : "" , 'description' : ""}) - sons=son - params="" - options="" - lastNodeStruct["sons"]= lastNodeStruct["sons"] + " " + sons - sons="" - params="" - options="" + nodesTree.append({'shortCut': "", 'name': son, 'lastCommandIndex': "1", 'nodeType': "0", 'sons': sons, 'extra': extra, 'upperNeed': "", 'description': ""}) + sons = son + params = "" + options = "" + lastNodeStruct["sons"] = lastNodeStruct["sons"] + " " + sons + sons = "" + params = "" + options = "" elif "params:" in line: paramsSplit = lineRemovingLeadingZero.split(" ") for param in paramsSplit: if param[0] == "[": - paramMame = param.replace("[", "").replace("]","") - params=params + " " + paramMame + paramMame = param.replace("[", "").replace("]", "") + params = params + " " + paramMame elif lineRemovingLeadingZero[0] == "-": - options=options + " " + lineRemovingLeadingZero.split(" ")[0].replace(":", "") + options = options + " " + lineRemovingLeadingZero.split(" ")[0].replace(":", "") nodesTree.append(lastNodeStruct) - nodesTree.append({ 'shortCut': "" , 'name' : "mst" , 'lastCommandIndex' : "1" , 'nodeType' : "0" , 'sons' : mstMainNodeSons , 'extra' : "" , 'upperNeed' : "" , 'description' : ""}) + nodesTree.append({'shortCut': "", 'name': "mst", 'lastCommandIndex': "1", 'nodeType': "0", 'sons': mstMainNodeSons, 'extra': "", 'upperNeed': "", 'description': ""}) return nodesTree -def buildMFTTollNodesTree(toolName,commandLine): - nodesTree=[] - nodesTabs=["","","","","","","","","","","","","","","","","","",""] + +def buildMFTTollNodesTree(toolName, commandLine): + nodesTree = [] + nodesTabs = ["", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""] try: filesList = subprocess.check_output(toolName + " -h", shell=True).decode().split("\n") # some tools supply --help only when executed by root. at this point auto-complete can not support them @@ -295,81 +311,83 @@ def buildMFTTollNodesTree(toolName,commandLine): sys.exit(0) helpLineOnlyNodes = keepOnlyNodes(filesList) - tabLevel=0 + tabLevel = 0 tabLevelBestIndex = [0] * 8 - tabLevelBestNode = [None] * 8 + tabLevelBestNode = [None] * 8 for line in reversed(helpLineOnlyNodes): parsedLine = parseLine(line) tabLevel = getTabLevelFromLine(line) nodesTabs[tabLevel] = nodesTabs[tabLevel] + " " + parsedLine["name"] - sons = nodesTabs[tabLevel+1] - nodesTabs[tabLevel+1]="" + sons = nodesTabs[tabLevel + 1] + nodesTabs[tabLevel + 1] = "" if parsedLine["sons"] == "": - parsedLine["sons"]=sons + parsedLine["sons"] = sons else: - parsedLine["extra"]=sons + parsedLine["extra"] = sons flagIndex = -1 splitCommand = commandLine.split(" ") if parsedLine["name"] in splitCommand: flagIndex = splitCommand.index(parsedLine["name"]) elif parsedLine["shortCut"] in splitCommand and parsedLine["shortCut"] != "": - flagIndex = splitCommand.index(parsedLine["shortCut"]) + flagIndex = splitCommand.index(parsedLine["shortCut"]) if flagIndex > -1: if isNeedUpdateNode(tabLevelBestNode[tabLevel], tabLevelBestIndex[tabLevel], parsedLine, flagIndex): tabLevelBestNode[tabLevel] = parsedLine - tabLevelBestIndex[tabLevel]= flagIndex - for i in range(tabLevel+1, 8): + tabLevelBestIndex[tabLevel] = flagIndex + for i in range(tabLevel + 1, 8): if tabLevelBestIndex[i] < flagIndex: tabLevelBestNode[i] = None for bestTab in tabLevelBestNode: - if bestTab != None: + if bestTab is not None: nodesTree.append(bestTab) - nodesTree.append({ 'shortCut': "" , 'name' : toolName , 'lastCommandIndex' : "-1" , 'nodeType' : "0" , 'sons' : " ".join(nodesTabs) , 'extra' : "" , 'upperNeed' : "" , 'description' : ""}) + nodesTree.append({'shortCut': "", 'name': toolName, 'lastCommandIndex': "-1", 'nodeType': "0", 'sons': " ".join(nodesTabs), 'extra': "", 'upperNeed': "", 'description': ""}) return nodesTree -def buildNodesTree(toolName,commandLine): + +def buildNodesTree(toolName, commandLine): if toolName == "mst": return buildMSTNodesTree(commandLine) else: - return buildMFTTollNodesTree(toolName,commandLine) + return buildMFTTollNodesTree(toolName, commandLine) def buildShortCutsNodeListNodesDeclary(nodesTree): - shortCuts="" - nodesList="" + shortCuts = "" + nodesList = "" nodesDeclareArray = [] for node in nodesTree: - shortCutVal = node["shortCut"] - nodeNAme = node["name"] - nodeSons = node["sons"] - extra = node["extra"] + shortCutVal = node["shortCut"] + nodeNAme = node["name"] + nodeSons = node["sons"] + extra = node["extra"] if nodeNAme == "--device" or nodeNAme == "-d" or nodeNAme == "-dev" or shortCutVal == "-d": - nodeSons="temp" - node["lastCommandIndex"]="1" - node["nodeType"]="2" + nodeSons = "temp" + node["lastCommandIndex"] = "1" + node["nodeType"] = "2" if shortCutVal != "": - shortCuts=shortCuts + " [\"" + shortCutVal + "\"]=\"" + nodeNAme + "\"" + shortCuts = shortCuts + " [\"" + shortCutVal + "\"]=\"" + nodeNAme + "\"" if nodeSons != "" or extra != "": - nodesList=nodesList + " " + nodeNAme - nodeDeclare="declare -A "+ nodeNAme.replace("-", "")+"=( [\"lastCommandIndex\"]="+node["lastCommandIndex"]+" [\"nodeType\"]=\""+node["nodeType"]+"\" [\"sons\"]=\""+nodeSons+"\" [\"extra\"]=\""+node["extra"]+"\" [\"upperNeed\"]="+node["upperNeed"]+" )\n" + nodesList = nodesList + " " + nodeNAme + nodeDeclare = "declare -A " + nodeNAme.replace("-", "") + "=( [\"lastCommandIndex\"]=" + node["lastCommandIndex"] + " [\"nodeType\"]=\"" + node["nodeType"] + "\" [\"sons\"]=\"" + nodeSons + "\" [\"extra\"]=\"" + node["extra"] + "\" [\"upperNeed\"]=" + node["upperNeed"] + " )\n" nodesDeclareArray.append(nodeDeclare) - return shortCuts,nodesList,nodesDeclareArray + return shortCuts, nodesList, nodesDeclareArray + def printNodesStructures(nodesTree): - shortCuts,nodesList,nodesDeclareArray = buildShortCutsNodeListNodesDeclary(nodesTree) + shortCuts, nodesList, nodesDeclareArray = buildShortCutsNodeListNodesDeclary(nodesTree) - print ("declare -A shortcuts=( " + shortCuts + " )\n") - print ("nodes=\""+nodesList+"\"\n") + print("declare -A shortcuts=( " + shortCuts + " )\n") + print("nodes=\"" + nodesList + "\"\n") for declareLine in nodesDeclareArray: - print (declareLine) + print(declareLine) if __name__ == "__main__": userInput = getUserInput() - toolName=userInput["name"] - commandLine=userInput["command"] + toolName = userInput["name"] + commandLine = userInput["command"] - nodesTree = buildNodesTree(toolName,commandLine) + nodesTree = buildNodesTree(toolName, commandLine) printNodesStructures(nodesTree) diff --git a/common/bit_slice.h b/common/bit_slice.h index 7707971a..9f176433 100644 --- a/common/bit_slice.h +++ b/common/bit_slice.h @@ -34,30 +34,36 @@ #define BIT_SLICE_H // BIT Slicing macros -#define ONES32(size) ((size) ? (0xffffffff >> (32 - (size))) : 0) -#define MASK32(offset, size) (ONES32(size) << (offset)) +#define ONES32(size) ((size) ? (0xffffffff >> (32 - (size))) : 0) +#define MASK32(offset, size) (ONES32(size) << (offset)) -#define EXTRACT_C(source, offset, size) ((((unsigned)(source)) >> (offset)) & ONES32(size)) -#define EXTRACT(src, start, len) (((len) == 32) ? (src) : EXTRACT_C(src, start, len)) -#define EXT(src, end, start) EXTRACT(src, start, end - start + 1) +#define EXTRACT_C(source, offset, size) ((((unsigned)(source)) >> (offset)) & ONES32(size)) +#define EXTRACT(src, start, len) (((len) == 32) ? (src) : EXTRACT_C(src, start, len)) +#define EXT(src, end, start) EXTRACT(src, start, end - start + 1) -#define MERGE_C(rsrc1, rsrc2, start, len) ((((rsrc2) << (start)) & (MASK32((start), (len)))) | ((rsrc1) & (~MASK32((start), (len))))) -#define MERGE(rsrc1, rsrc2, start, len) (((len) == 32) ? (rsrc2) : MERGE_C(rsrc1, rsrc2, start, len)) +#define MERGE_C(rsrc1, rsrc2, start, len) \ + ((((rsrc2) << (start)) & (MASK32((start), (len)))) | ((rsrc1) & (~MASK32((start), (len))))) +#define MERGE(rsrc1, rsrc2, start, len) (((len) == 32) ? (rsrc2) : MERGE_C(rsrc1, rsrc2, start, len)) #define INSERTF(src1, start1, src2, start2, len) MERGE((src1), EXTRACT((src2), (start2), (len)), (start1), (len)) -#define ONES64(size) ((size) ? (0xffffffffffffffffULL >> (64 - (size))) : 0) -#define MASK64(offset, size) (ONES64(size) << (offset)) +#define ONES64(size) ((size) ? (0xffffffffffffffffULL >> (64 - (size))) : 0) +#define MASK64(offset, size) (ONES64(size) << (offset)) -#define EXTRACT_C64(source, offset, size) ((((unsigned long long)(source)) >> (offset)) & ONES64(size)) -#define EXTRACT64(src, start, len) (((len) == 64) ? (src) : EXTRACT_C64(src, start, len)) +#define EXTRACT_C64(source, offset, size) ((((unsigned long long)(source)) >> (offset)) & ONES64(size)) +#define EXTRACT64(src, start, len) (((len) == 64) ? (src) : EXTRACT_C64(src, start, len)) -#define MERGE_C64(rsrc1, rsrc2, start, len) ((((u_int64_t)(rsrc2) << (start)) & (MASK64((start), (len)))) | ((rsrc1) & (~MASK64((start), (len))))) -#define MERGE64(rsrc1, rsrc2, start, len) (((len) == 64) ? (rsrc2) : MERGE_C64(rsrc1, rsrc2, start, len)) +#define MERGE_C64(rsrc1, rsrc2, start, len) \ + ((((u_int64_t)(rsrc2) << (start)) & (MASK64((start), (len)))) | ((rsrc1) & (~MASK64((start), (len))))) +#define MERGE64(rsrc1, rsrc2, start, len) (((len) == 64) ? (rsrc2) : MERGE_C64(rsrc1, rsrc2, start, len)) #define INSERTF64(src1, start1, src2, start2, len) MERGE64((src1), EXTRACT64((src2), (start2), (len)), (start1), (len)) -#define EXT64(src, end, start) EXTRACT64(src, start, end - start + 1) +#define EXT64(src, end, start) EXTRACT64(src, start, end - start + 1) #ifndef __cplusplus -enum cpp_bool {false = 0, true}; +enum cpp_bool +{ + false = 0, + true +}; typedef unsigned char bool; #endif diff --git a/common/compatibility.h b/common/compatibility.h index 2eda7c81..e5991c28 100644 --- a/common/compatibility.h +++ b/common/compatibility.h @@ -42,182 +42,177 @@ #include #if defined(__ia64__) || defined(__x86_64__) || defined(__PPC64__) || defined(__arm__) - #define U64L "l" +#define U64L "l" #else - #define U64L "ll" +#define U64L "ll" #endif - /* define macros to the architecture of the CPU */ #if defined(__linux__) || defined(__FreeBSD__) -# if defined(__i386__) -# define ARCH_x86 -# elif defined(__x86_64__) -# define ARCH_x86_64 -# elif defined(__ia64__) -# define ARCH_ia64 -# elif defined(__m68k__) -# define ARCH_m68k -# elif defined(__hppa__) -# define ARCH_hppa -# elif defined(__PPC64__) || defined(__s390x__) -# define ARCH_ppc64 -# elif defined(__PPC__) -# define ARCH_ppc -# elif defined(__aarch64__) -# define ARCH_arm64 -# elif defined(__arm__) -# define ARCH_arm6l -# elif defined(__riscv) -# define ARCH_riscv -# else -# error Unknown CPU architecture using the linux OS -# endif -#elif defined(__MINGW32__) || defined(__MINGW64__) /* Windows MINGW */ -# if defined(__MINGW32__) -# define ARCH_x86 -# elif defined(__MINGW64__) -# define ARCH_x86_64 -# else -# error Unknown CPU architecture using the windows-mingw OS -# endif -#elif defined(_WIN32) || defined(_WIN64) /* Windows */ -# if defined(_WIN32) -# define ARCH_x86 -# elif defined(_WIN64) -# define ARCH_x86_64 -# else -# error Unknown CPU architecture using the windows OS -# endif -#else /* Unknown */ -# error Unknown OS +#if defined(__i386__) +#define ARCH_x86 +#elif defined(__x86_64__) +#define ARCH_x86_64 +#elif defined(__ia64__) +#define ARCH_ia64 +#elif defined(__m68k__) +#define ARCH_m68k +#elif defined(__hppa__) +#define ARCH_hppa +#elif defined(__PPC64__) || defined(__s390x__) +#define ARCH_ppc64 +#elif defined(__PPC__) +#define ARCH_ppc +#elif defined(__aarch64__) +#define ARCH_arm64 +#elif defined(__arm__) +#define ARCH_arm6l +#elif defined(__riscv) +#define ARCH_riscv +#else +#error Unknown CPU architecture using the linux OS +#endif +#elif defined(__MINGW32__) || defined(__MINGW64__) /* Windows MINGW */ +#if defined(__MINGW32__) +#define ARCH_x86 +#elif defined(__MINGW64__) +#define ARCH_x86_64 +#else +#error Unknown CPU architecture using the windows-mingw OS +#endif +#elif defined(_WIN32) || defined(_WIN64) /* Windows */ +#if defined(_WIN32) +#define ARCH_x86 +#elif defined(_WIN64) +#define ARCH_x86_64 +#else +#error Unknown CPU architecture using the windows OS +#endif +#else /* Unknown */ +#error Unknown OS #endif /* define macros for print fields */ -#define U32D_FMT "%u" -#define U32H_FMT "0x%08x" -#define UH_FMT "0x%x" -#define STR_FMT "%s" -#define U16H_FMT "0x%04x" -#define U8H_FMT "0x%02x" - -#if defined(ARCH_x86) || defined(ARCH_ppc) || defined(UEFI_BUILD) || defined(ARCH_arm6l) || defined(ARCH_m68k) || defined(ARCH_hppa) -# if defined(__MINGW32__) || defined(__MINGW64__) -# include -# define U64D_FMT "0x%" PRId64 -# define U64H_FMT "0x%" PRIx64 -# define U64H_FMT_GEN "" PRIx64 -# define U48H_FMT "0x%" PRIx64 -# define U64D_FMT_GEN "" PRId64 -# else -# define U64D_FMT "%llu" -# define U64H_FMT "0x%016llx" -# define U64H_FMT_GEN "llx" -# define U48H_FMT "0x%012llx" -# define U64D_FMT_GEN "llu" -# endif +#define U32D_FMT "%u" +#define U32H_FMT "0x%08x" +#define UH_FMT "0x%x" +#define STR_FMT "%s" +#define U16H_FMT "0x%04x" +#define U8H_FMT "0x%02x" + +#if defined(ARCH_x86) || defined(ARCH_ppc) || defined(UEFI_BUILD) || defined(ARCH_arm6l) || defined(ARCH_m68k) || \ + defined(ARCH_hppa) +#if defined(__MINGW32__) || defined(__MINGW64__) +#include +#define U64D_FMT "0x%" PRId64 +#define U64H_FMT "0x%" PRIx64 +#define U64H_FMT_GEN "" PRIx64 +#define U48H_FMT "0x%" PRIx64 +#define U64D_FMT_GEN "" PRId64 +#else +#define U64D_FMT "%llu" +#define U64H_FMT "0x%016llx" +#define U64H_FMT_GEN "llx" +#define U48H_FMT "0x%012llx" +#define U64D_FMT_GEN "llu" +#endif #elif defined(ARCH_ia64) || defined(ARCH_x86_64) || defined(ARCH_ppc64) || defined(ARCH_arm64) || defined(ARCH_riscv) -# define U64D_FMT "%lu" -# define U64H_FMT "0x%016lx" -# define U48H_FMT "0x%012lx" -# define U64H_FMT_GEN "lx" -# define U64D_FMT_GEN "lu" +#define U64D_FMT "%lu" +#define U64H_FMT "0x%016lx" +#define U48H_FMT "0x%012lx" +#define U64H_FMT_GEN "lx" +#define U64D_FMT_GEN "lu" #else -# error Unknown architecture -#endif /* ARCH */ +#error Unknown architecture +#endif /* ARCH */ /* * Only for architectures which can't do swab by themselves */ #define ___my_swab16(x) \ - ((u_int16_t)( \ - (((u_int16_t)(x) & (u_int16_t)0x00ffU) << 8) | \ - (((u_int16_t)(x) & (u_int16_t)0xff00U) >> 8) )) -#define ___my_swab32(x) \ - ((u_int32_t)( \ - (((u_int32_t)(x) & (u_int32_t)0x000000ffUL) << 24) | \ - (((u_int32_t)(x) & (u_int32_t)0x0000ff00UL) << 8) | \ - (((u_int32_t)(x) & (u_int32_t)0x00ff0000UL) >> 8) | \ - (((u_int32_t)(x) & (u_int32_t)0xff000000UL) >> 24) )) -#define ___my_swab64(x) \ - ((u_int64_t)( \ - (u_int64_t)(((u_int64_t)(x) & (u_int64_t)0x00000000000000ffULL) << 56) | \ - (u_int64_t)(((u_int64_t)(x) & (u_int64_t)0x000000000000ff00ULL) << 40) | \ - (u_int64_t)(((u_int64_t)(x) & (u_int64_t)0x0000000000ff0000ULL) << 24) | \ - (u_int64_t)(((u_int64_t)(x) & (u_int64_t)0x00000000ff000000ULL) << 8) | \ - (u_int64_t)(((u_int64_t)(x) & (u_int64_t)0x000000ff00000000ULL) >> 8) | \ - (u_int64_t)(((u_int64_t)(x) & (u_int64_t)0x0000ff0000000000ULL) >> 24) | \ - (u_int64_t)(((u_int64_t)(x) & (u_int64_t)0x00ff000000000000ULL) >> 40) | \ - (u_int64_t)(((u_int64_t)(x) & (u_int64_t)0xff00000000000000ULL) >> 56) )) + ((u_int16_t)((((u_int16_t)(x) & (u_int16_t)0x00ffU) << 8) | (((u_int16_t)(x) & (u_int16_t)0xff00U) >> 8))) +#define ___my_swab32(x) \ + ((u_int32_t)( \ + (((u_int32_t)(x) & (u_int32_t)0x000000ffUL) << 24) | (((u_int32_t)(x) & (u_int32_t)0x0000ff00UL) << 8) | \ + (((u_int32_t)(x) & (u_int32_t)0x00ff0000UL) >> 8) | (((u_int32_t)(x) & (u_int32_t)0xff000000UL) >> 24))) +#define ___my_swab64(x) \ + ((u_int64_t)((u_int64_t)(((u_int64_t)(x) & (u_int64_t)0x00000000000000ffULL) << 56) | \ + (u_int64_t)(((u_int64_t)(x) & (u_int64_t)0x000000000000ff00ULL) << 40) | \ + (u_int64_t)(((u_int64_t)(x) & (u_int64_t)0x0000000000ff0000ULL) << 24) | \ + (u_int64_t)(((u_int64_t)(x) & (u_int64_t)0x00000000ff000000ULL) << 8) | \ + (u_int64_t)(((u_int64_t)(x) & (u_int64_t)0x000000ff00000000ULL) >> 8) | \ + (u_int64_t)(((u_int64_t)(x) & (u_int64_t)0x0000ff0000000000ULL) >> 24) | \ + (u_int64_t)(((u_int64_t)(x) & (u_int64_t)0x00ff000000000000ULL) >> 40) | \ + (u_int64_t)(((u_int64_t)(x) & (u_int64_t)0xff00000000000000ULL) >> 56))) /* * Linux */ #if defined(__linux__) || defined(__FreeBSD__) // #include - #include - #include +#include +#include - #if defined(__FreeBSD__) - #include +#if defined(__FreeBSD__) +#include // WA: on FBSD the BYTE ORDER AND ENDIANESS names are different - #ifndef __BYTE_ORDER - #define __BYTE_ORDER _BYTE_ORDER - #endif - #ifndef __LITTLE_ENDIAN - #define __LITTLE_ENDIAN _LITTLE_ENDIAN - #endif - #ifndef __BIG_ENDIAN - #define __BIG_ENDIAN _BIG_ENDIAN - #endif - #else - #include - #endif - - #undef __be64_to_cpu - #undef __be32_to_cpu - #undef __be16_to_cpu - #undef __cpu_to_be64 - #undef __cpu_to_be32 - #undef __cpu_to_be16 - #undef __le64_to_cpu - #undef __le32_to_cpu - #undef __le16_to_cpu - #undef __cpu_to_le64 - #undef __cpu_to_le32 - #undef __cpu_to_le16 - - #if __BYTE_ORDER == __LITTLE_ENDIAN - - #define __be64_to_cpu(x) ___my_swab64(x) - #define __be32_to_cpu(x) ___my_swab32(x) - #define __be16_to_cpu(x) ___my_swab16(x) - #define __cpu_to_be64(x) ___my_swab64(x) - #define __cpu_to_be32(x) ___my_swab32(x) - #define __cpu_to_be16(x) ___my_swab16(x) - #define __le64_to_cpu(x) (x) - #define __le32_to_cpu(x) (x) - #define __le16_to_cpu(x) (x) - #define __cpu_to_le64(x) (x) - #define __cpu_to_le32(x) (x) - #define __cpu_to_le16(x) (x) - - #elif __BYTE_ORDER == __BIG_ENDIAN - - #define __be64_to_cpu(x) (x) - #define __be32_to_cpu(x) (x) - #define __be16_to_cpu(x) (x) - #define __cpu_to_be64(x) (x) - #define __cpu_to_be32(x) (x) - #define __cpu_to_be16(x) (x) - #define __le64_to_cpu(x) ___my_swab64(x) - #define __le32_to_cpu(x) ___my_swab32(x) - #define __le16_to_cpu(x) ___my_swab16(x) - #define __cpu_to_le64(x) ___my_swab64(x) - #define __cpu_to_le32(x) ___my_swab32(x) - #define __cpu_to_le16(x) ___my_swab16(x) - - #endif // __BYTE_ORDER +#ifndef __BYTE_ORDER +#define __BYTE_ORDER _BYTE_ORDER +#endif +#ifndef __LITTLE_ENDIAN +#define __LITTLE_ENDIAN _LITTLE_ENDIAN +#endif +#ifndef __BIG_ENDIAN +#define __BIG_ENDIAN _BIG_ENDIAN +#endif +#else +#include +#endif + +#undef __be64_to_cpu +#undef __be32_to_cpu +#undef __be16_to_cpu +#undef __cpu_to_be64 +#undef __cpu_to_be32 +#undef __cpu_to_be16 +#undef __le64_to_cpu +#undef __le32_to_cpu +#undef __le16_to_cpu +#undef __cpu_to_le64 +#undef __cpu_to_le32 +#undef __cpu_to_le16 + +#if __BYTE_ORDER == __LITTLE_ENDIAN + +#define __be64_to_cpu(x) ___my_swab64(x) +#define __be32_to_cpu(x) ___my_swab32(x) +#define __be16_to_cpu(x) ___my_swab16(x) +#define __cpu_to_be64(x) ___my_swab64(x) +#define __cpu_to_be32(x) ___my_swab32(x) +#define __cpu_to_be16(x) ___my_swab16(x) +#define __le64_to_cpu(x) (x) +#define __le32_to_cpu(x) (x) +#define __le16_to_cpu(x) (x) +#define __cpu_to_le64(x) (x) +#define __cpu_to_le32(x) (x) +#define __cpu_to_le16(x) (x) + +#elif __BYTE_ORDER == __BIG_ENDIAN + +#define __be64_to_cpu(x) (x) +#define __be32_to_cpu(x) (x) +#define __be16_to_cpu(x) (x) +#define __cpu_to_be64(x) (x) +#define __cpu_to_be32(x) (x) +#define __cpu_to_be16(x) (x) +#define __le64_to_cpu(x) ___my_swab64(x) +#define __le32_to_cpu(x) ___my_swab32(x) +#define __le16_to_cpu(x) ___my_swab16(x) +#define __cpu_to_le64(x) ___my_swab64(x) +#define __cpu_to_le32(x) ___my_swab32(x) +#define __cpu_to_le16(x) ___my_swab16(x) + +#endif // __BYTE_ORDER #endif @@ -225,21 +220,21 @@ * Windows (CYGWIN) */ #if defined(__CYGWIN32__) - #include - #include - - #define __be64_to_cpu(x) ___my_swab64(x) - #define __be32_to_cpu(x) ___my_swab32(x) - #define __be16_to_cpu(x) ___my_swab16(x) - #define __cpu_to_be64(x) ___my_swab64(x) - #define __cpu_to_be32(x) ___my_swab32(x) - #define __cpu_to_be16(x) ___my_swab16(x) - #define __le64_to_cpu(x) (x) - #define __le32_to_cpu(x) (x) - #define __le16_to_cpu(x) (x) - #define __cpu_to_le64(x) (x) - #define __cpu_to_le32(x) (x) - #define __cpu_to_le16(x) (x) +#include +#include + +#define __be64_to_cpu(x) ___my_swab64(x) +#define __be32_to_cpu(x) ___my_swab32(x) +#define __be16_to_cpu(x) ___my_swab16(x) +#define __cpu_to_be64(x) ___my_swab64(x) +#define __cpu_to_be32(x) ___my_swab32(x) +#define __cpu_to_be16(x) ___my_swab16(x) +#define __le64_to_cpu(x) (x) +#define __le32_to_cpu(x) (x) +#define __le16_to_cpu(x) (x) +#define __cpu_to_le64(x) (x) +#define __cpu_to_le32(x) (x) +#define __cpu_to_le16(x) (x) #endif @@ -247,47 +242,45 @@ * Windows (DDK) */ #if defined(__WIN__) - #include - #include - #include - - - #define __LITTLE_ENDIAN 1234 - #define __BIG_ENDIAN 4321 - #define __BYTE_ORDER __LITTLE_ENDIAN - - #define __be64_to_cpu(x) ___my_swab64(x) - #define __be32_to_cpu(x) ___my_swab32(x) - #define __be16_to_cpu(x) ___my_swab16(x) - #define __cpu_to_be64(x) ___my_swab64(x) - #define __cpu_to_be32(x) ___my_swab32(x) - #define __cpu_to_be16(x) ___my_swab16(x) - #define __le64_to_cpu(x) (x) - #define __le32_to_cpu(x) (x) - #define __le16_to_cpu(x) (x) - #define __cpu_to_le64(x) (x) - #define __cpu_to_le32(x) (x) - #define __cpu_to_le16(x) (x) - - - #if defined(_WIN32) || defined(_WIN64) || defined(__MINGW32__) || defined(__MINGW64__) - #include - #ifndef MFT_TOOLS_VARS - #define MFT_TOOLS_VARS +#include +#include +#include + +#define __LITTLE_ENDIAN 1234 +#define __BIG_ENDIAN 4321 +#define __BYTE_ORDER __LITTLE_ENDIAN + +#define __be64_to_cpu(x) ___my_swab64(x) +#define __be32_to_cpu(x) ___my_swab32(x) +#define __be16_to_cpu(x) ___my_swab16(x) +#define __cpu_to_be64(x) ___my_swab64(x) +#define __cpu_to_be32(x) ___my_swab32(x) +#define __cpu_to_be16(x) ___my_swab16(x) +#define __le64_to_cpu(x) (x) +#define __le32_to_cpu(x) (x) +#define __le16_to_cpu(x) (x) +#define __cpu_to_le64(x) (x) +#define __cpu_to_le32(x) (x) +#define __cpu_to_le16(x) (x) + +#if defined(_WIN32) || defined(_WIN64) || defined(__MINGW32__) || defined(__MINGW64__) +#include +#ifndef MFT_TOOLS_VARS +#define MFT_TOOLS_VARS typedef uint8_t u_int8_t; typedef uint16_t u_int16_t; typedef uint32_t u_int32_t; typedef uint64_t u_int64_t; - #endif - #include // Get a define for strcasecmp - #if defined(_MSC_VER) +#endif +#include // Get a define for strcasecmp +#if defined(_MSC_VER) typedef size_t ssize_t; - #define strcasecmp _stricmp - #define strncasecmp _strnicmp - #endif +#define strcasecmp _stricmp +#define strncasecmp _strnicmp +#endif - #else +#else typedef unsigned __int8 u_int8_t; typedef __int8 int8_t; typedef unsigned __int16 u_int16_t; @@ -297,32 +290,32 @@ typedef __int32 int32_t; typedef unsigned __int64 u_int64_t; typedef __int64 int64_t; - #define strcasecmp _stricmp - #define strtoll _strtoi64 - #define strtoull _strtoui64 - #define strdup _strdup +#define strcasecmp _stricmp +#define strtoll _strtoi64 +#define strtoull _strtoui64 +#define strdup _strdup - #endif +#endif - #ifndef __WIN__ // TBD : investigate crash on win +#ifndef __WIN__ // TBD : investigate crash on win inline - #endif +#endif - #define COMP_CDECL __cdecl - #define COMP_OPEN ::_open - #define COMP_CLOSE ::_close - #define COMP_READ ::_read - #define COMP_FSTAT ::_fstat +#define COMP_CDECL __cdecl +#define COMP_OPEN ::_open +#define COMP_CLOSE ::_close +#define COMP_READ ::_read +#define COMP_FSTAT ::_fstat - #ifndef __cplusplus - #define close _close - #endif +#ifndef __cplusplus +#define close _close +#endif -typedef struct _stat Stat; + typedef struct _stat Stat; #ifndef PRIx64 - #define PRIx64 "I64x" - #define PRIu64 "I64u" +#define PRIx64 "I64x" +#define PRIu64 "I64u" #endif /* #ifdef __cplusplus @@ -335,47 +328,45 @@ typedef struct _stat Stat; */ #else - #define COMP_CDECL - #define COMP_OPEN ::open - #define COMP_CLOSE ::close - #define COMP_READ ::read - #define COMP_FSTAT ::fstat +#define COMP_CDECL +#define COMP_OPEN ::open +#define COMP_CLOSE ::close +#define COMP_READ ::read +#define COMP_FSTAT ::fstat typedef struct stat Stat; - #include - #include +#include +#include #endif - - /* * MAC (Darwin) */ #if defined(__APPLE_CC__) - #include - - #define __swab64(x) NXSwapLongLong(x) - #define __swab32(x) NXSwapLong(x) - #define __swab16(x) NXSwapShort(x) - #define __be64_to_cpu(x) NXSwapBigLongLongToHost(x) - #define __be32_to_cpu(x) NXSwapBigLongToHost(x) - #define __be16_to_cpu(x) NXSwapBigShortToHost(x) - #define __le64_to_cpu(x) NXSwapLittleLongLongToHost(x) - #define __le32_to_cpu(x) NXSwapLittleLongToHost(x) - #define __le16_to_cpu(x) NXSwapLittleShortToHost(x) - #define __cpu_to_be64(x) NXSwapHostLongLongToBig(x) - #define __cpu_to_be32(x) NXSwapHostLongToBig(x) - #define __cpu_to_be16(x) NXSwapHostShortToBig(x) - #define __cpu_to_le64(x) NXSwapHostLongLongToLittle(x) - #define __cpu_to_le32(x) NXSwapHostLongToLittle(x) - #define __cpu_to_le16(x) NXSwapHostShortToLittle(x) - - #define __LITTLE_ENDIAN 1234 - #define __BIG_ENDIAN 4321 - #define __PDP_ENDIAN 3412 - #define __BYTE_ORDER __BIG_ENDIAN +#include + +#define __swab64(x) NXSwapLongLong(x) +#define __swab32(x) NXSwapLong(x) +#define __swab16(x) NXSwapShort(x) +#define __be64_to_cpu(x) NXSwapBigLongLongToHost(x) +#define __be32_to_cpu(x) NXSwapBigLongToHost(x) +#define __be16_to_cpu(x) NXSwapBigShortToHost(x) +#define __le64_to_cpu(x) NXSwapLittleLongLongToHost(x) +#define __le32_to_cpu(x) NXSwapLittleLongToHost(x) +#define __le16_to_cpu(x) NXSwapLittleShortToHost(x) +#define __cpu_to_be64(x) NXSwapHostLongLongToBig(x) +#define __cpu_to_be32(x) NXSwapHostLongToBig(x) +#define __cpu_to_be16(x) NXSwapHostShortToBig(x) +#define __cpu_to_le64(x) NXSwapHostLongLongToLittle(x) +#define __cpu_to_le32(x) NXSwapHostLongToLittle(x) +#define __cpu_to_le16(x) NXSwapHostShortToLittle(x) + +#define __LITTLE_ENDIAN 1234 +#define __BIG_ENDIAN 4321 +#define __PDP_ENDIAN 3412 +#define __BYTE_ORDER __BIG_ENDIAN #endif /* @@ -383,22 +374,22 @@ typedef struct stat Stat; * ------- */ #if defined(__sparc__) - #include - #include - #include - - #define __be64_to_cpu(x) (x) - #define __be32_to_cpu(x) (x) - #define __be16_to_cpu(x) (x) - #define __cpu_to_be64(x) (x) - #define __cpu_to_be32(x) (x) - #define __cpu_to_be16(x) (x) - #define __le64_to_cpu(x) ___my_swab64(x) - #define __le32_to_cpu(x) ___my_swab32(x) - #define __le16_to_cpu(x) ___my_swab16(x) - #define __cpu_to_le64(x) ___my_swab64(x) - #define __cpu_to_le32(x) ___my_swab32(x) - #define __cpu_to_le16(x) ___my_swab16(x) +#include +#include +#include + +#define __be64_to_cpu(x) (x) +#define __be32_to_cpu(x) (x) +#define __be16_to_cpu(x) (x) +#define __cpu_to_be64(x) (x) +#define __cpu_to_be32(x) (x) +#define __cpu_to_be16(x) (x) +#define __le64_to_cpu(x) ___my_swab64(x) +#define __le32_to_cpu(x) ___my_swab32(x) +#define __le16_to_cpu(x) ___my_swab16(x) +#define __cpu_to_le64(x) ___my_swab64(x) +#define __cpu_to_le32(x) ___my_swab32(x) +#define __cpu_to_le16(x) ___my_swab16(x) typedef uint64_t u_int64_t; typedef uint32_t u_int32_t; @@ -409,39 +400,45 @@ typedef uint8_t u_int8_t; /* define msleep(x) - sleeps for x milliseconds */ #if defined(_WIN32) || defined(_WIN64) || defined(__MINGW32__) || defined(__MINGW64__) - #define msleep(x) Sleep(x) +#define msleep(x) Sleep(x) #else - #define msleep(x) usleep(((unsigned long)x) * 1000) +#define msleep(x) usleep(((unsigned long)x) * 1000) #endif // Convert BYTES - DWORDS with MEMCPY BE -#define BYTES_TO_DWORD_BE(dw_dest, byte_src) do { u_int32_t tmp; \ - memcpy(&tmp, byte_src, 4); \ - *(dw_dest) = __be32_to_cpu(tmp); \ -} while (0) - -#define DWORD_TO_BYTES_BE(bytes_dest, dw_src) do { u_int32_t tmp; \ - tmp = __cpu_to_be32(*(dw_src)); \ - memcpy(bytes_dest, &tmp, 4); \ -} while (0) +#define BYTES_TO_DWORD_BE(dw_dest, byte_src) \ + do \ + { \ + u_int32_t tmp; \ + memcpy(&tmp, byte_src, 4); \ + *(dw_dest) = __be32_to_cpu(tmp); \ + } while (0) + +#define DWORD_TO_BYTES_BE(bytes_dest, dw_src) \ + do \ + { \ + u_int32_t tmp; \ + tmp = __cpu_to_be32(*(dw_src)); \ + memcpy(bytes_dest, &tmp, 4); \ + } while (0) /* * Old GCC * ------- */ #if !defined(__WIN__) && defined(__cplusplus) && __GNUG__ < 3 - #include +#include #endif #define __STDC_FORMAT_MACROS #if !defined(__WIN__) && !defined(UEFI_BUILD) - #include +#include #endif #if defined(__VMKERNEL_UW_NATIVE__) - #define ROOT_PATH "/opt/mellanox/" +#define ROOT_PATH "/opt/mellanox/" #else - #define ROOT_PATH "/" +#define ROOT_PATH "/" #endif #ifndef IN @@ -460,4 +457,3 @@ typedef uint8_t u_int8_t; #endif #endif - diff --git a/common/mft_logger.py b/common/mft_logger.py index 3b86727d..3961e3a3 100755 --- a/common/mft_logger.py +++ b/common/mft_logger.py @@ -28,7 +28,7 @@ # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -#-- +# -- import logging @@ -49,7 +49,6 @@ def get(self, name, level): else: log_level = self._levels[level] - logging.basicConfig(level=log_level, format='%(asctime)s - %(name)s - %(levelname)s - {%(pathname)s:%(lineno)d} - %(message)s') logger = logging.getLogger(name) return logger diff --git a/common/tools_utils.h b/common/tools_utils.h index e8ef84f1..8f4e48cf 100644 --- a/common/tools_utils.h +++ b/common/tools_utils.h @@ -35,34 +35,33 @@ #include "compatibility.h" -#define CPU_TO_BE32(x) __cpu_to_be32(x) -#define CPU_TO_LE32(x) __cpu_to_le32(x) -#define BE32_TO_CPU(x) __be32_to_cpu(x) -#define LE32_TO_CPU(x) __le32_to_cpu(x) -#define CPU_TO_BE16(x) __cpu_to_be16(x) -#define CPU_TO_LE16(x) __cpu_to_le16(x) -#define BE16_TO_CPU(x) __be16_to_cpu(x) -#define LE16_TO_CPU(x) __le16_to_cpu(x) -#define CPU_TO_BE64(x) __cpu_to_be64(x) -#define CPU_TO_LE64(x) __cpu_to_le64(x) -#define BE64_TO_CPU(x) __be64_to_cpu(x) -#define LE64_TO_CPU(x) __le64_to_cpu(x) +#define CPU_TO_BE32(x) __cpu_to_be32(x) +#define CPU_TO_LE32(x) __cpu_to_le32(x) +#define BE32_TO_CPU(x) __be32_to_cpu(x) +#define LE32_TO_CPU(x) __le32_to_cpu(x) +#define CPU_TO_BE16(x) __cpu_to_be16(x) +#define CPU_TO_LE16(x) __cpu_to_le16(x) +#define BE16_TO_CPU(x) __be16_to_cpu(x) +#define LE16_TO_CPU(x) __le16_to_cpu(x) +#define CPU_TO_BE64(x) __cpu_to_be64(x) +#define CPU_TO_LE64(x) __cpu_to_le64(x) +#define BE64_TO_CPU(x) __be64_to_cpu(x) +#define LE64_TO_CPU(x) __le64_to_cpu(x) #define FIELD_8_OF_BUFF(buf, offset) (*(u_int8_t*)((u_int8_t*)(buf) + (offset))) #define FIELD_16_OF_BUFF(buf, offset) (*(u_int16_t*)((u_int8_t*)(buf) + (offset))) #define FIELD_32_OF_BUFF(buf, offset) (*(u_int32_t*)((u_int8_t*)(buf) + (offset))) #define FIELD_64_OF_BUFF(buf, offset) (*(u_int64_t*)((u_int8_t*)(buf) + (offset))) -#define BYTE_N(buf, n) FIELD_8_OF_BUFF((buf), (n)) -#define WORD_N(buf, n) FIELD_16_OF_BUFF((buf), (n) * 2) -#define DWORD_N(buf, n) FIELD_32_OF_BUFF((buf), (n) * 4) -#define QWORD_N(buf, n) FIELD_64_OF_BUFF((buf), (n) * 8) +#define BYTE_N(buf, n) FIELD_8_OF_BUFF((buf), (n)) +#define WORD_N(buf, n) FIELD_16_OF_BUFF((buf), (n)*2) +#define DWORD_N(buf, n) FIELD_32_OF_BUFF((buf), (n)*4) +#define QWORD_N(buf, n) FIELD_64_OF_BUFF((buf), (n)*8) #define QWORD_EXTRACT_DWORD_HI(qword) ((u_int64_t)(qword) >> 32) #define QWORD_EXTRACT_DWORD_LO(qword) ((u_int64_t)(qword) & (u_int64_t)0xffffffff) #define QWORD_INSERT_DWORD_HI(qword, dword) qword = ((qword & (u_int64_t)0xffffffff) | ((u_int64_t)dword << 32)) #define QWORD_INSERT_DWORD_LO(qword, dword) qword = ((qword & (u_int64_t)0xffffffff00000000) | ((u_int64_t)dword)) #define U32_TO_U64(dword1, dword2) ((((u_int64_t)(dword1)) << 32) | (((u_int64_t)(dword2)) & 0xffffffff)) - #define TOOLS_MAX(a, b) ((a) > (b) ? (a) : (b)) #define TOOLS_MIN(a, b) ((a) < (b) ? (a) : (b)) @@ -73,6 +72,4 @@ */ #define TOOLS_UNUSED(var) ((void)var) - #endif // TOOLS_UTILS_H - diff --git a/common/tools_version.h b/common/tools_version.h index 8e37872b..c656076c 100644 --- a/common/tools_version.h +++ b/common/tools_version.h @@ -37,7 +37,6 @@ #ifndef TOOLS_VERSION_H #define TOOLS_VERSION_H - #include #include #include @@ -47,43 +46,40 @@ #include "gitversion.h" #endif #ifndef TOOLS_GIT_SHA - #define TOOLS_GIT_SHA "6469M" +#define TOOLS_GIT_SHA "6469M" #endif #ifdef HAVE_CONFIG_H - #include - #ifndef MSTFLINT_VERSION_STR - #define MSTFLINT_VERSION_STR PACKAGE_STRING - #endif +#include +#ifndef MSTFLINT_VERSION_STR +#define MSTFLINT_VERSION_STR PACKAGE_STRING +#endif #endif #ifndef MFT_VERSION_STR - #define MFT_VERSION_STR "mft V.V.V-R" +#define MFT_VERSION_STR "mft V.V.V-R" #endif -static inline -int get_version_string(char *buf, int buf_size, const char *exe_name, const char *tool_version) +static inline int get_version_string(char* buf, int buf_size, const char* exe_name, const char* tool_version) { int len = 0; // "svn ci" updates the below line - - if (tool_version == NULL || !strcmp(tool_version, "")) { + if (tool_version == NULL || !strcmp(tool_version, "")) + { len = snprintf(buf, buf_size, "%s, ", exe_name); - } else { + } + else + { len = snprintf(buf, buf_size, "%s %s, ", exe_name, tool_version); } // cut out first and last "$" from the SVN version string: - len += snprintf(buf + len, buf_size - len, "%s, built on %s, %s. Git SHA Hash: %s", - MSTFLINT_VERSION_STR, - __DATE__, - __TIME__, - TOOLS_GIT_SHA); + len += snprintf(buf + len, buf_size - len, "%s, built on %s, %s. Git SHA Hash: %s", MSTFLINT_VERSION_STR, __DATE__, + __TIME__, TOOLS_GIT_SHA); return len; } -static inline -void print_version_string(const char *exe_name, const char *tool_version) +static inline void print_version_string(const char* exe_name, const char* tool_version) { char buf[1024] = {0}; get_version_string(buf, sizeof(buf), exe_name, tool_version); diff --git a/dev_mgt/dev_mgt.py b/dev_mgt/dev_mgt.py index efe1ac66..712369af 100755 --- a/dev_mgt/dev_mgt.py +++ b/dev_mgt/dev_mgt.py @@ -28,7 +28,7 @@ # 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. -#-- +# -- from __future__ import print_function import os @@ -37,6 +37,7 @@ import ctypes import mtcr + class DevMgtException(Exception): pass @@ -48,13 +49,13 @@ class DevMgtException(Exception): if platform.system() == "Windows" or os.name == "nt": try: DEV_MGT = CDLL("c_dev_mgt.dll") - except: + except BaseException: DEV_MGT = CDLL(os.path.join(os.path.dirname(os.path.realpath(__file__)), "c_dev_mgt.dll")) else: try: - #c_dev_mgt.so must be specified explicitly for pyinstaller collection + # c_dev_mgt.so must be specified explicitly for pyinstaller collection DEV_MGT = CDLL("c_dev_mgt.so") - except: + except BaseException: DEV_MGT = CDLL(os.path.join(os.path.dirname(os.path.realpath(__file__)), "c_dev_mgt.so")) except Exception as exp: raise DevMgtException("Failed to load shared library c_dev_mgt: %s" % exp) @@ -64,18 +65,17 @@ class DevMgt: ########################## def __init__(self, dev): self.mf = 0 - self._isLivefishModeFunc = DEV_MGT.dm_is_livefish_mode # dm_is_livefish_mode(mfile* mf) - if isinstance(dev,(mtcr.MstDevice)): - self._mstdev = dev + self._isLivefishModeFunc = DEV_MGT.dm_is_livefish_mode # dm_is_livefish_mode(mfile* mf) + if isinstance(dev, (mtcr.MstDevice)): + self._mstdev = dev else: - self._mstdev = mtcr.MstDevice(dev) + self._mstdev = mtcr.MstDevice(dev) if not self._mstdev: raise DevMgtException("Failed to open device (%s): %s" % (dev, os.strerror(ctypes.get_errno()))) - ########################## def isLivefishMode(self): rc = self._isLivefishModeFunc(self._mstdev.mf) return not (rc == 0) else: - raise DevMgtException("Failed to load c_dev_mgt.so/libdev_mgt.dll") + raise DevMgtException("Failed to load c_dev_mgt.so/libdev_mgt.dll") diff --git a/dev_mgt/tools_dev_types.c b/dev_mgt/tools_dev_types.c index 43074c4d..8145ca4d 100644 --- a/dev_mgt/tools_dev_types.c +++ b/dev_mgt/tools_dev_types.c @@ -48,7 +48,8 @@ #include "tools_dev_types.h" #include "mflash/mflash_types.h" -enum dm_dev_type { +enum dm_dev_type +{ DM_UNKNOWN = -1, DM_HCA, DM_SWITCH, @@ -60,20 +61,21 @@ enum dm_dev_type { DM_GEARBOX }; -struct device_info { +struct device_info +{ dm_dev_id_t dm_id; u_int16_t hw_dev_id; - int hw_rev_id; /* -1 means all revisions match this record */ - int sw_dev_id; /* -1 means all hw ids match this record */ - const char *name; + int hw_rev_id; /* -1 means all revisions match this record */ + int sw_dev_id; /* -1 means all hw ids match this record */ + const char* name; int port_num; enum dm_dev_type dev_type; }; -#define DEVID_ADDR 0xf0014 -#define CABLEID_ADDR 0x0 -#define SFP_DIGITAL_DIAGNOSTIC_MONITORING_IMPLEMENTED_ADDR 92 -#define SFP_PAGING_IMPLEMENTED_INDICATOR_ADDR 64 +#define DEVID_ADDR 0xf0014 +#define CABLEID_ADDR 0x0 +#define SFP_DIGITAL_DIAGNOSTIC_MONITORING_IMPLEMENTED_ADDR 92 +#define SFP_PAGING_IMPLEMENTED_INDICATOR_ADDR 64 #define ARDBEG_REV0_DEVID 0x6e #define ARDBEG_REV1_DEVID 0x7e @@ -84,397 +86,397 @@ struct device_info { #define MENHIT_DEVID_VER1 0x72 #define MENHIT_DEVID_VER2 0x73 - #ifdef CABLES_SUPP enum dm_dev_type getCableType(u_int8_t id) { - switch (id) { - case 0xd: - case 0x11: - case 0xe: - case 0xc: - return DM_QSFP_CABLE; - - case 0x3: - return DM_SFP_CABLE; - case 0x18: - case 0x19: // Stallion2 - case 0x1e: - return DM_CMIS_CABLE; - default: - return DM_UNKNOWN; + switch (id) + { + case 0xd: + case 0x11: + case 0xe: + case 0xc: + return DM_QSFP_CABLE; + + case 0x3: + return DM_SFP_CABLE; + case 0x18: + case 0x19: // Stallion2 + case 0x1e: + return DM_CMIS_CABLE; + default: + return DM_UNKNOWN; } } #endif -static struct device_info g_devs_info[] = { - { - DeviceInfiniScaleIV, //dm_id - 0x01b3, //hw_dev_id - -1, //hw_rev_id - -1, //sw_dev_id - "InfiniScaleIV", //name - 36, //port_num - DM_SWITCH //dev_type - }, - { - DeviceSwitchX, //dm_id - 0x0245, //hw_dev_id - -1, //hw_rev_id - -1, //sw_dev_id - "SwitchX", //name - 64, //port_num - DM_SWITCH //dev_type - }, - { - DeviceConnectX2, //dm_id - 0x190, //hw_dev_id - 0xb0, //hw_rev_id - -1, //sw_dev_id - "ConnectX2", //name - 2, //port_num - DM_HCA //dev_type - }, - { - DeviceConnectX3, //dm_id - 0x1f5, //hw_dev_id - -1, //hw_rev_id - -1, //sw_dev_id - "ConnectX3", //name - 2, //port_num - DM_HCA //dev_type - }, - { - DeviceConnectIB, //dm_id - 0x1ff, //hw_dev_id - -1, //hw_rev_id - -1, //sw_dev_id - "ConnectIB", //name - 2, //port_num - DM_HCA //dev_type - }, - { - DeviceConnectX3Pro, //dm_id - 0x1f7, //hw_dev_id - -1, //hw_rev_id - -1, //sw_dev_id - "ConnectX3Pro", //name - 2, //port_num - DM_HCA //dev_type - }, - { - DeviceSwitchIB, //dm_id - 0x247, //hw_dev_id - -1, //hw_rev_id - -1, //sw_dev_id - "SwitchIB", //name - 36, //port_num - DM_SWITCH //dev_type - }, - { - DeviceSpectrum, //dm_id - 0x249, //hw_dev_id - -1, //hw_rev_id - -1, //sw_dev_id - "Spectrum", //name - 64, //port_num - DM_SWITCH //dev_type - }, - { - DeviceConnectX4, //dm_id - 0x209, //hw_dev_id - -1, //hw_rev_id - -1, //sw_dev_id - "ConnectX4", //name - 2, //port_num - DM_HCA //dev_type - }, - { - DeviceConnectX4LX, //dm_id - 0x20b, //hw_dev_id - -1, //hw_rev_id - -1, //sw_dev_id - "ConnectX4LX", //name - 2, //port_num - DM_HCA //dev_type - }, - { - DeviceConnectX5, //dm_id - 0x20d, //hw_dev_id - -1, //hw_rev_id - -1, //sw_dev_id - "ConnectX5", //name - 2, //port_num - DM_HCA //dev_type - }, - { - DeviceConnectX6, //dm_id - 0x20f, //hw_dev_id - -1, //hw_rev_id - -1, //sw_dev_id - "ConnectX6", //name - 2, //port_num - DM_HCA //dev_type - }, - { - DeviceConnectX6DX, //dm_id - 0x212, //hw_dev_id - -1, //hw_rev_id - -1, //sw_dev_id - "ConnectX6DX", //name - 2, //port_num - DM_HCA //dev_type - }, - { - DeviceConnectX6LX, //dm_id - 0x216, //hw_dev_id - -1, //hw_rev_id - -1, //sw_dev_id - "ConnectX6LX", //name - 2, //port_num - DM_HCA //dev_type - }, - { - DeviceConnectX7, //dm_id - 0x218, //hw_dev_id - -1, //hw_rev_id - -1, //sw_dev_id - "ConnectX7", //name - 4, //port_num - DM_HCA //dev_type - }, - { - DeviceBlueField, //dm_id - 0x211, //hw_dev_id - -1, //hw_rev_id - -1, //sw_dev_id - "BlueField", //name - 2, //port_num - DM_HCA //dev_type - }, - { - DeviceBlueField2, //dm_id - 0x214, //hw_dev_id - -1, //hw_rev_id - -1, //sw_dev_id - "BlueField2", //name - 2, //port_num - DM_HCA //dev_type - }, - { - DeviceBlueField3, //dm_id - 0x21c, //hw_dev_id - -1, //hw_rev_id - -1, //sw_dev_id - "BlueField3", //name - 4, //port_num - DM_HCA //dev_type - }, - { - DeviceSwitchIB2, //dm_id - 0x24b, //hw_dev_id - -1, //hw_rev_id - -1, //sw_dev_id - "SwitchIB2", //name - 36, //port_num - DM_SWITCH //dev_type - }, - { - DeviceCableQSFP, //dm_id - 0x0d, //hw_dev_id - 0, //hw_rev_id - -1, //sw_dev_id - "CableQSFP", //name - -1, //port_num - DM_QSFP_CABLE //dev_type - }, - { - DeviceCableQSFPaging, //dm_id - 0x11, //hw_dev_id - 0xab, //hw_rev_id - -1, //sw_dev_id - "CableQSFPaging", //name - -1, //port_num - DM_QSFP_CABLE //dev_type - }, - { - DeviceCableCMIS, //dm_id - 0x19, //hw_dev_id - 0, //hw_rev_id - -1, //sw_dev_id - "CableCMIS", //name - -1, //port_num - DM_CMIS_CABLE //dev_type - }, - { - DeviceCableCMISPaging, //dm_id - 0x19, //hw_dev_id - 0xab, //hw_rev_id - -1, //sw_dev_id - "CableCMISPaging", //name - -1, //port_num - DM_CMIS_CABLE //dev_type - }, - { - DeviceCableSFP, //dm_id - 0x03, //hw_dev_id - 1, //hw_rev_id - -1, //sw_dev_id - "CableSFP", //name - -1, //port_num - DM_SFP_CABLE //dev_type - }, - { - DeviceCableSFP51, //dm_id - 0x03, //hw_dev_id - 1, //hw_rev_id - -1, //sw_dev_id - "CableSFP51", //name - -1, //port_num - DM_SFP_CABLE //dev_type - }, - { - DeviceCableSFP51Paging, //dm_id - 0x03, //hw_dev_id - 1, //hw_rev_id - -1, //sw_dev_id - "CableSFP51Paging", //name - -1, //port_num - DM_SFP_CABLE //dev_type - }, - { - DeviceSpectrum2, //dm_id - 0x24e, //hw_dev_id - -1, //hw_rev_id - -1, //sw_dev_id - "Spectrum2", //name - 128, //port_num - DM_SWITCH //dev_type - }, - { - DeviceDummy, //dm_id - 0x1, //hw_dev_id - -1, //hw_rev_id - -1, //sw_dev_id - "DummyDevice", //name - 2, //port_num - DM_HCA //dev_type - }, - { - DeviceQuantum, //dm_id - 0x24d, //hw_dev_id - -1, //hw_rev_id - -1, //sw_dev_id - "Quantum", //name - 80, //port_num - DM_SWITCH //dev_type - }, - { - DeviceArdbeg, //dm_id - 0x6e, //hw_dev_id (ArdbegMirror 0x70) - -1, //hw_rev_id - -1, //sw_dev_id - "Ardbeg", //name - -1, //port_num - DM_LINKX //dev_type - }, - { - DeviceBaritone, //dm_id - 0x6b, //hw_dev_id (BaritoneMirror 0x71) - -1, //hw_rev_id - -1, //sw_dev_id - "Baritone", //name - -1, //port_num - DM_LINKX //dev_type - }, - { - DeviceMenhit, //dm_id - 0x72, //hw_dev_id (other versions 0x6f,0x73) - -1, //hw_rev_id - -1, //sw_dev_id - "Menhit", //name - -1, //port_num - DM_LINKX //dev_type - }, - { - DeviceSecureHost, //dm_id - 0xcafe, //hw_dev_id - 0xd0, //hw_rev_id - 0, //sw_dev_id - "Unknown Device", //name - -1, //port_num - DM_UNKNOWN //dev_type - }, - { - DeviceSpectrum3, //dm_id - 0x250, //hw_dev_id - -1, //hw_rev_id - -1, //sw_dev_id - "Spectrum3", //name - 128, //port_num NEED_CHECK - DM_SWITCH //dev_type - }, - { - DeviceSpectrum4, //dm_id - 0x254, //hw_dev_id - -1, //hw_rev_id - -1, //sw_dev_id - "Spectrum4", //name - 128, //port_num NEED_CHECK - DM_SWITCH //dev_type - }, - { - DeviceQuantum2, //dm_id - 0x257, //hw_dev_id - -1, //hw_rev_id - -1, //sw_dev_id - "Quantum2", //name - 128, //port_num NEED_CHECK - DM_SWITCH //dev_type - }, - { - DeviceGearBox, //dm_id - 0x252, //hw_dev_id - -1, //hw_rev_id - -1, //sw_dev_id - "AmosGearBox", //name - 128, //port_num NEED_CHECK - DM_GEARBOX //dev_type - }, - { - DeviceGearBoxManager, //dm_id - 0x253, //hw_dev_id - -1, //hw_rev_id - -1, //sw_dev_id - "AmosGearBoxManager", //name - -1, //port_num NEED_CHECK - DM_GEARBOX //dev_type - }, - { - DeviceAbirGearBox, //dm_id - 0x256, //hw_dev_id - -1, //hw_rev_id - -1, //sw_dev_id - "AbirGearBox", //name - -1, //port_num NEED_CHECK - DM_GEARBOX //dev_type - }, - { - DeviceUnknown, //dm_id - 0, //hw_dev_id - 0, //hw_rev_id - 0, //sw_dev_id - "Unknown Device", //name - -1, //port_num - DM_UNKNOWN //dev_type - } -}; +static struct device_info g_devs_info[] = {{ + DeviceInfiniScaleIV, // dm_id + 0x01b3, // hw_dev_id + -1, // hw_rev_id + -1, // sw_dev_id + "InfiniScaleIV", // name + 36, // port_num + DM_SWITCH // dev_type + }, + { + DeviceSwitchX, // dm_id + 0x0245, // hw_dev_id + -1, // hw_rev_id + -1, // sw_dev_id + "SwitchX", // name + 64, // port_num + DM_SWITCH // dev_type + }, + { + DeviceConnectX2, // dm_id + 0x190, // hw_dev_id + 0xb0, // hw_rev_id + -1, // sw_dev_id + "ConnectX2", // name + 2, // port_num + DM_HCA // dev_type + }, + { + DeviceConnectX3, // dm_id + 0x1f5, // hw_dev_id + -1, // hw_rev_id + -1, // sw_dev_id + "ConnectX3", // name + 2, // port_num + DM_HCA // dev_type + }, + { + DeviceConnectIB, // dm_id + 0x1ff, // hw_dev_id + -1, // hw_rev_id + -1, // sw_dev_id + "ConnectIB", // name + 2, // port_num + DM_HCA // dev_type + }, + { + DeviceConnectX3Pro, // dm_id + 0x1f7, // hw_dev_id + -1, // hw_rev_id + -1, // sw_dev_id + "ConnectX3Pro", // name + 2, // port_num + DM_HCA // dev_type + }, + { + DeviceSwitchIB, // dm_id + 0x247, // hw_dev_id + -1, // hw_rev_id + -1, // sw_dev_id + "SwitchIB", // name + 36, // port_num + DM_SWITCH // dev_type + }, + { + DeviceSpectrum, // dm_id + 0x249, // hw_dev_id + -1, // hw_rev_id + -1, // sw_dev_id + "Spectrum", // name + 64, // port_num + DM_SWITCH // dev_type + }, + { + DeviceConnectX4, // dm_id + 0x209, // hw_dev_id + -1, // hw_rev_id + -1, // sw_dev_id + "ConnectX4", // name + 2, // port_num + DM_HCA // dev_type + }, + { + DeviceConnectX4LX, // dm_id + 0x20b, // hw_dev_id + -1, // hw_rev_id + -1, // sw_dev_id + "ConnectX4LX", // name + 2, // port_num + DM_HCA // dev_type + }, + { + DeviceConnectX5, // dm_id + 0x20d, // hw_dev_id + -1, // hw_rev_id + -1, // sw_dev_id + "ConnectX5", // name + 2, // port_num + DM_HCA // dev_type + }, + { + DeviceConnectX6, // dm_id + 0x20f, // hw_dev_id + -1, // hw_rev_id + -1, // sw_dev_id + "ConnectX6", // name + 2, // port_num + DM_HCA // dev_type + }, + { + DeviceConnectX6DX, // dm_id + 0x212, // hw_dev_id + -1, // hw_rev_id + -1, // sw_dev_id + "ConnectX6DX", // name + 2, // port_num + DM_HCA // dev_type + }, + { + DeviceConnectX6LX, // dm_id + 0x216, // hw_dev_id + -1, // hw_rev_id + -1, // sw_dev_id + "ConnectX6LX", // name + 2, // port_num + DM_HCA // dev_type + }, + { + DeviceConnectX7, // dm_id + 0x218, // hw_dev_id + -1, // hw_rev_id + -1, // sw_dev_id + "ConnectX7", // name + 4, // port_num + DM_HCA // dev_type + }, + { + DeviceBlueField, // dm_id + 0x211, // hw_dev_id + -1, // hw_rev_id + -1, // sw_dev_id + "BlueField", // name + 2, // port_num + DM_HCA // dev_type + }, + { + DeviceBlueField2, // dm_id + 0x214, // hw_dev_id + -1, // hw_rev_id + -1, // sw_dev_id + "BlueField2", // name + 2, // port_num + DM_HCA // dev_type + }, + { + DeviceBlueField3, // dm_id + 0x21c, // hw_dev_id + -1, // hw_rev_id + -1, // sw_dev_id + "BlueField3", // name + 4, // port_num + DM_HCA // dev_type + }, + { + DeviceSwitchIB2, // dm_id + 0x24b, // hw_dev_id + -1, // hw_rev_id + -1, // sw_dev_id + "SwitchIB2", // name + 36, // port_num + DM_SWITCH // dev_type + }, + { + DeviceCableQSFP, // dm_id + 0x0d, // hw_dev_id + 0, // hw_rev_id + -1, // sw_dev_id + "CableQSFP", // name + -1, // port_num + DM_QSFP_CABLE // dev_type + }, + { + DeviceCableQSFPaging, // dm_id + 0x11, // hw_dev_id + 0xab, // hw_rev_id + -1, // sw_dev_id + "CableQSFPaging", // name + -1, // port_num + DM_QSFP_CABLE // dev_type + }, + { + DeviceCableCMIS, // dm_id + 0x19, // hw_dev_id + 0, // hw_rev_id + -1, // sw_dev_id + "CableCMIS", // name + -1, // port_num + DM_CMIS_CABLE // dev_type + }, + { + DeviceCableCMISPaging, // dm_id + 0x19, // hw_dev_id + 0xab, // hw_rev_id + -1, // sw_dev_id + "CableCMISPaging", // name + -1, // port_num + DM_CMIS_CABLE // dev_type + }, + { + DeviceCableSFP, // dm_id + 0x03, // hw_dev_id + 1, // hw_rev_id + -1, // sw_dev_id + "CableSFP", // name + -1, // port_num + DM_SFP_CABLE // dev_type + }, + { + DeviceCableSFP51, // dm_id + 0x03, // hw_dev_id + 1, // hw_rev_id + -1, // sw_dev_id + "CableSFP51", // name + -1, // port_num + DM_SFP_CABLE // dev_type + }, + { + DeviceCableSFP51Paging, // dm_id + 0x03, // hw_dev_id + 1, // hw_rev_id + -1, // sw_dev_id + "CableSFP51Paging", // name + -1, // port_num + DM_SFP_CABLE // dev_type + }, + { + DeviceSpectrum2, // dm_id + 0x24e, // hw_dev_id + -1, // hw_rev_id + -1, // sw_dev_id + "Spectrum2", // name + 128, // port_num + DM_SWITCH // dev_type + }, + { + DeviceDummy, // dm_id + 0x1, // hw_dev_id + -1, // hw_rev_id + -1, // sw_dev_id + "DummyDevice", // name + 2, // port_num + DM_HCA // dev_type + }, + { + DeviceQuantum, // dm_id + 0x24d, // hw_dev_id + -1, // hw_rev_id + -1, // sw_dev_id + "Quantum", // name + 80, // port_num + DM_SWITCH // dev_type + }, + { + DeviceArdbeg, // dm_id + 0x6e, // hw_dev_id (ArdbegMirror 0x70) + -1, // hw_rev_id + -1, // sw_dev_id + "Ardbeg", // name + -1, // port_num + DM_LINKX // dev_type + }, + { + DeviceBaritone, // dm_id + 0x6b, // hw_dev_id (BaritoneMirror 0x71) + -1, // hw_rev_id + -1, // sw_dev_id + "Baritone", // name + -1, // port_num + DM_LINKX // dev_type + }, + { + DeviceMenhit, // dm_id + 0x72, // hw_dev_id (other versions 0x6f,0x73) + -1, // hw_rev_id + -1, // sw_dev_id + "Menhit", // name + -1, // port_num + DM_LINKX // dev_type + }, + { + DeviceSecureHost, // dm_id + 0xcafe, // hw_dev_id + 0xd0, // hw_rev_id + 0, // sw_dev_id + "Unknown Device", // name + -1, // port_num + DM_UNKNOWN // dev_type + }, + { + DeviceSpectrum3, // dm_id + 0x250, // hw_dev_id + -1, // hw_rev_id + -1, // sw_dev_id + "Spectrum3", // name + 128, // port_num NEED_CHECK + DM_SWITCH // dev_type + }, + { + DeviceSpectrum4, // dm_id + 0x254, // hw_dev_id + -1, // hw_rev_id + -1, // sw_dev_id + "Spectrum4", // name + 128, // port_num NEED_CHECK + DM_SWITCH // dev_type + }, + { + DeviceQuantum2, // dm_id + 0x257, // hw_dev_id + -1, // hw_rev_id + -1, // sw_dev_id + "Quantum2", // name + 128, // port_num NEED_CHECK + DM_SWITCH // dev_type + }, + { + DeviceGearBox, // dm_id + 0x252, // hw_dev_id + -1, // hw_rev_id + -1, // sw_dev_id + "AmosGearBox", // name + 128, // port_num NEED_CHECK + DM_GEARBOX // dev_type + }, + { + DeviceGearBoxManager, // dm_id + 0x253, // hw_dev_id + -1, // hw_rev_id + -1, // sw_dev_id + "AmosGearBoxManager", // name + -1, // port_num NEED_CHECK + DM_GEARBOX // dev_type + }, + { + DeviceAbirGearBox, // dm_id + 0x256, // hw_dev_id + -1, // hw_rev_id + -1, // sw_dev_id + "AbirGearBox", // name + -1, // port_num NEED_CHECK + DM_GEARBOX // dev_type + }, + { + DeviceUnknown, // dm_id + 0, // hw_dev_id + 0, // hw_rev_id + 0, // sw_dev_id + "Unknown Device", // name + -1, // port_num + DM_UNKNOWN // dev_type + }}; static const struct device_info* get_entry(dm_dev_id_t type) { - const struct device_info *p = g_devs_info; - while (p->dm_id != DeviceUnknown) { - if (type == p->dm_id) { + const struct device_info* p = g_devs_info; + while (p->dm_id != DeviceUnknown) + { + if (type == p->dm_id) + { break; } p++; @@ -484,10 +486,13 @@ static const struct device_info* get_entry(dm_dev_id_t type) static const struct device_info* get_entry_by_dev_rev_id(u_int32_t hw_dev_id, u_int32_t hw_rev_id) { - const struct device_info *p = g_devs_info; - while (p->dm_id != DeviceUnknown) { - if (hw_dev_id == p->hw_dev_id) { - if ((p->hw_rev_id == -1) || ((int)hw_rev_id == p->hw_rev_id)) { + const struct device_info* p = g_devs_info; + while (p->dm_id != DeviceUnknown) + { + if (hw_dev_id == p->hw_dev_id) + { + if ((p->hw_rev_id == -1) || ((int)hw_rev_id == p->hw_rev_id)) + { break; } } @@ -496,26 +501,25 @@ static const struct device_info* get_entry_by_dev_rev_id(u_int32_t hw_dev_id, u_ return p; } -typedef enum get_dev_id_error_t { +typedef enum get_dev_id_error_t +{ GET_DEV_ID_SUCCESS, GET_DEV_ID_ERROR, CRSPACE_READ_ERROR, CHECK_PTR_DEV_ID, } dev_id_error; -static int dm_get_device_id_inner(mfile *mf, - dm_dev_id_t *ptr_dm_dev_id, - u_int32_t *ptr_hw_dev_id, - u_int32_t *ptr_hw_rev) +static int dm_get_device_id_inner(mfile* mf, dm_dev_id_t* ptr_dm_dev_id, u_int32_t* ptr_hw_dev_id, u_int32_t* ptr_hw_rev) { u_int32_t dword = 0; int rc; u_int32_t dev_flags; #ifdef CABLES_SUPP - if (mf->tp == MST_LINKX_CHIP){ - - switch (mf->linkx_chip_devid){ + if (mf->tp == MST_LINKX_CHIP) + { + switch (mf->linkx_chip_devid) + { case ARDBEG_REV0_DEVID: case ARDBEG_REV1_DEVID: case ARDBEG_MIRRORED_DEVID: @@ -536,97 +540,126 @@ static int dm_get_device_id_inner(mfile *mf, } *ptr_hw_dev_id = (u_int32_t)mf->linkx_chip_devid; return GET_DEV_ID_SUCCESS; - } - if (mf->tp == MST_CABLE) { - //printf("-D- Getting cable ID\n"); - if (mread4(mf, CABLEID_ADDR, &dword) != 4) { - //printf("FATAL - crspace read (0x%x) failed: %s\n", DEVID_ADDR, strerror(errno)); + if (mf->tp == MST_CABLE) + { + // printf("-D- Getting cable ID\n"); + if (mread4(mf, CABLEID_ADDR, &dword) != 4) + { + // printf("FATAL - crspace read (0x%x) failed: %s\n", DEVID_ADDR, strerror(errno)); return GET_DEV_ID_ERROR; } - //dword = __cpu_to_le32(dword); // Cable pages are read in LE, no need to swap + // dword = __cpu_to_le32(dword); // Cable pages are read in LE, no need to swap *ptr_hw_dev_id = 0xffff; u_int8_t id = EXTRACT(dword, 0, 8); enum dm_dev_type cbl_type = getCableType(id); u_int8_t paging; - if (cbl_type == DM_QSFP_CABLE) { + if (cbl_type == DM_QSFP_CABLE) + { // Get Byte 2 bit 2 ~ bit 18 (flat_mem : upper memory flat or paged. 0=paging, 1=page 0 only) paging = EXTRACT(dword, 18, 1); - //printf("DWORD: %#x, paging: %d\n", dword, paging); - if (paging == 0) { + // printf("DWORD: %#x, paging: %d\n", dword, paging); + if (paging == 0) + { *ptr_dm_dev_id = DeviceCableQSFPaging; - } else { + } + else + { *ptr_dm_dev_id = DeviceCableQSFP; } - } else if (cbl_type == DM_SFP_CABLE) { + } + else if (cbl_type == DM_SFP_CABLE) + { *ptr_dm_dev_id = DeviceCableSFP; - if (mread4(mf, SFP_DIGITAL_DIAGNOSTIC_MONITORING_IMPLEMENTED_ADDR, &dword) != 4) { - //printf("FATAL - crspace read (0x%x) failed: %s\n", DEVID_ADDR, strerror(errno)); + if (mread4(mf, SFP_DIGITAL_DIAGNOSTIC_MONITORING_IMPLEMENTED_ADDR, &dword) != 4) + { + // printf("FATAL - crspace read (0x%x) failed: %s\n", DEVID_ADDR, strerror(errno)); return GET_DEV_ID_ERROR; } - u_int8_t byte = EXTRACT(dword, 6, 1); //Byte 92 bit 6 (digital diagnostic monitoring implemented) - if (byte) { + u_int8_t byte = EXTRACT(dword, 6, 1); // Byte 92 bit 6 (digital diagnostic monitoring implemented) + if (byte) + { *ptr_dm_dev_id = DeviceCableSFP51; - if (mread4(mf, SFP_PAGING_IMPLEMENTED_INDICATOR_ADDR, &dword) != 4) { - //printf("FATAL - crspace read (0x%x) failed: %s\n", DEVID_ADDR, strerror(errno)); + if (mread4(mf, SFP_PAGING_IMPLEMENTED_INDICATOR_ADDR, &dword) != 4) + { + // printf("FATAL - crspace read (0x%x) failed: %s\n", DEVID_ADDR, strerror(errno)); return GET_DEV_ID_ERROR; } - byte = EXTRACT(dword, 4, 1); //Byte 64 bit 4 (paging implemented indicator) - if (byte) { + byte = EXTRACT(dword, 4, 1); // Byte 64 bit 4 (paging implemented indicator) + if (byte) + { *ptr_dm_dev_id = DeviceCableSFP51Paging; } } - } else if (cbl_type == DM_CMIS_CABLE) { + } + else if (cbl_type == DM_CMIS_CABLE) + { // Get Byte 2 bit 7 ~ bit 23 (flat_mem : upper memory flat or paged. 0=paging, 1=page 0 only) paging = EXTRACT(dword, 23, 1); - if (paging == 0) { + if (paging == 0) + { *ptr_dm_dev_id = DeviceCableCMISPaging; - } else { + } + else + { *ptr_dm_dev_id = DeviceCableCMIS; } - } else { + } + else + { *ptr_dm_dev_id = DeviceUnknown; } return GET_DEV_ID_SUCCESS; } #endif - rc = mget_mdevs_flags(mf, &dev_flags); - if (rc) { + if (rc) + { dev_flags = 0; } // get hw id // Special case for MLNX OS getting dev_id using REG MGIR - if (dev_flags & MDEVS_MLNX_OS) { + if (dev_flags & MDEVS_MLNX_OS) + { reg_access_status_t rc; struct reg_access_hca_mgir mgir; memset(&mgir, 0, sizeof(mgir)); rc = reg_access_mgir(mf, REG_ACCESS_METHOD_GET, &mgir); - //printf("-D- RC[%s] -- REVID: %d -- DEVID: %d hw_dev_id: %d\n", m_err2str(rc), mgir.HWInfo.REVID, mgir.HWInfo.DEVID, mgir.HWInfo.hw_dev_id); - if (rc) { + // printf("-D- RC[%s] -- REVID: %d -- DEVID: %d hw_dev_id: %d\n", m_err2str(rc), mgir.HWInfo.REVID, + // mgir.HWInfo.DEVID, mgir.HWInfo.hw_dev_id); + if (rc) + { dword = get_entry(DeviceSwitchX)->hw_dev_id; - *ptr_hw_rev = 0; + *ptr_hw_rev = 0; *ptr_hw_dev_id = get_entry(DeviceSwitchX)->hw_dev_id; - } else { + } + else + { dword = mgir.hw_info.hw_dev_id; - if (dword == 0) { + if (dword == 0) + { dword = get_entry(DeviceSwitchX)->hw_dev_id; *ptr_hw_dev_id = get_entry(DeviceSwitchX)->hw_dev_id; *ptr_hw_rev = mgir.hw_info.device_hw_revision & 0xf; - } else { + } + else + { *ptr_hw_dev_id = dword; - *ptr_hw_rev = 0; //WA: MGIR should have also hw_rev_id and then we can use it. + *ptr_hw_rev = 0; // WA: MGIR should have also hw_rev_id and then we can use it. } } - } else { - if (mread4(mf, DEVID_ADDR, &dword) != 4) { + } + else + { + if (mread4(mf, DEVID_ADDR, &dword) != 4) + { return CRSPACE_READ_ERROR; } *ptr_hw_dev_id = EXTRACT(dword, 0, 16); - *ptr_hw_rev = EXTRACT(dword, 16, 8); + *ptr_hw_rev = EXTRACT(dword, 16, 8); } *ptr_dm_dev_id = get_entry_by_dev_rev_id(*ptr_hw_dev_id, *ptr_hw_rev)->dm_id; @@ -636,20 +669,19 @@ static int dm_get_device_id_inner(mfile *mf, /** * Returns 0 on success and 1 on failure. */ -int dm_get_device_id(mfile *mf, - dm_dev_id_t *ptr_dm_dev_id, - u_int32_t *ptr_hw_dev_id, - u_int32_t *ptr_hw_rev) +int dm_get_device_id(mfile* mf, dm_dev_id_t* ptr_dm_dev_id, u_int32_t* ptr_hw_dev_id, u_int32_t* ptr_hw_rev) { int return_value = 1; - return_value = dm_get_device_id_inner(mf, ptr_dm_dev_id, - ptr_hw_dev_id, ptr_hw_rev); - if (return_value == CRSPACE_READ_ERROR) { + return_value = dm_get_device_id_inner(mf, ptr_dm_dev_id, ptr_hw_dev_id, ptr_hw_rev); + if (return_value == CRSPACE_READ_ERROR) + { printf("FATAL - crspace read (0x%x) failed: %s\n", DEVID_ADDR, strerror(errno)); return GET_DEV_ID_ERROR; - } else if (return_value == CHECK_PTR_DEV_ID) { - if (*ptr_dm_dev_id == DeviceUnknown) { - + } + else if (return_value == CHECK_PTR_DEV_ID) + { + if (*ptr_dm_dev_id == DeviceUnknown) + { // Due to issue 2719128, we prefer to skip this device // and not filter using the 'pciconf' FreeBSD tool #ifndef __FreeBSD__ @@ -664,16 +696,17 @@ int dm_get_device_id(mfile *mf, } // Due to issue 2846942, added this function to be used on mdevices) -int dm_get_device_id_without_prints(mfile *mf, - dm_dev_id_t *ptr_dm_dev_id, - u_int32_t *ptr_hw_dev_id, - u_int32_t *ptr_hw_rev) +int dm_get_device_id_without_prints(mfile* mf, + dm_dev_id_t* ptr_dm_dev_id, + u_int32_t* ptr_hw_dev_id, + u_int32_t* ptr_hw_rev) { int return_value = 1; - return_value = dm_get_device_id_inner(mf, ptr_dm_dev_id, - ptr_hw_dev_id, ptr_hw_rev); - if (return_value == CHECK_PTR_DEV_ID) { - if (*ptr_dm_dev_id == DeviceUnknown) { + return_value = dm_get_device_id_inner(mf, ptr_dm_dev_id, ptr_hw_dev_id, ptr_hw_rev); + if (return_value == CHECK_PTR_DEV_ID) + { + if (*ptr_dm_dev_id == DeviceUnknown) + { return MFE_UNSUPPORTED_DEVICE; } return GET_DEV_ID_SUCCESS; @@ -681,12 +714,10 @@ int dm_get_device_id_without_prints(mfile *mf, return return_value; } -int dm_get_device_id_offline(u_int32_t devid, - u_int32_t chip_rev, - dm_dev_id_t *ptr_dev_type) +int dm_get_device_id_offline(u_int32_t devid, u_int32_t chip_rev, dm_dev_id_t* ptr_dev_type) { *ptr_dev_type = get_entry_by_dev_rev_id(devid, chip_rev)->dm_id; - return *ptr_dev_type == DeviceUnknown ? MFE_UNSUPPORTED_DEVICE: MFE_OK; + return *ptr_dev_type == DeviceUnknown ? MFE_UNSUPPORTED_DEVICE : MFE_OK; } const char* dm_dev_type2str(dm_dev_id_t type) @@ -694,14 +725,17 @@ const char* dm_dev_type2str(dm_dev_id_t type) return get_entry(type)->name; } -dm_dev_id_t dm_dev_str2type(const char *str) +dm_dev_id_t dm_dev_str2type(const char* str) { - const struct device_info *p = g_devs_info; - if (!str) { + const struct device_info* p = g_devs_info; + if (!str) + { return DeviceUnknown; } - while (p->dm_id != DeviceUnknown) { - if (strcmp(str, p->name) == 0) { + while (p->dm_id != DeviceUnknown) + { + if (strcmp(str, p->name) == 0) + { return p->dm_id; } p++; @@ -722,7 +756,8 @@ int dm_dev_is_hca(dm_dev_id_t type) int dm_dev_is_200g_speed_supported_hca(dm_dev_id_t type) { bool isBlueField = (type == DeviceBlueField || type == DeviceBlueField2 || type == DeviceBlueField3); - return !isBlueField && (dm_dev_is_hca(type) && (get_entry(type)->hw_dev_id >= get_entry(DeviceConnectX6)->hw_dev_id)); + return !isBlueField && + (dm_dev_is_hca(type) && (get_entry(type)->hw_dev_id >= get_entry(DeviceConnectX6)->hw_dev_id)); } int dm_dev_is_switch(dm_dev_id_t type) @@ -740,15 +775,18 @@ int dm_dev_is_bridge(dm_dev_id_t type) return get_entry(type)->dev_type == DM_BRIDGE; } -int dm_dev_is_qsfp_cable(dm_dev_id_t type) { +int dm_dev_is_qsfp_cable(dm_dev_id_t type) +{ return get_entry(type)->dev_type == DM_QSFP_CABLE; } -int dm_dev_is_sfp_cable(dm_dev_id_t type) { +int dm_dev_is_sfp_cable(dm_dev_id_t type) +{ return get_entry(type)->dev_type == DM_SFP_CABLE; } -int dm_dev_is_cmis_cable(dm_dev_id_t type) { +int dm_dev_is_cmis_cable(dm_dev_id_t type) +{ return get_entry(type)->dev_type == DM_CMIS_CABLE; } @@ -770,7 +808,7 @@ u_int32_t dm_get_hw_rev_id(dm_dev_id_t type) int dm_is_fpp_supported(dm_dev_id_t type) { // Function per port is supported only in HCAs that arrived after CX3 - const struct device_info *dp = get_entry(type); + const struct device_info* dp = get_entry(type); return dm_is_5th_gen_hca(dp->dm_id); } @@ -779,27 +817,33 @@ int dm_is_device_supported(dm_dev_id_t type) return get_entry(type)->dm_id != DeviceUnknown; } -int dm_is_livefish_mode(mfile *mf) +int dm_is_livefish_mode(mfile* mf) { - if (!mf || !mf->dinfo) { + if (!mf || !mf->dinfo) + { return 0; } - if (mf->tp == MST_SOFTWARE) { + if (mf->tp == MST_SOFTWARE) + { return 1; } dm_dev_id_t devid_t = DeviceUnknown; u_int32_t devid = 0; u_int32_t revid = 0; int rc = dm_get_device_id(mf, &devid_t, &devid, &revid); - if (rc) { + if (rc) + { // Could not detrmine , by default is not livefish return 0; } u_int32_t swid = mf->dinfo->pci.dev_id; - //printf("-D- swid: %#x, devid: %#x\n", swid, devid); - if (dm_is_4th_gen(devid_t) || dm_is_switchx(devid_t)) { + // printf("-D- swid: %#x, devid: %#x\n", swid, devid); + if (dm_is_4th_gen(devid_t) || dm_is_switchx(devid_t)) + { return (devid == swid - 1); - } else { + } + else + { return (devid == swid); } @@ -808,9 +852,7 @@ int dm_is_livefish_mode(mfile *mf) int dm_is_4th_gen(dm_dev_id_t type) { - return (type == DeviceConnectX2 || - type == DeviceConnectX3 || - type == DeviceConnectX3Pro); + return (type == DeviceConnectX2 || type == DeviceConnectX3 || type == DeviceConnectX3Pro); } int dm_is_5th_gen_hca(dm_dev_id_t type) @@ -835,11 +877,12 @@ int dm_is_new_gen_switch(dm_dev_id_t type) int dm_dev_is_raven_family_switch(dm_dev_id_t type) { - return (dm_dev_is_switch(type) && (type == DeviceQuantum || type == DeviceQuantum2 || type == DeviceSpectrum2 || type == DeviceSpectrum3 || type == DeviceSpectrum4)); + return (dm_dev_is_switch(type) && (type == DeviceQuantum || type == DeviceQuantum2 || type == DeviceSpectrum2 || + type == DeviceSpectrum3 || type == DeviceSpectrum4)); } int dm_dev_is_ib_switch(dm_dev_id_t type) { - return (dm_dev_is_switch(type) && (type == DeviceQuantum || type == DeviceQuantum2 || type == DeviceSwitchIB || type == DeviceSwitchIB2)); + return (dm_dev_is_switch(type) && + (type == DeviceQuantum || type == DeviceQuantum2 || type == DeviceSwitchIB || type == DeviceSwitchIB2)); } - diff --git a/dev_mgt/tools_dev_types.h b/dev_mgt/tools_dev_types.h index 2ccbab2a..98674504 100644 --- a/dev_mgt/tools_dev_types.h +++ b/dev_mgt/tools_dev_types.h @@ -44,75 +44,76 @@ #define TOOLS_DEV_TYPE_H #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif #include #include #include -enum dm_dev_id -{ - DeviceUnknown = -1, //Dummy Device - Marker for indicating error. - DeviceStartMarker = 0, // Dummy Device - Marker for first device - // to let user iterate from DeviceStartMarker to DeviceEndMarker - // Note: Call dm_is_device_supported() to see if a device is supported by the lib. - - DeviceInfiniScale = 0, // UnSupported - DeviceInfiniHost, // UnSupported - DeviceInfiniHostIIIEx, // UnSupported - DeviceInfiniHostIIIEx_MF,// UnSupported - DeviceInfiniScaleIII, // UnSupported - DeviceInfiniHostIIILx, // UnSupported - DeviceConnectX, // UnSupported - DeviceConnectX2, - DeviceInfiniScaleIV, - DeviceBridgeX, // UnSupported - DeviceSwitchX, - DeviceConnectX3, - DeviceConnectIB, - DeviceConnectX3Pro, - DeviceSwitchIB, - DeviceSpectrum, - DeviceQuantum, - DeviceConnectX4, - DeviceConnectX4LX, - DeviceConnectX5, - DeviceConnectX6, - DeviceBlueField, - DeviceBlueField2, - DeviceBlueField3, - DeviceFPGA, // UnSupported - DeviceSwitchIB2, - DeviceFPGANewton, // Unsupported - DeviceCable, - DeviceCableQSFP, - DeviceCableQSFPaging, - DeviceCableSFP, - DeviceCableSFP51, - DeviceCableSFP51Paging, - DeviceArdbeg, - DeviceBaritone, - DeviceMenhit, - DeviceSpectrum2, - DeviceDummy, - DeviceSecureHost, - DeviceConnectX6DX, - DeviceConnectX6LX, - DeviceConnectX7, - DeviceSpectrum3, // Firebird - DeviceSpectrum4, // Albatross - DeviceQuantum2, // Blackbird - DeviceGearBox, - DeviceGearBoxManager, - DeviceAbirGearBox, - DeviceCableCMIS, - DeviceCableCMISPaging, - DeviceEndMarker // Dummy Device - Marker for indicating end of devices when iterating -}; - -enum hw_dev_id -{ + enum dm_dev_id + { + DeviceUnknown = -1, // Dummy Device - Marker for indicating error. + DeviceStartMarker = 0, // Dummy Device - Marker for first device + // to let user iterate from DeviceStartMarker to DeviceEndMarker + // Note: Call dm_is_device_supported() to see if a device is supported by the lib. + + DeviceInfiniScale = 0, // UnSupported + DeviceInfiniHost, // UnSupported + DeviceInfiniHostIIIEx, // UnSupported + DeviceInfiniHostIIIEx_MF, // UnSupported + DeviceInfiniScaleIII, // UnSupported + DeviceInfiniHostIIILx, // UnSupported + DeviceConnectX, // UnSupported + DeviceConnectX2, + DeviceInfiniScaleIV, + DeviceBridgeX, // UnSupported + DeviceSwitchX, + DeviceConnectX3, + DeviceConnectIB, + DeviceConnectX3Pro, + DeviceSwitchIB, + DeviceSpectrum, + DeviceQuantum, + DeviceConnectX4, + DeviceConnectX4LX, + DeviceConnectX5, + DeviceConnectX6, + DeviceBlueField, + DeviceBlueField2, + DeviceBlueField3, + DeviceFPGA, // UnSupported + DeviceSwitchIB2, + DeviceFPGANewton, // Unsupported + DeviceCable, + DeviceCableQSFP, + DeviceCableQSFPaging, + DeviceCableSFP, + DeviceCableSFP51, + DeviceCableSFP51Paging, + DeviceArdbeg, + DeviceBaritone, + DeviceMenhit, + DeviceSpectrum2, + DeviceDummy, + DeviceSecureHost, + DeviceConnectX6DX, + DeviceConnectX6LX, + DeviceConnectX7, + DeviceSpectrum3, // Firebird + DeviceSpectrum4, // Albatross + DeviceQuantum2, // Blackbird + DeviceGearBox, + DeviceGearBoxManager, + DeviceAbirGearBox, + DeviceCableCMIS, + DeviceCableCMISPaging, + DeviceEndMarker // Dummy Device - Marker for indicating end of devices when iterating + }; + + enum hw_dev_id + { DeviceInfiniScale_HwId = 0x01b3, DeviceSwitchX_HwId = 0x0245, DeviceConnectX2_HwId = 0x190, @@ -138,7 +139,7 @@ enum hw_dev_id DeviceCableCMISPaging_HwId = 0x19, DeviceCableSFP_HwId = 0x03, DeviceCableSFP51_HwId = 0x03, - DeviceCableSFP51Paging_HwId =0x03, + DeviceCableSFP51Paging_HwId = 0x03, DeviceSpectrum2_HwId = 0x24e, DeviceQuantum_HwId = 0x24d, DeviceQuantum2_HwId = 0x257, @@ -151,117 +152,110 @@ enum hw_dev_id DeviceGearBox_HwId = 0x252, DeviceGearBoxManager_HwId = 0x253, DeviceAbirGearBox_HwId = 0x256 -}; -typedef enum dm_dev_id dm_dev_id_t; - -/** - * Returns 0 on success and 1 on failure. - */ -int dm_get_device_id(mfile *mf, - dm_dev_id_t *ptr_dev_type, - u_int32_t *ptr_dev_id, - u_int32_t *ptr_chip_rev); - -int dm_get_device_id_without_prints(mfile *mf, - dm_dev_id_t *ptr_dm_dev_id, - u_int32_t *ptr_hw_dev_id, - u_int32_t *ptr_hw_rev); - -/** - * Returns 0 on success and 1 on failure. - */ -int dm_get_device_id_offline(u_int32_t devid, - u_int32_t chip_rev, - dm_dev_id_t *ptr_dev_type); - - -/** - * Returns 1 if device is supported and 0 otherwise (library dependant) - */ -int dm_is_device_supported(dm_dev_id_t type); - - -/** - * Returns the device name as a "const char*" - */ -const char* dm_dev_type2str(dm_dev_id_t type); - -/** - * Returns the device id - */ -dm_dev_id_t dm_dev_str2type(const char *str); - -/** - * A predicate returning if the device is an hca - */ -int dm_dev_is_hca(dm_dev_id_t type); - -/** - * A predicate returning if the hca supports 200G speed and above - */ -int dm_dev_is_200g_speed_supported_hca(dm_dev_id_t type); - -/** - * A predicate returning if the device is a switch - */ -int dm_dev_is_switch(dm_dev_id_t type); - -/** - * A predicate returning if the switch supports 200G speed and above - */ -int dm_dev_is_200g_speed_supported_switch(dm_dev_id_t type); - -/** - * A predicate returning if the device is a bridge - */ -int dm_dev_is_bridge(dm_dev_id_t type); - -/** - * A predicate returning if the device is a Cable - */ -int dm_dev_is_cable(dm_dev_id_t type); - -/** - * Returns the max num of ports or -1 on error - */ -int dm_get_hw_ports_num(dm_dev_id_t type); - -/** - * Returns the HW device id of the givn device type or zero on failure. - */ -u_int32_t dm_get_hw_dev_id(dm_dev_id_t type); - -/** - * Returns the HW chip revision of the given device type or zero on failures, - * This is useful to distinguish between ConnectX2 and ConnectX. - */ -u_int32_t dm_get_hw_rev_id(dm_dev_id_t type); - -/** - * A predicate returning if the device supports Function Per Port - */ -int dm_is_fpp_supported(dm_dev_id_t type); - -int dm_is_4th_gen(dm_dev_id_t type); - -int dm_is_5th_gen_hca(dm_dev_id_t type); - -int dm_is_connectib(dm_dev_id_t type); - -int dm_is_switchx(dm_dev_id_t type); - -int dm_is_new_gen_switch(dm_dev_id_t type); - -int dm_dev_is_raven_family_switch(dm_dev_id_t type); - -int dm_dev_is_ib_switch(dm_dev_id_t type); -/* - * A predicate returning if the device is in LiveFish mode - */ -int dm_is_livefish_mode(mfile *mf); + }; + typedef enum dm_dev_id dm_dev_id_t; + + /** + * Returns 0 on success and 1 on failure. + */ + int dm_get_device_id(mfile* mf, dm_dev_id_t* ptr_dev_type, u_int32_t* ptr_dev_id, u_int32_t* ptr_chip_rev); + + int dm_get_device_id_without_prints(mfile* mf, + dm_dev_id_t* ptr_dm_dev_id, + u_int32_t* ptr_hw_dev_id, + u_int32_t* ptr_hw_rev); + + /** + * Returns 0 on success and 1 on failure. + */ + int dm_get_device_id_offline(u_int32_t devid, u_int32_t chip_rev, dm_dev_id_t* ptr_dev_type); + + /** + * Returns 1 if device is supported and 0 otherwise (library dependant) + */ + int dm_is_device_supported(dm_dev_id_t type); + + /** + * Returns the device name as a "const char*" + */ + const char* dm_dev_type2str(dm_dev_id_t type); + + /** + * Returns the device id + */ + dm_dev_id_t dm_dev_str2type(const char* str); + + /** + * A predicate returning if the device is an hca + */ + int dm_dev_is_hca(dm_dev_id_t type); + + /** + * A predicate returning if the hca supports 200G speed and above + */ + int dm_dev_is_200g_speed_supported_hca(dm_dev_id_t type); + + /** + * A predicate returning if the device is a switch + */ + int dm_dev_is_switch(dm_dev_id_t type); + + /** + * A predicate returning if the switch supports 200G speed and above + */ + int dm_dev_is_200g_speed_supported_switch(dm_dev_id_t type); + + /** + * A predicate returning if the device is a bridge + */ + int dm_dev_is_bridge(dm_dev_id_t type); + + /** + * A predicate returning if the device is a Cable + */ + int dm_dev_is_cable(dm_dev_id_t type); + + /** + * Returns the max num of ports or -1 on error + */ + int dm_get_hw_ports_num(dm_dev_id_t type); + + /** + * Returns the HW device id of the givn device type or zero on failure. + */ + u_int32_t dm_get_hw_dev_id(dm_dev_id_t type); + + /** + * Returns the HW chip revision of the given device type or zero on failures, + * This is useful to distinguish between ConnectX2 and ConnectX. + */ + u_int32_t dm_get_hw_rev_id(dm_dev_id_t type); + + /** + * A predicate returning if the device supports Function Per Port + */ + int dm_is_fpp_supported(dm_dev_id_t type); + + int dm_is_4th_gen(dm_dev_id_t type); + + int dm_is_5th_gen_hca(dm_dev_id_t type); + + int dm_is_connectib(dm_dev_id_t type); + + int dm_is_switchx(dm_dev_id_t type); + + int dm_is_new_gen_switch(dm_dev_id_t type); + + int dm_dev_is_raven_family_switch(dm_dev_id_t type); + + int dm_dev_is_ib_switch(dm_dev_id_t type); + /* + * A predicate returning if the device is in LiveFish mode + */ + int dm_is_livefish_mode(mfile* mf); #ifdef __cplusplus -} /* end of 'extern "C"' */ +} /* end of 'extern "C"' */ #endif #endif // TOOLS_DEV_TYPE_H diff --git a/ext_libs/iniParser/dictionary.c b/ext_libs/iniParser/dictionary.c index 7985ab3f..5e998193 100644 --- a/ext_libs/iniParser/dictionary.c +++ b/ext_libs/iniParser/dictionary.c @@ -20,13 +20,13 @@ #include /** Maximum value size for integers and doubles. */ -#define MAXVALSZ 1024 +#define MAXVALSZ 1024 /** Minimal allocated number of entries in a dictionary */ -#define DICTMINSZ 128 +#define DICTMINSZ 128 /** Invalid key token */ -#define DICT_INVALID_KEY ((char*)-1) +#define DICT_INVALID_KEY ((char*)-1) /*--------------------------------------------------------------------------- Private functions @@ -42,19 +42,20 @@ for systems that do not have it. */ /*--------------------------------------------------------------------------*/ -static char * xstrdup(const char * s) +static char* xstrdup(const char* s) { - char * t ; - size_t len ; + char* t; + size_t len; if (!s) - return NULL ; + return NULL; - len = strlen(s) + 1 ; - t = (char*) malloc(len) ; - if (t) { - memcpy(t, s, len) ; + len = strlen(s) + 1; + t = (char*)malloc(len); + if (t) + { + memcpy(t, s, len); } - return t ; + return t; } /*-------------------------------------------------------------------------*/ @@ -64,16 +65,17 @@ static char * xstrdup(const char * s) @return This function returns non-zero in case of failure */ /*--------------------------------------------------------------------------*/ -static int dictionary_grow(dictionary * d) +static int dictionary_grow(dictionary* d) { - char ** new_val ; - char ** new_key ; - unsigned * new_hash ; - - new_val = (char**) calloc(d->size * 2, sizeof *d->val); - new_key = (char**) calloc(d->size * 2, sizeof *d->key); - new_hash = (unsigned*) calloc(d->size * 2, sizeof *d->hash); - if (!new_val || !new_key || !new_hash) { + char** new_val; + char** new_key; + unsigned* new_hash; + + new_val = (char**)calloc(d->size * 2, sizeof *d->val); + new_key = (char**)calloc(d->size * 2, sizeof *d->key); + new_hash = (unsigned*)calloc(d->size * 2, sizeof *d->hash); + if (!new_val || !new_key || !new_hash) + { /* An allocation failed, leave the dictionary unchanged */ if (new_val) free(new_val); @@ -81,22 +83,22 @@ static int dictionary_grow(dictionary * d) free(new_key); if (new_hash) free(new_hash); - return -1 ; + return -1; } /* Initialize the newly allocated space */ - memcpy(new_val, d->val, d->size * sizeof(char *)); - memcpy(new_key, d->key, d->size * sizeof(char *)); + memcpy(new_val, d->val, d->size * sizeof(char*)); + memcpy(new_key, d->key, d->size * sizeof(char*)); memcpy(new_hash, d->hash, d->size * sizeof(unsigned)); /* Delete previous data */ free(d->val); free(d->key); free(d->hash); /* Actually update the dictionary */ - d->size *= 2 ; + d->size *= 2; d->val = new_val; d->key = new_key; d->hash = new_hash; - return 0 ; + return 0; } /*--------------------------------------------------------------------------- @@ -114,25 +116,26 @@ static int dictionary_grow(dictionary * d) by comparing the key itself in last resort. */ /*--------------------------------------------------------------------------*/ -unsigned dictionary_hash(const char * key) +unsigned dictionary_hash(const char* key) { - size_t len ; - unsigned hash ; - size_t i ; + size_t len; + unsigned hash; + size_t i; if (!key) - return 0 ; + return 0; len = strlen(key); - for (hash=0, i=0 ; i>6) ; + for (hash = 0, i = 0; i < len; i++) + { + hash += (unsigned)key[i]; + hash += (hash << 10); + hash ^= (hash >> 6); } - hash += (hash <<3); - hash ^= (hash >>11); - hash += (hash <<15); - return hash ; + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + return hash; } /*-------------------------------------------------------------------------*/ @@ -146,22 +149,24 @@ unsigned dictionary_hash(const char * key) dictionary, give size=0. */ /*-------------------------------------------------------------------------*/ -dictionary * dictionary_new(size_t size) +dictionary* dictionary_new(size_t size) { - dictionary * d ; + dictionary* d; /* If no size was specified, allocate space for DICTMINSZ */ - if (sizesize = size ; - d->val = (char**) calloc(size, sizeof *d->val); - d->key = (char**) calloc(size, sizeof *d->key); - d->hash = (unsigned*) calloc(size, sizeof *d->hash); + if (d) + { + d->size = size; + d->val = (char**)calloc(size, sizeof *d->val); + d->key = (char**)calloc(size, sizeof *d->key); + d->hash = (unsigned*)calloc(size, sizeof *d->hash); } - return d ; + return d; } /*-------------------------------------------------------------------------*/ @@ -173,22 +178,24 @@ dictionary * dictionary_new(size_t size) Deallocate a dictionary object and all memory associated to it. */ /*--------------------------------------------------------------------------*/ -void dictionary_del(dictionary * d) +void dictionary_del(dictionary* d) { - ssize_t i ; + ssize_t i; - if (d==NULL) return ; - for (i=0 ; isize ; i++) { - if (d->key[i]!=NULL) + if (d == NULL) + return; + for (i = 0; i < d->size; i++) + { + if (d->key[i] != NULL) free(d->key[i]); - if (d->val[i]!=NULL) + if (d->val[i] != NULL) free(d->val[i]); } free(d->val); free(d->key); free(d->hash); free(d); - return ; + return; } /*-------------------------------------------------------------------------*/ @@ -205,24 +212,27 @@ void dictionary_del(dictionary * d) dictionary object, you should not try to free it or modify it. */ /*--------------------------------------------------------------------------*/ -const char * dictionary_get(const dictionary * d, const char * key, const char * def) +const char* dictionary_get(const dictionary* d, const char* key, const char* def) { - unsigned hash ; - ssize_t i ; + unsigned hash; + ssize_t i; hash = dictionary_hash(key); - for (i=0 ; isize ; i++) { - if (d->key[i]==NULL) - continue ; + for (i = 0; i < d->size; i++) + { + if (d->key[i] == NULL) + continue; /* Compare hash */ - if (hash==d->hash[i]) { + if (hash == d->hash[i]) + { /* Compare string, to avoid hash collisions */ - if (!strcmp(key, d->key[i])) { - return d->val[i] ; + if (!strcmp(key, d->key[i])) + { + return d->val[i]; } } } - return def ; + return def; } /*-------------------------------------------------------------------------*/ @@ -251,35 +261,41 @@ const char * dictionary_get(const dictionary * d, const char * key, const char * This function returns non-zero in case of failure. */ /*--------------------------------------------------------------------------*/ -int dictionary_set(dictionary * d, const char * key, const char * val) +int dictionary_set(dictionary* d, const char* key, const char* val) { - ssize_t i ; - unsigned hash ; + ssize_t i; + unsigned hash; - if (d==NULL || key==NULL) return -1 ; + if (d == NULL || key == NULL) + return -1; /* Compute hash for this key */ - hash = dictionary_hash(key) ; + hash = dictionary_hash(key); /* Find if value is already in dictionary */ - if (d->n>0) { - for (i=0 ; isize ; i++) { - if (d->key[i]==NULL) - continue ; - if (hash==d->hash[i]) { /* Same hash value */ - if (!strcmp(key, d->key[i])) { /* Same key */ + if (d->n > 0) + { + for (i = 0; i < d->size; i++) + { + if (d->key[i] == NULL) + continue; + if (hash == d->hash[i]) + { /* Same hash value */ + if (!strcmp(key, d->key[i])) + { /* Same key */ /* Found a value: modify and return */ - if (d->val[i]!=NULL) + if (d->val[i] != NULL) free(d->val[i]); d->val[i] = (val ? xstrdup(val) : NULL); /* Value has been modified: return */ - return 0 ; + return 0; } } } } /* Add a new value */ /* See if dictionary needs to grow */ - if (d->n==d->size) { + if (d->n == d->size) + { /* Reached maximum size: reallocate dictionary */ if (dictionary_grow(d) != 0) return -1; @@ -288,15 +304,17 @@ int dictionary_set(dictionary * d, const char * key, const char * val) /* Insert key in the first empty slot. Start at d->n and wrap at d->size. Because d->n < d->size this will necessarily terminate. */ - for (i=d->n ; d->key[i] ; ) { - if(++i == d->size) i = 0; + for (i = d->n; d->key[i];) + { + if (++i == d->size) + i = 0; } /* Copy key */ - d->key[i] = xstrdup(key); - d->val[i] = (val ? xstrdup(val) : NULL) ; + d->key[i] = xstrdup(key); + d->val[i] = (val ? xstrdup(val) : NULL); d->hash[i] = hash; - d->n ++ ; - return 0 ; + d->n++; + return 0; } /*-------------------------------------------------------------------------*/ @@ -310,41 +328,46 @@ int dictionary_set(dictionary * d, const char * key, const char * val) key cannot be found. */ /*--------------------------------------------------------------------------*/ -void dictionary_unset(dictionary * d, const char * key) +void dictionary_unset(dictionary* d, const char* key) { - unsigned hash ; - ssize_t i ; + unsigned hash; + ssize_t i; - if (key == NULL || d == NULL) { + if (key == NULL || d == NULL) + { return; } hash = dictionary_hash(key); - for (i=0 ; isize ; i++) { - if (d->key[i]==NULL) - continue ; + for (i = 0; i < d->size; i++) + { + if (d->key[i] == NULL) + continue; /* Compare hash */ - if (hash==d->hash[i]) { + if (hash == d->hash[i]) + { /* Compare string, to avoid hash collisions */ - if (!strcmp(key, d->key[i])) { + if (!strcmp(key, d->key[i])) + { /* Found key */ - break ; + break; } } } - if (i>=d->size) + if (i >= d->size) /* Key not found */ - return ; + return; free(d->key[i]); - d->key[i] = NULL ; - if (d->val[i]!=NULL) { + d->key[i] = NULL; + if (d->val[i] != NULL) + { free(d->val[i]); - d->val[i] = NULL ; + d->val[i] = NULL; } - d->hash[i] = 0 ; - d->n -- ; - return ; + d->hash[i] = 0; + d->n--; + return; } /*-------------------------------------------------------------------------*/ @@ -359,21 +382,23 @@ void dictionary_unset(dictionary * d, const char * key) output file pointers. */ /*--------------------------------------------------------------------------*/ -void dictionary_dump(const dictionary * d, FILE * out) +void dictionary_dump(const dictionary* d, FILE* out) { - ssize_t i ; + ssize_t i; - if (d==NULL || out==NULL) return ; - if (d->n<1) { + if (d == NULL || out == NULL) + return; + if (d->n < 1) + { fprintf(out, "empty dictionary\n"); - return ; + return; } - for (i=0 ; isize ; i++) { - if (d->key[i]) { - fprintf(out, "%20s\t[%s]\n", - d->key[i], - d->val[i] ? d->val[i] : "UNDEF"); + for (i = 0; i < d->size; i++) + { + if (d->key[i]) + { + fprintf(out, "%20s\t[%s]\n", d->key[i], d->val[i] ? d->val[i] : "UNDEF"); } } - return ; + return; } diff --git a/ext_libs/iniParser/dictionary.h b/ext_libs/iniParser/dictionary.h index f7ef8e46..772b5156 100644 --- a/ext_libs/iniParser/dictionary.h +++ b/ext_libs/iniParser/dictionary.h @@ -27,147 +27,145 @@ #include #endif #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/*--------------------------------------------------------------------------- - New types - ---------------------------------------------------------------------------*/ - - -/*-------------------------------------------------------------------------*/ -/** - @brief Dictionary object - - This object contains a list of string/string associations. Each - association is identified by a unique string key. Looking up values - in the dictionary is speeded up by the use of a (hopefully collision-free) - hash function. - */ -/*-------------------------------------------------------------------------*/ -typedef struct _dictionary_ { - int n ; /** Number of entries in dictionary */ - ssize_t size ; /** Storage size */ - char ** val ; /** List of string values */ - char ** key ; /** List of string keys */ - unsigned * hash ; /** List of hash values for keys */ -} dictionary ; - - -/*--------------------------------------------------------------------------- - Function prototypes - ---------------------------------------------------------------------------*/ - -/*-------------------------------------------------------------------------*/ -/** - @brief Compute the hash key for a string. - @param key Character string to use for key. - @return 1 unsigned int on at least 32 bits. - - This hash function has been taken from an Article in Dr Dobbs Journal. - This is normally a collision-free function, distributing keys evenly. - The key is stored anyway in the struct so that collision can be avoided - by comparing the key itself in last resort. - */ -/*--------------------------------------------------------------------------*/ -unsigned dictionary_hash(const char * key); - -/*-------------------------------------------------------------------------*/ -/** - @brief Create a new dictionary object. - @param size Optional initial size of the dictionary. - @return 1 newly allocated dictionary objet. - - This function allocates a new dictionary object of given size and returns - it. If you do not know in advance (roughly) the number of entries in the - dictionary, give size=0. - */ -/*--------------------------------------------------------------------------*/ -dictionary * dictionary_new(size_t size); - -/*-------------------------------------------------------------------------*/ -/** - @brief Delete a dictionary object - @param d dictionary object to deallocate. - @return void - - Deallocate a dictionary object and all memory associated to it. - */ -/*--------------------------------------------------------------------------*/ -void dictionary_del(dictionary * vd); - -/*-------------------------------------------------------------------------*/ -/** - @brief Get a value from a dictionary. - @param d dictionary object to search. - @param key Key to look for in the dictionary. - @param def Default value to return if key not found. - @return 1 pointer to internally allocated character string. - - This function locates a key in a dictionary and returns a pointer to its - value, or the passed 'def' pointer if no such key can be found in - dictionary. The returned character pointer points to data internal to the - dictionary object, you should not try to free it or modify it. - */ -/*--------------------------------------------------------------------------*/ -const char * dictionary_get(const dictionary * d, const char * key, const char * def); - - -/*-------------------------------------------------------------------------*/ -/** - @brief Set a value in a dictionary. - @param d dictionary object to modify. - @param key Key to modify or add. - @param val Value to add. - @return int 0 if Ok, anything else otherwise - - If the given key is found in the dictionary, the associated value is - replaced by the provided one. If the key cannot be found in the - dictionary, it is added to it. - - It is Ok to provide a NULL value for val, but NULL values for the dictionary - or the key are considered as errors: the function will return immediately - in such a case. - - Notice that if you dictionary_set a variable to NULL, a call to - dictionary_get will return a NULL value: the variable will be found, and - its value (NULL) is returned. In other words, setting the variable - content to NULL is equivalent to deleting the variable from the - dictionary. It is not possible (in this implementation) to have a key in - the dictionary without value. - - This function returns non-zero in case of failure. - */ -/*--------------------------------------------------------------------------*/ -int dictionary_set(dictionary * vd, const char * key, const char * val); - -/*-------------------------------------------------------------------------*/ -/** - @brief Delete a key in a dictionary - @param d dictionary object to modify. - @param key Key to remove. - @return void - - This function deletes a key in a dictionary. Nothing is done if the - key cannot be found. - */ -/*--------------------------------------------------------------------------*/ -void dictionary_unset(dictionary * d, const char * key); - - -/*-------------------------------------------------------------------------*/ -/** - @brief Dump a dictionary to an opened file pointer. - @param d Dictionary to dump - @param f Opened file pointer. - @return void - - Dumps a dictionary onto an opened file pointer. Key pairs are printed out - as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as - output file pointers. - */ -/*--------------------------------------------------------------------------*/ -void dictionary_dump(const dictionary * d, FILE * out); + /*--------------------------------------------------------------------------- + New types + ---------------------------------------------------------------------------*/ + + /*-------------------------------------------------------------------------*/ + /** + @brief Dictionary object + + This object contains a list of string/string associations. Each + association is identified by a unique string key. Looking up values + in the dictionary is speeded up by the use of a (hopefully collision-free) + hash function. + */ + /*-------------------------------------------------------------------------*/ + typedef struct _dictionary_ + { + int n; /** Number of entries in dictionary */ + ssize_t size; /** Storage size */ + char** val; /** List of string values */ + char** key; /** List of string keys */ + unsigned* hash; /** List of hash values for keys */ + } dictionary; + + /*--------------------------------------------------------------------------- + Function prototypes + ---------------------------------------------------------------------------*/ + + /*-------------------------------------------------------------------------*/ + /** + @brief Compute the hash key for a string. + @param key Character string to use for key. + @return 1 unsigned int on at least 32 bits. + + This hash function has been taken from an Article in Dr Dobbs Journal. + This is normally a collision-free function, distributing keys evenly. + The key is stored anyway in the struct so that collision can be avoided + by comparing the key itself in last resort. + */ + /*--------------------------------------------------------------------------*/ + unsigned dictionary_hash(const char* key); + + /*-------------------------------------------------------------------------*/ + /** + @brief Create a new dictionary object. + @param size Optional initial size of the dictionary. + @return 1 newly allocated dictionary objet. + + This function allocates a new dictionary object of given size and returns + it. If you do not know in advance (roughly) the number of entries in the + dictionary, give size=0. + */ + /*--------------------------------------------------------------------------*/ + dictionary* dictionary_new(size_t size); + + /*-------------------------------------------------------------------------*/ + /** + @brief Delete a dictionary object + @param d dictionary object to deallocate. + @return void + + Deallocate a dictionary object and all memory associated to it. + */ + /*--------------------------------------------------------------------------*/ + void dictionary_del(dictionary* vd); + + /*-------------------------------------------------------------------------*/ + /** + @brief Get a value from a dictionary. + @param d dictionary object to search. + @param key Key to look for in the dictionary. + @param def Default value to return if key not found. + @return 1 pointer to internally allocated character string. + + This function locates a key in a dictionary and returns a pointer to its + value, or the passed 'def' pointer if no such key can be found in + dictionary. The returned character pointer points to data internal to the + dictionary object, you should not try to free it or modify it. + */ + /*--------------------------------------------------------------------------*/ + const char* dictionary_get(const dictionary* d, const char* key, const char* def); + + /*-------------------------------------------------------------------------*/ + /** + @brief Set a value in a dictionary. + @param d dictionary object to modify. + @param key Key to modify or add. + @param val Value to add. + @return int 0 if Ok, anything else otherwise + + If the given key is found in the dictionary, the associated value is + replaced by the provided one. If the key cannot be found in the + dictionary, it is added to it. + + It is Ok to provide a NULL value for val, but NULL values for the dictionary + or the key are considered as errors: the function will return immediately + in such a case. + + Notice that if you dictionary_set a variable to NULL, a call to + dictionary_get will return a NULL value: the variable will be found, and + its value (NULL) is returned. In other words, setting the variable + content to NULL is equivalent to deleting the variable from the + dictionary. It is not possible (in this implementation) to have a key in + the dictionary without value. + + This function returns non-zero in case of failure. + */ + /*--------------------------------------------------------------------------*/ + int dictionary_set(dictionary* vd, const char* key, const char* val); + + /*-------------------------------------------------------------------------*/ + /** + @brief Delete a key in a dictionary + @param d dictionary object to modify. + @param key Key to remove. + @return void + + This function deletes a key in a dictionary. Nothing is done if the + key cannot be found. + */ + /*--------------------------------------------------------------------------*/ + void dictionary_unset(dictionary* d, const char* key); + + /*-------------------------------------------------------------------------*/ + /** + @brief Dump a dictionary to an opened file pointer. + @param d Dictionary to dump + @param f Opened file pointer. + @return void + + Dumps a dictionary onto an opened file pointer. Key pairs are printed out + as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as + output file pointers. + */ + /*--------------------------------------------------------------------------*/ + void dictionary_dump(const dictionary* d, FILE* out); #ifdef __cplusplus } diff --git a/ext_libs/iniParser/iniparser.c b/ext_libs/iniParser/iniparser.c index f1d16589..f91962b9 100644 --- a/ext_libs/iniParser/iniparser.c +++ b/ext_libs/iniParser/iniparser.c @@ -12,8 +12,8 @@ #include "iniparser.h" /*---------------------------- Defines -------------------------------------*/ -#define ASCIILINESZ (1024) -#define INI_INVALID_KEY ((char*)-1) +#define ASCIILINESZ (1024) +#define INI_INVALID_KEY ((char*)-1) /*--------------------------------------------------------------------------- Private to this module @@ -21,14 +21,15 @@ /** * This enum stores the status for each parsed line (internal use only). */ -typedef enum _line_status_ { +typedef enum _line_status_ +{ LINE_UNPROCESSED, LINE_ERROR, LINE_EMPTY, LINE_COMMENT, LINE_SECTION, LINE_VALUE -} line_status ; +} line_status; /*-------------------------------------------------------------------------*/ /** @@ -42,18 +43,20 @@ typedef enum _line_status_ { At most len - 1 elements of the input string will be converted. */ /*--------------------------------------------------------------------------*/ -static const char * strlwc(const char * in, char *out, unsigned len) +static const char* strlwc(const char* in, char* out, unsigned len) { - unsigned i ; + unsigned i; - if (in==NULL || out == NULL || len==0) return NULL ; - i=0 ; - while (in[i] != '\0' && i < len-1) { + if (in == NULL || out == NULL || len == 0) + return NULL; + i = 0; + while (in[i] != '\0' && i < len - 1) + { out[i] = (char)tolower((int)in[i]); - i++ ; + i++; } out[i] = '\0'; - return out ; + return out; } /*-------------------------------------------------------------------------*/ @@ -66,19 +69,20 @@ static const char * strlwc(const char * in, char *out, unsigned len) for systems that do not have it. */ /*--------------------------------------------------------------------------*/ -static char * xstrdup(const char * s) +static char* xstrdup(const char* s) { - char * t ; - size_t len ; + char* t; + size_t len; if (!s) - return NULL ; + return NULL; - len = strlen(s) + 1 ; - t = (char*) malloc(len) ; - if (t) { - memcpy(t, s, len) ; + len = strlen(s) + 1; + t = (char*)malloc(len); + if (t) + { + memcpy(t, s, len); } - return t ; + return t; } /*-------------------------------------------------------------------------*/ @@ -88,23 +92,26 @@ static char * xstrdup(const char * s) @return unsigned New size of the string. */ /*--------------------------------------------------------------------------*/ -static unsigned strstrip(char * s) +static unsigned strstrip(char* s) { - char *last = NULL ; - char *dest = s; + char* last = NULL; + char* dest = s; - if (s==NULL) return 0; + if (s == NULL) + return 0; last = s + strlen(s); - while (isspace((int)*s) && *s) s++; - while (last > s) { - if (!isspace((int)*(last-1))) - break ; - last -- ; + while (isspace((int)*s) && *s) + s++; + while (last > s) + { + if (!isspace((int)*(last - 1))) + break; + last--; } *last = (char)0; - memmove(dest,s,last - s + 1); + memmove(dest, s, last - s + 1); return last - s; } @@ -113,14 +120,14 @@ static unsigned strstrip(char * s) @brief Default error callback for iniparser: wraps `fprintf(stderr, ...)`. */ /*--------------------------------------------------------------------------*/ -static int default_error_callback(const char *format, ...) +static int default_error_callback(const char* format, ...) { - int ret; - va_list argptr; - va_start(argptr, format); - ret = vfprintf(stderr, format, argptr); - va_end(argptr); - return ret; + int ret; + va_list argptr; + va_start(argptr, format); + ret = vfprintf(stderr, format, argptr); + va_end(argptr); + return ret; } static int (*iniparser_error_callback)(const char*, ...) = default_error_callback; @@ -134,13 +141,16 @@ static int (*iniparser_error_callback)(const char*, ...) = default_error_callbac as errback the error callback will be switched back to default. */ /*--------------------------------------------------------------------------*/ -void iniparser_set_error_callback(int (*errback)(const char *, ...)) +void iniparser_set_error_callback(int (*errback)(const char*, ...)) { - if (errback) { - iniparser_error_callback = errback; - } else { - iniparser_error_callback = default_error_callback; - } + if (errback) + { + iniparser_error_callback = errback; + } + else + { + iniparser_error_callback = default_error_callback; + } } /*-------------------------------------------------------------------------*/ @@ -161,21 +171,24 @@ void iniparser_set_error_callback(int (*errback)(const char *, ...)) This function returns -1 in case of error. */ /*--------------------------------------------------------------------------*/ -int iniparser_getnsec(const dictionary * d) +int iniparser_getnsec(const dictionary* d) { - int i ; - int nsec ; - - if (d==NULL) return -1 ; - nsec=0 ; - for (i=0 ; isize ; i++) { - if (d->key[i]==NULL) - continue ; - if (strchr(d->key[i], ':')==NULL) { - nsec ++ ; + int i; + int nsec; + + if (d == NULL) + return -1; + nsec = 0; + for (i = 0; i < d->size; i++) + { + if (d->key[i] == NULL) + continue; + if (strchr(d->key[i], ':') == NULL) + { + nsec++; } } - return nsec ; + return nsec; } /*-------------------------------------------------------------------------*/ @@ -192,26 +205,30 @@ int iniparser_getnsec(const dictionary * d) This function returns NULL in case of error. */ /*--------------------------------------------------------------------------*/ -const char * iniparser_getsecname(const dictionary * d, int n) +const char* iniparser_getsecname(const dictionary* d, int n) { - int i ; - int foundsec ; - - if (d==NULL || n<0) return NULL ; - foundsec=0 ; - for (i=0 ; isize ; i++) { - if (d->key[i]==NULL) - continue ; - if (strchr(d->key[i], ':')==NULL) { - foundsec++ ; - if (foundsec>n) - break ; + int i; + int foundsec; + + if (d == NULL || n < 0) + return NULL; + foundsec = 0; + for (i = 0; i < d->size; i++) + { + if (d->key[i] == NULL) + continue; + if (strchr(d->key[i], ':') == NULL) + { + foundsec++; + if (foundsec > n) + break; } } - if (foundsec<=n) { - return NULL ; + if (foundsec <= n) + { + return NULL; } - return d->key[i] ; + return d->key[i]; } /*-------------------------------------------------------------------------*/ @@ -227,21 +244,26 @@ const char * iniparser_getsecname(const dictionary * d, int n) purposes mostly. */ /*--------------------------------------------------------------------------*/ -void iniparser_dump(const dictionary * d, FILE * f) +void iniparser_dump(const dictionary* d, FILE* f) { - int i ; + int i; - if (d==NULL || f==NULL) return ; - for (i=0 ; isize ; i++) { - if (d->key[i]==NULL) - continue ; - if (d->val[i]!=NULL) { + if (d == NULL || f == NULL) + return; + for (i = 0; i < d->size; i++) + { + if (d->key[i] == NULL) + continue; + if (d->val[i] != NULL) + { fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]); - } else { + } + else + { fprintf(f, "[%s]=UNDEF\n", d->key[i]); } } - return ; + return; } /*-------------------------------------------------------------------------*/ @@ -255,30 +277,34 @@ void iniparser_dump(const dictionary * d, FILE * f) It is Ok to specify @c stderr or @c stdout as output files. */ /*--------------------------------------------------------------------------*/ -void iniparser_dump_ini(const dictionary * d, FILE * f) +void iniparser_dump_ini(const dictionary* d, FILE* f) { - int i ; - int nsec ; - const char * secname ; + int i; + int nsec; + const char* secname; - if (d==NULL || f==NULL) return ; + if (d == NULL || f == NULL) + return; nsec = iniparser_getnsec(d); - if (nsec<1) { + if (nsec < 1) + { /* No section in file: dump all keys as they are */ - for (i=0 ; isize ; i++) { - if (d->key[i]==NULL) - continue ; + for (i = 0; i < d->size; i++) + { + if (d->key[i] == NULL) + continue; fprintf(f, "%s = %s\n", d->key[i], d->val[i]); } - return ; + return; } - for (i=0 ; isize ; j++) { - if (d->key[j]==NULL) - continue ; - if (!strncmp(d->key[j], keym, seclen+1)) { - fprintf(f, - "%-30s = %s\n", - d->key[j]+seclen+1, - d->val[j] ? d->val[j] : ""); + for (j = 0; j < d->size; j++) + { + if (d->key[j] == NULL) + continue; + if (!strncmp(d->key[j], keym, seclen + 1)) + { + fprintf(f, "%-30s = %s\n", d->key[j] + seclen + 1, d->val[j] ? d->val[j] : ""); } } fprintf(f, "\n"); - return ; + return; } /*-------------------------------------------------------------------------*/ @@ -327,30 +354,32 @@ void iniparser_dumpsection_ini(const dictionary * d, const char * s, FILE * f) @return Number of keys in section */ /*--------------------------------------------------------------------------*/ -int iniparser_getsecnkeys(const dictionary * d, const char * s) +int iniparser_getsecnkeys(const dictionary* d, const char* s) { - int seclen, nkeys ; - char keym[ASCIILINESZ+1]; - int j ; + int seclen, nkeys; + char keym[ASCIILINESZ + 1]; + int j; nkeys = 0; - if (d==NULL) return nkeys; - if (! iniparser_find_entry(d, s)) return nkeys; + if (d == NULL) + return nkeys; + if (!iniparser_find_entry(d, s)) + return nkeys; - seclen = (int)strlen(s); + seclen = (int)strlen(s); strlwc(s, keym, sizeof(keym)); keym[seclen] = ':'; - for (j=0 ; jsize ; j++) { - if (d->key[j]==NULL) - continue ; - if (!strncmp(d->key[j], keym, seclen+1)) + for (j = 0; j < d->size; j++) + { + if (d->key[j] == NULL) + continue; + if (!strncmp(d->key[j], keym, seclen + 1)) nkeys++; } return nkeys; - } /*-------------------------------------------------------------------------*/ @@ -369,24 +398,28 @@ int iniparser_getsecnkeys(const dictionary * d, const char * s) a string allocated in the dictionary; do not free or modify them. */ /*--------------------------------------------------------------------------*/ -const char ** iniparser_getseckeys(const dictionary * d, const char * s, const char ** keys) +const char** iniparser_getseckeys(const dictionary* d, const char* s, const char** keys) { - int i, j, seclen ; - char keym[ASCIILINESZ+1]; + int i, j, seclen; + char keym[ASCIILINESZ + 1]; - if (d==NULL || keys==NULL) return NULL; - if (! iniparser_find_entry(d, s)) return NULL; + if (d == NULL || keys == NULL) + return NULL; + if (!iniparser_find_entry(d, s)) + return NULL; - seclen = (int)strlen(s); + seclen = (int)strlen(s); strlwc(s, keym, sizeof(keym)); keym[seclen] = ':'; i = 0; - for (j=0 ; jsize ; j++) { - if (d->key[j]==NULL) - continue ; - if (!strncmp(d->key[j], keym, seclen+1)) { + for (j = 0; j < d->size; j++) + { + if (d->key[j] == NULL) + continue; + if (!strncmp(d->key[j], keym, seclen + 1)) + { keys[i] = d->key[j]; i++; } @@ -410,18 +443,18 @@ const char ** iniparser_getseckeys(const dictionary * d, const char * s, const c the dictionary, do not free or modify it. */ /*--------------------------------------------------------------------------*/ -const char * iniparser_getstring(const dictionary * d, const char * key, const char * def) +const char* iniparser_getstring(const dictionary* d, const char* key, const char* def) { - const char * lc_key ; - const char * sval ; - char tmp_str[ASCIILINESZ+1]; + const char* lc_key; + const char* sval; + char tmp_str[ASCIILINESZ + 1]; - if (d==NULL || key==NULL) - return def ; + if (d == NULL || key == NULL) + return def; lc_key = strlwc(key, tmp_str, sizeof(tmp_str)); sval = dictionary_get(d, lc_key, def); - return sval ; + return sval; } /*-------------------------------------------------------------------------*/ @@ -451,16 +484,16 @@ const char * iniparser_getstring(const dictionary * d, const char * key, const c Credits: Thanks to A. Becker for suggesting strtol() */ /*--------------------------------------------------------------------------*/ -long int iniparser_getlongint(const dictionary * d, const char * key, long int notfound) +long int iniparser_getlongint(const dictionary* d, const char* key, long int notfound) { - const char * str ; + const char* str; str = iniparser_getstring(d, key, INI_INVALID_KEY); - if (str==INI_INVALID_KEY) return notfound ; + if (str == INI_INVALID_KEY) + return notfound; return strtol(str, NULL, 0); } - /*-------------------------------------------------------------------------*/ /** @brief Get the string associated to a key, convert to an int @@ -488,7 +521,7 @@ long int iniparser_getlongint(const dictionary * d, const char * key, long int n Credits: Thanks to A. Becker for suggesting strtol() */ /*--------------------------------------------------------------------------*/ -int iniparser_getint(const dictionary * d, const char * key, int notfound) +int iniparser_getint(const dictionary* d, const char* key, int notfound) { return (int)iniparser_getlongint(d, key, notfound); } @@ -506,12 +539,13 @@ int iniparser_getint(const dictionary * d, const char * key, int notfound) the notfound value is returned. */ /*--------------------------------------------------------------------------*/ -double iniparser_getdouble(const dictionary * d, const char * key, double notfound) +double iniparser_getdouble(const dictionary* d, const char* key, double notfound) { - const char * str ; + const char* str; str = iniparser_getstring(d, key, INI_INVALID_KEY); - if (str==INI_INVALID_KEY) return notfound ; + if (str == INI_INVALID_KEY) + return notfound; return atof(str); } @@ -547,19 +581,25 @@ double iniparser_getdouble(const dictionary * d, const char * key, double notfou necessarily have to be 0 or 1. */ /*--------------------------------------------------------------------------*/ -int iniparser_getboolean(const dictionary * d, const char * key, int notfound) +int iniparser_getboolean(const dictionary* d, const char* key, int notfound) { - int ret ; - const char * c ; + int ret; + const char* c; c = iniparser_getstring(d, key, INI_INVALID_KEY); - if (c==INI_INVALID_KEY) return notfound ; - if (c[0]=='y' || c[0]=='Y' || c[0]=='1' || c[0]=='t' || c[0]=='T') { - ret = 1 ; - } else if (c[0]=='n' || c[0]=='N' || c[0]=='0' || c[0]=='f' || c[0]=='F') { - ret = 0 ; - } else { - ret = notfound ; + if (c == INI_INVALID_KEY) + return notfound; + if (c[0] == 'y' || c[0] == 'Y' || c[0] == '1' || c[0] == 't' || c[0] == 'T') + { + ret = 1; + } + else if (c[0] == 'n' || c[0] == 'N' || c[0] == '0' || c[0] == 'f' || c[0] == 'F') + { + ret = 0; + } + else + { + ret = notfound; } return ret; } @@ -576,13 +616,14 @@ int iniparser_getboolean(const dictionary * d, const char * key, int notfound) of querying for the presence of sections in a dictionary. */ /*--------------------------------------------------------------------------*/ -int iniparser_find_entry(const dictionary * ini, const char * entry) +int iniparser_find_entry(const dictionary* ini, const char* entry) { - int found=0 ; - if (iniparser_getstring(ini, entry, INI_INVALID_KEY)!=INI_INVALID_KEY) { - found = 1 ; + int found = 0; + if (iniparser_getstring(ini, entry, INI_INVALID_KEY) != INI_INVALID_KEY) + { + found = 1; } - return found ; + return found; } /*-------------------------------------------------------------------------*/ @@ -598,10 +639,10 @@ int iniparser_find_entry(const dictionary * ini, const char * entry) It is Ok to set val to NULL. */ /*--------------------------------------------------------------------------*/ -int iniparser_set(dictionary * ini, const char * entry, const char * val) +int iniparser_set(dictionary* ini, const char* entry, const char* val) { - char tmp_str[ASCIILINESZ+1]; - return dictionary_set(ini, strlwc(entry, tmp_str, sizeof(tmp_str)), val) ; + char tmp_str[ASCIILINESZ + 1]; + return dictionary_set(ini, strlwc(entry, tmp_str, sizeof(tmp_str)), val); } /*-------------------------------------------------------------------------*/ @@ -614,9 +655,9 @@ int iniparser_set(dictionary * ini, const char * entry, const char * val) If the given entry can be found, it is deleted from the dictionary. */ /*--------------------------------------------------------------------------*/ -void iniparser_unset(dictionary * ini, const char * entry) +void iniparser_unset(dictionary* ini, const char* entry) { - char tmp_str[ASCIILINESZ+1]; + char tmp_str[ASCIILINESZ + 1]; dictionary_unset(ini, strlwc(entry, tmp_str, sizeof(tmp_str))); } @@ -630,40 +671,44 @@ void iniparser_unset(dictionary * ini, const char * entry) @return line_status value */ /*--------------------------------------------------------------------------*/ -static line_status iniparser_line( - const char * input_line, - char * section, - char * key, - char * value) +static line_status iniparser_line(const char* input_line, char* section, char* key, char* value) { - line_status sta ; - char * line = NULL; - size_t len ; + line_status sta; + char* line = NULL; + size_t len; line = xstrdup(input_line); len = strstrip(line); - sta = LINE_UNPROCESSED ; - if (len<1) { + sta = LINE_UNPROCESSED; + if (len < 1) + { /* Empty line */ - sta = LINE_EMPTY ; - } else if (line[0]=='#' || line[0]==';') { + sta = LINE_EMPTY; + } + else if (line[0] == '#' || line[0] == ';') + { /* Comment line */ - sta = LINE_COMMENT ; - } else if (line[0]=='[' && line[len-1]==']') { + sta = LINE_COMMENT; + } + else if (line[0] == '[' && line[len - 1] == ']') + { /* Section name */ sscanf(line, "[%[^]]", section); strstrip(section); strlwc(section, section, len); - sta = LINE_SECTION ; - } else if (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2 - || sscanf (line, "%[^=] = '%[^\']'", key, value) == 2) { + sta = LINE_SECTION; + } + else if (sscanf(line, "%[^=] = \"%[^\"]\"", key, value) == 2 || sscanf(line, "%[^=] = '%[^\']'", key, value) == 2) + { /* Usual key=value with quotes, with or without comments */ strstrip(key); strlwc(key, key, len); /* Don't strip spaces from values surrounded with quotes */ - sta = LINE_VALUE ; - } else if (sscanf (line, "%[^=] = %[^;#]", key, value) == 2) { + sta = LINE_VALUE; + } + else if (sscanf(line, "%[^=] = %[^;#]", key, value) == 2) + { /* Usual key=value without quotes, with or without comments */ strstrip(key); strlwc(key, key, len); @@ -672,12 +717,14 @@ static line_status iniparser_line( * sscanf cannot handle '' or "" as empty values * this is done here */ - if (!strcmp(value, "\"\"") || (!strcmp(value, "''"))) { - value[0]=0 ; + if (!strcmp(value, "\"\"") || (!strcmp(value, "''"))) + { + value[0] = 0; } - sta = LINE_VALUE ; - } else if (sscanf(line, "%[^=] = %[;#]", key, value)==2 - || sscanf(line, "%[^=] %[=]", key, value) == 2) { + sta = LINE_VALUE; + } + else if (sscanf(line, "%[^=] = %[;#]", key, value) == 2 || sscanf(line, "%[^=] %[=]", key, value) == 2) + { /* * Special cases: * key= @@ -686,15 +733,17 @@ static line_status iniparser_line( */ strstrip(key); strlwc(key, key, len); - value[0]=0 ; - sta = LINE_VALUE ; - } else { + value[0] = 0; + sta = LINE_VALUE; + } + else + { /* Generate syntax error */ - sta = LINE_ERROR ; + sta = LINE_ERROR; } free(line); - return sta ; + return sta; } /*-------------------------------------------------------------------------*/ @@ -711,112 +760,116 @@ static line_status iniparser_line( The returned dictionary must be freed using iniparser_freedict(). */ /*--------------------------------------------------------------------------*/ -dictionary * iniparser_load(const char * ininame) +dictionary* iniparser_load(const char* ininame) { - FILE * in ; + FILE* in; - char line [ASCIILINESZ+1] ; - char section [ASCIILINESZ+1] ; - char key [ASCIILINESZ+1] ; - char tmp [(ASCIILINESZ * 2) + 2] ; - char val [ASCIILINESZ+1] ; + char line[ASCIILINESZ + 1]; + char section[ASCIILINESZ + 1]; + char key[ASCIILINESZ + 1]; + char tmp[(ASCIILINESZ * 2) + 2]; + char val[ASCIILINESZ + 1]; - int last=0 ; - int len ; - int lineno=0 ; - int errs=0; - int mem_err=0; + int last = 0; + int len; + int lineno = 0; + int errs = 0; + int mem_err = 0; - dictionary * dict ; + dictionary* dict; - if ((in=fopen(ininame, "r"))==NULL) { + if ((in = fopen(ininame, "r")) == NULL) + { iniparser_error_callback("iniparser: cannot open %s\n", ininame); - return NULL ; + return NULL; } - dict = dictionary_new(0) ; - if (!dict) { + dict = dictionary_new(0); + if (!dict) + { fclose(in); - return NULL ; + return NULL; } - memset(line, 0, ASCIILINESZ); + memset(line, 0, ASCIILINESZ); memset(section, 0, ASCIILINESZ); - memset(key, 0, ASCIILINESZ); - memset(val, 0, ASCIILINESZ); - last=0 ; - - while (fgets(line+last, ASCIILINESZ-last, in)!=NULL) { - lineno++ ; - len = (int)strlen(line)-1; - if (len<=0) + memset(key, 0, ASCIILINESZ); + memset(val, 0, ASCIILINESZ); + last = 0; + + while (fgets(line + last, ASCIILINESZ - last, in) != NULL) + { + lineno++; + len = (int)strlen(line) - 1; + if (len <= 0) continue; /* Safety check against buffer overflows */ - if (line[len]!='\n' && !feof(in)) { - iniparser_error_callback( - "iniparser: input line too long in %s (%d)\n", - ininame, - lineno); + if (line[len] != '\n' && !feof(in)) + { + iniparser_error_callback("iniparser: input line too long in %s (%d)\n", ininame, lineno); dictionary_del(dict); fclose(in); - return NULL ; + return NULL; } /* Get rid of \n and spaces at end of line */ - while ((len>=0) && - ((line[len]=='\n') || (isspace(line[len])))) { - line[len]=0 ; - len-- ; + while ((len >= 0) && ((line[len] == '\n') || (isspace(line[len])))) + { + line[len] = 0; + len--; } - if (len < 0) { /* Line was entirely \n and/or spaces */ + if (len < 0) + { /* Line was entirely \n and/or spaces */ len = 0; } /* Detect multi-line */ - if (line[len]=='\\') { + if (line[len] == '\\') + { /* Multi-line value */ - last=len ; - continue ; - } else { - last=0 ; + last = len; + continue; } - switch (iniparser_line(line, section, key, val)) { + else + { + last = 0; + } + switch (iniparser_line(line, section, key, val)) + { case LINE_EMPTY: case LINE_COMMENT: - break ; + break; case LINE_SECTION: - mem_err = dictionary_set(dict, section, NULL); - break ; + mem_err = dictionary_set(dict, section, NULL); + break; case LINE_VALUE: - sprintf(tmp, "%s:%s", section, key); - mem_err = dictionary_set(dict, tmp, val); - break ; + sprintf(tmp, "%s:%s", section, key); + mem_err = dictionary_set(dict, tmp, val); + break; case LINE_ERROR: - iniparser_error_callback( - "iniparser: syntax error in %s (%d):\n-> %s\n", - ininame, - lineno, - line); - errs++ ; - break; + iniparser_error_callback("iniparser: syntax error in %s (%d):\n-> %s\n", ininame, lineno, line); + errs++; + break; default: - break ; + break; } memset(line, 0, ASCIILINESZ); - last=0; - if (mem_err<0) { + last = 0; + if (mem_err < 0) + { iniparser_error_callback("iniparser: memory allocation failure\n"); - break ; + break; } } - if (errs) { + if (errs) + { dictionary_del(dict); - dict = NULL ; + dict = NULL; } fclose(in); - return dict ; + return dict; } /*-------------------------------------------------------------------------*/ @@ -830,7 +883,7 @@ dictionary * iniparser_load(const char * ininame) gets out of the current context. */ /*--------------------------------------------------------------------------*/ -void iniparser_freedict(dictionary * d) +void iniparser_freedict(dictionary* d) { dictionary_del(d); } diff --git a/ext_libs/iniParser/iniparser.h b/ext_libs/iniParser/iniparser.h index 37ff7b71..f12fc40c 100644 --- a/ext_libs/iniParser/iniparser.h +++ b/ext_libs/iniParser/iniparser.h @@ -28,328 +28,323 @@ #include "dictionary.h" #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/*-------------------------------------------------------------------------*/ -/** - @brief Configure a function to receive the error messages. - @param errback Function to call. - - By default, the error will be printed on stderr. If a null pointer is passed - as errback the error callback will be switched back to default. - */ -/*--------------------------------------------------------------------------*/ - -void iniparser_set_error_callback(int (*errback)(const char *, ...)); - -/*-------------------------------------------------------------------------*/ -/** - @brief Get number of sections in a dictionary - @param d Dictionary to examine - @return int Number of sections found in dictionary - - This function returns the number of sections found in a dictionary. - The test to recognize sections is done on the string stored in the - dictionary: a section name is given as "section" whereas a key is - stored as "section:key", thus the test looks for entries that do not - contain a colon. - - This clearly fails in the case a section name contains a colon, but - this should simply be avoided. - - This function returns -1 in case of error. - */ -/*--------------------------------------------------------------------------*/ - -int iniparser_getnsec(const dictionary * d); - - -/*-------------------------------------------------------------------------*/ -/** - @brief Get name for section n in a dictionary. - @param d Dictionary to examine - @param n Section number (from 0 to nsec-1). - @return Pointer to char string - - This function locates the n-th section in a dictionary and returns - its name as a pointer to a string statically allocated inside the - dictionary. Do not free or modify the returned string! - - This function returns NULL in case of error. - */ -/*--------------------------------------------------------------------------*/ - -const char * iniparser_getsecname(const dictionary * d, int n); - - -/*-------------------------------------------------------------------------*/ -/** - @brief Save a dictionary to a loadable ini file - @param d Dictionary to dump - @param f Opened file pointer to dump to - @return void - - This function dumps a given dictionary into a loadable ini file. - It is Ok to specify @c stderr or @c stdout as output files. - */ -/*--------------------------------------------------------------------------*/ - -void iniparser_dump_ini(const dictionary * d, FILE * f); - -/*-------------------------------------------------------------------------*/ -/** - @brief Save a dictionary section to a loadable ini file - @param d Dictionary to dump - @param s Section name of dictionary to dump - @param f Opened file pointer to dump to - @return void - - This function dumps a given section of a given dictionary into a loadable ini - file. It is Ok to specify @c stderr or @c stdout as output files. - */ -/*--------------------------------------------------------------------------*/ - -void iniparser_dumpsection_ini(const dictionary * d, const char * s, FILE * f); - -/*-------------------------------------------------------------------------*/ -/** - @brief Dump a dictionary to an opened file pointer. - @param d Dictionary to dump. - @param f Opened file pointer to dump to. - @return void - - This function prints out the contents of a dictionary, one element by - line, onto the provided file pointer. It is OK to specify @c stderr - or @c stdout as output files. This function is meant for debugging - purposes mostly. - */ -/*--------------------------------------------------------------------------*/ -void iniparser_dump(const dictionary * d, FILE * f); - -/*-------------------------------------------------------------------------*/ -/** - @brief Get the number of keys in a section of a dictionary. - @param d Dictionary to examine - @param s Section name of dictionary to examine - @return Number of keys in section - */ -/*--------------------------------------------------------------------------*/ -int iniparser_getsecnkeys(const dictionary * d, const char * s); - -/*-------------------------------------------------------------------------*/ -/** - @brief Get the number of keys in a section of a dictionary. - @param d Dictionary to examine - @param s Section name of dictionary to examine - @param keys Already allocated array to store the keys in - @return The pointer passed as `keys` argument or NULL in case of error - - This function queries a dictionary and finds all keys in a given section. - The keys argument should be an array of pointers which size has been - determined by calling `iniparser_getsecnkeys` function prior to this one. - - Each pointer in the returned char pointer-to-pointer is pointing to - a string allocated in the dictionary; do not free or modify them. - */ -/*--------------------------------------------------------------------------*/ -const char ** iniparser_getseckeys(const dictionary * d, const char * s, const char ** keys); - - -/*-------------------------------------------------------------------------*/ -/** - @brief Get the string associated to a key - @param d Dictionary to search - @param key Key string to look for - @param def Default value to return if key not found. - @return pointer to statically allocated character string - - This function queries a dictionary for a key. A key as read from an - ini file is given as "section:key". If the key cannot be found, - the pointer passed as 'def' is returned. - The returned char pointer is pointing to a string allocated in - the dictionary, do not free or modify it. - */ -/*--------------------------------------------------------------------------*/ -const char * iniparser_getstring(const dictionary * d, const char * key, const char * def); - -/*-------------------------------------------------------------------------*/ -/** - @brief Get the string associated to a key, convert to an int - @param d Dictionary to search - @param key Key string to look for - @param notfound Value to return in case of error - @return integer - - This function queries a dictionary for a key. A key as read from an - ini file is given as "section:key". If the key cannot be found, - the notfound value is returned. - - Supported values for integers include the usual C notation - so decimal, octal (starting with 0) and hexadecimal (starting with 0x) - are supported. Examples: - - - "42" -> 42 - - "042" -> 34 (octal -> decimal) - - "0x42" -> 66 (hexa -> decimal) - - Warning: the conversion may overflow in various ways. Conversion is - totally outsourced to strtol(), see the associated man page for overflow - handling. - - Credits: Thanks to A. Becker for suggesting strtol() - */ -/*--------------------------------------------------------------------------*/ -int iniparser_getint(const dictionary * d, const char * key, int notfound); - -/*-------------------------------------------------------------------------*/ -/** - @brief Get the string associated to a key, convert to an long int - @param d Dictionary to search - @param key Key string to look for - @param notfound Value to return in case of error - @return integer - - This function queries a dictionary for a key. A key as read from an - ini file is given as "section:key". If the key cannot be found, - the notfound value is returned. - - Supported values for integers include the usual C notation - so decimal, octal (starting with 0) and hexadecimal (starting with 0x) - are supported. Examples: - - - "42" -> 42 - - "042" -> 34 (octal -> decimal) - - "0x42" -> 66 (hexa -> decimal) - - Warning: the conversion may overflow in various ways. Conversion is - totally outsourced to strtol(), see the associated man page for overflow - handling. - */ -/*--------------------------------------------------------------------------*/ -long int iniparser_getlongint(const dictionary * d, const char * key, long int notfound); - - -/*-------------------------------------------------------------------------*/ -/** - @brief Get the string associated to a key, convert to a double - @param d Dictionary to search - @param key Key string to look for - @param notfound Value to return in case of error - @return double - - This function queries a dictionary for a key. A key as read from an - ini file is given as "section:key". If the key cannot be found, - the notfound value is returned. - */ -/*--------------------------------------------------------------------------*/ -double iniparser_getdouble(const dictionary * d, const char * key, double notfound); - -/*-------------------------------------------------------------------------*/ -/** - @brief Get the string associated to a key, convert to a boolean - @param d Dictionary to search - @param key Key string to look for - @param notfound Value to return in case of error - @return integer - - This function queries a dictionary for a key. A key as read from an - ini file is given as "section:key". If the key cannot be found, - the notfound value is returned. - - A true boolean is found if one of the following is matched: - - - A string starting with 'y' - - A string starting with 'Y' - - A string starting with 't' - - A string starting with 'T' - - A string starting with '1' - - A false boolean is found if one of the following is matched: - - - A string starting with 'n' - - A string starting with 'N' - - A string starting with 'f' - - A string starting with 'F' - - A string starting with '0' - - The notfound value returned if no boolean is identified, does not - necessarily have to be 0 or 1. - */ -/*--------------------------------------------------------------------------*/ -int iniparser_getboolean(const dictionary * d, const char * key, int notfound); - - -/*-------------------------------------------------------------------------*/ -/** - @brief Set an entry in a dictionary. - @param ini Dictionary to modify. - @param entry Entry to modify (entry name) - @param val New value to associate to the entry. - @return int 0 if Ok, -1 otherwise. - - If the given entry can be found in the dictionary, it is modified to - contain the provided value. If it cannot be found, the entry is created. - It is Ok to set val to NULL. - */ -/*--------------------------------------------------------------------------*/ -int iniparser_set(dictionary * ini, const char * entry, const char * val); - - -/*-------------------------------------------------------------------------*/ -/** - @brief Delete an entry in a dictionary - @param ini Dictionary to modify - @param entry Entry to delete (entry name) - @return void - - If the given entry can be found, it is deleted from the dictionary. - */ -/*--------------------------------------------------------------------------*/ -void iniparser_unset(dictionary * ini, const char * entry); - -/*-------------------------------------------------------------------------*/ -/** - @brief Finds out if a given entry exists in a dictionary - @param ini Dictionary to search - @param entry Name of the entry to look for - @return integer 1 if entry exists, 0 otherwise - - Finds out if a given entry exists in the dictionary. Since sections - are stored as keys with NULL associated values, this is the only way - of querying for the presence of sections in a dictionary. - */ -/*--------------------------------------------------------------------------*/ -int iniparser_find_entry(const dictionary * ini, const char * entry) ; - -/*-------------------------------------------------------------------------*/ -/** - @brief Parse an ini file and return an allocated dictionary object - @param ininame Name of the ini file to read. - @return Pointer to newly allocated dictionary - - This is the parser for ini files. This function is called, providing - the name of the file to be read. It returns a dictionary object that - should not be accessed directly, but through accessor functions - instead. - - The returned dictionary must be freed using iniparser_freedict(). - */ -/*--------------------------------------------------------------------------*/ -dictionary * iniparser_load(const char * ininame); - -/*-------------------------------------------------------------------------*/ -/** - @brief Free all memory associated to an ini dictionary - @param d Dictionary to free - @return void - - Free all memory associated to an ini dictionary. - It is mandatory to call this function before the dictionary object - gets out of the current context. - */ -/*--------------------------------------------------------------------------*/ -void iniparser_freedict(dictionary * d); + /*-------------------------------------------------------------------------*/ + /** + @brief Configure a function to receive the error messages. + @param errback Function to call. + + By default, the error will be printed on stderr. If a null pointer is passed + as errback the error callback will be switched back to default. + */ + /*--------------------------------------------------------------------------*/ + + void iniparser_set_error_callback(int (*errback)(const char*, ...)); + + /*-------------------------------------------------------------------------*/ + /** + @brief Get number of sections in a dictionary + @param d Dictionary to examine + @return int Number of sections found in dictionary + + This function returns the number of sections found in a dictionary. + The test to recognize sections is done on the string stored in the + dictionary: a section name is given as "section" whereas a key is + stored as "section:key", thus the test looks for entries that do not + contain a colon. + + This clearly fails in the case a section name contains a colon, but + this should simply be avoided. + + This function returns -1 in case of error. + */ + /*--------------------------------------------------------------------------*/ + + int iniparser_getnsec(const dictionary* d); + + /*-------------------------------------------------------------------------*/ + /** + @brief Get name for section n in a dictionary. + @param d Dictionary to examine + @param n Section number (from 0 to nsec-1). + @return Pointer to char string + + This function locates the n-th section in a dictionary and returns + its name as a pointer to a string statically allocated inside the + dictionary. Do not free or modify the returned string! + + This function returns NULL in case of error. + */ + /*--------------------------------------------------------------------------*/ + + const char* iniparser_getsecname(const dictionary* d, int n); + + /*-------------------------------------------------------------------------*/ + /** + @brief Save a dictionary to a loadable ini file + @param d Dictionary to dump + @param f Opened file pointer to dump to + @return void + + This function dumps a given dictionary into a loadable ini file. + It is Ok to specify @c stderr or @c stdout as output files. + */ + /*--------------------------------------------------------------------------*/ + + void iniparser_dump_ini(const dictionary* d, FILE* f); + + /*-------------------------------------------------------------------------*/ + /** + @brief Save a dictionary section to a loadable ini file + @param d Dictionary to dump + @param s Section name of dictionary to dump + @param f Opened file pointer to dump to + @return void + + This function dumps a given section of a given dictionary into a loadable ini + file. It is Ok to specify @c stderr or @c stdout as output files. + */ + /*--------------------------------------------------------------------------*/ + + void iniparser_dumpsection_ini(const dictionary* d, const char* s, FILE* f); + + /*-------------------------------------------------------------------------*/ + /** + @brief Dump a dictionary to an opened file pointer. + @param d Dictionary to dump. + @param f Opened file pointer to dump to. + @return void + + This function prints out the contents of a dictionary, one element by + line, onto the provided file pointer. It is OK to specify @c stderr + or @c stdout as output files. This function is meant for debugging + purposes mostly. + */ + /*--------------------------------------------------------------------------*/ + void iniparser_dump(const dictionary* d, FILE* f); + + /*-------------------------------------------------------------------------*/ + /** + @brief Get the number of keys in a section of a dictionary. + @param d Dictionary to examine + @param s Section name of dictionary to examine + @return Number of keys in section + */ + /*--------------------------------------------------------------------------*/ + int iniparser_getsecnkeys(const dictionary* d, const char* s); + + /*-------------------------------------------------------------------------*/ + /** + @brief Get the number of keys in a section of a dictionary. + @param d Dictionary to examine + @param s Section name of dictionary to examine + @param keys Already allocated array to store the keys in + @return The pointer passed as `keys` argument or NULL in case of error + + This function queries a dictionary and finds all keys in a given section. + The keys argument should be an array of pointers which size has been + determined by calling `iniparser_getsecnkeys` function prior to this one. + + Each pointer in the returned char pointer-to-pointer is pointing to + a string allocated in the dictionary; do not free or modify them. + */ + /*--------------------------------------------------------------------------*/ + const char** iniparser_getseckeys(const dictionary* d, const char* s, const char** keys); + + /*-------------------------------------------------------------------------*/ + /** + @brief Get the string associated to a key + @param d Dictionary to search + @param key Key string to look for + @param def Default value to return if key not found. + @return pointer to statically allocated character string + + This function queries a dictionary for a key. A key as read from an + ini file is given as "section:key". If the key cannot be found, + the pointer passed as 'def' is returned. + The returned char pointer is pointing to a string allocated in + the dictionary, do not free or modify it. + */ + /*--------------------------------------------------------------------------*/ + const char* iniparser_getstring(const dictionary* d, const char* key, const char* def); + + /*-------------------------------------------------------------------------*/ + /** + @brief Get the string associated to a key, convert to an int + @param d Dictionary to search + @param key Key string to look for + @param notfound Value to return in case of error + @return integer + + This function queries a dictionary for a key. A key as read from an + ini file is given as "section:key". If the key cannot be found, + the notfound value is returned. + + Supported values for integers include the usual C notation + so decimal, octal (starting with 0) and hexadecimal (starting with 0x) + are supported. Examples: + + - "42" -> 42 + - "042" -> 34 (octal -> decimal) + - "0x42" -> 66 (hexa -> decimal) + + Warning: the conversion may overflow in various ways. Conversion is + totally outsourced to strtol(), see the associated man page for overflow + handling. + + Credits: Thanks to A. Becker for suggesting strtol() + */ + /*--------------------------------------------------------------------------*/ + int iniparser_getint(const dictionary* d, const char* key, int notfound); + + /*-------------------------------------------------------------------------*/ + /** + @brief Get the string associated to a key, convert to an long int + @param d Dictionary to search + @param key Key string to look for + @param notfound Value to return in case of error + @return integer + + This function queries a dictionary for a key. A key as read from an + ini file is given as "section:key". If the key cannot be found, + the notfound value is returned. + + Supported values for integers include the usual C notation + so decimal, octal (starting with 0) and hexadecimal (starting with 0x) + are supported. Examples: + + - "42" -> 42 + - "042" -> 34 (octal -> decimal) + - "0x42" -> 66 (hexa -> decimal) + + Warning: the conversion may overflow in various ways. Conversion is + totally outsourced to strtol(), see the associated man page for overflow + handling. + */ + /*--------------------------------------------------------------------------*/ + long int iniparser_getlongint(const dictionary* d, const char* key, long int notfound); + + /*-------------------------------------------------------------------------*/ + /** + @brief Get the string associated to a key, convert to a double + @param d Dictionary to search + @param key Key string to look for + @param notfound Value to return in case of error + @return double + + This function queries a dictionary for a key. A key as read from an + ini file is given as "section:key". If the key cannot be found, + the notfound value is returned. + */ + /*--------------------------------------------------------------------------*/ + double iniparser_getdouble(const dictionary* d, const char* key, double notfound); + + /*-------------------------------------------------------------------------*/ + /** + @brief Get the string associated to a key, convert to a boolean + @param d Dictionary to search + @param key Key string to look for + @param notfound Value to return in case of error + @return integer + + This function queries a dictionary for a key. A key as read from an + ini file is given as "section:key". If the key cannot be found, + the notfound value is returned. + + A true boolean is found if one of the following is matched: + + - A string starting with 'y' + - A string starting with 'Y' + - A string starting with 't' + - A string starting with 'T' + - A string starting with '1' + + A false boolean is found if one of the following is matched: + + - A string starting with 'n' + - A string starting with 'N' + - A string starting with 'f' + - A string starting with 'F' + - A string starting with '0' + + The notfound value returned if no boolean is identified, does not + necessarily have to be 0 or 1. + */ + /*--------------------------------------------------------------------------*/ + int iniparser_getboolean(const dictionary* d, const char* key, int notfound); + + /*-------------------------------------------------------------------------*/ + /** + @brief Set an entry in a dictionary. + @param ini Dictionary to modify. + @param entry Entry to modify (entry name) + @param val New value to associate to the entry. + @return int 0 if Ok, -1 otherwise. + + If the given entry can be found in the dictionary, it is modified to + contain the provided value. If it cannot be found, the entry is created. + It is Ok to set val to NULL. + */ + /*--------------------------------------------------------------------------*/ + int iniparser_set(dictionary* ini, const char* entry, const char* val); + + /*-------------------------------------------------------------------------*/ + /** + @brief Delete an entry in a dictionary + @param ini Dictionary to modify + @param entry Entry to delete (entry name) + @return void + + If the given entry can be found, it is deleted from the dictionary. + */ + /*--------------------------------------------------------------------------*/ + void iniparser_unset(dictionary* ini, const char* entry); + + /*-------------------------------------------------------------------------*/ + /** + @brief Finds out if a given entry exists in a dictionary + @param ini Dictionary to search + @param entry Name of the entry to look for + @return integer 1 if entry exists, 0 otherwise + + Finds out if a given entry exists in the dictionary. Since sections + are stored as keys with NULL associated values, this is the only way + of querying for the presence of sections in a dictionary. + */ + /*--------------------------------------------------------------------------*/ + int iniparser_find_entry(const dictionary* ini, const char* entry); + + /*-------------------------------------------------------------------------*/ + /** + @brief Parse an ini file and return an allocated dictionary object + @param ininame Name of the ini file to read. + @return Pointer to newly allocated dictionary + + This is the parser for ini files. This function is called, providing + the name of the file to be read. It returns a dictionary object that + should not be accessed directly, but through accessor functions + instead. + + The returned dictionary must be freed using iniparser_freedict(). + */ + /*--------------------------------------------------------------------------*/ + dictionary* iniparser_load(const char* ininame); + + /*-------------------------------------------------------------------------*/ + /** + @brief Free all memory associated to an ini dictionary + @param d Dictionary to free + @return void + + Free all memory associated to an ini dictionary. + It is mandatory to call this function before the dictionary object + gets out of the current context. + */ + /*--------------------------------------------------------------------------*/ + void iniparser_freedict(dictionary* d); #ifdef __cplusplus } diff --git a/ext_libs/iniParser/test/iniexample.c b/ext_libs/iniParser/test/iniexample.c index 833b1ccd..00fdcc7e 100644 --- a/ext_libs/iniParser/test/iniexample.c +++ b/ext_libs/iniParser/test/iniexample.c @@ -40,95 +40,96 @@ #include "iniparser.h" void create_example_ini_file(void); -int parse_ini_file(char * ini_name); +int parse_ini_file(char* ini_name); -int main(int argc, char * argv[]) +int main(int argc, char* argv[]) { - int status ; - - if (argc<2) { - create_example_ini_file(); - status = parse_ini_file("example.ini"); - } else { - status = parse_ini_file(argv[1]); - } - return status ; + int status; + + if (argc < 2) + { + create_example_ini_file(); + status = parse_ini_file("example.ini"); + } + else + { + status = parse_ini_file(argv[1]); + } + return status; } void create_example_ini_file(void) { - FILE * ini ; - - ini = fopen("example.ini", "w"); - fprintf(ini, - "#\n" - "# This is an example of ini file\n" - "#\n" - "\n" - "[Pizza]\n" - "\n" - "Ham = yes ;\n" - "Mushrooms = TRUE ;\n" - "Capres = 0 ;\n" - "Cheese = Non ;\n" - "\n" - "\n" - "[Wine]\n" - "\n" - "Grape = Cabernet Sauvignon ;\n" - "Year = 1989 ;\n" - "Country = Spain ;\n" - "Alcohol = 12.5 ;\n" - "\n"); - fclose(ini); + FILE* ini; + + ini = fopen("example.ini", "w"); + fprintf(ini, + "#\n" + "# This is an example of ini file\n" + "#\n" + "\n" + "[Pizza]\n" + "\n" + "Ham = yes ;\n" + "Mushrooms = TRUE ;\n" + "Capres = 0 ;\n" + "Cheese = Non ;\n" + "\n" + "\n" + "[Wine]\n" + "\n" + "Grape = Cabernet Sauvignon ;\n" + "Year = 1989 ;\n" + "Country = Spain ;\n" + "Alcohol = 12.5 ;\n" + "\n"); + fclose(ini); } - -int parse_ini_file(char * ini_name) +int parse_ini_file(char* ini_name) { - dictionary * ini ; - - /* Some temporary variables to hold query results */ - int b ; - int i ; - double d ; - char * s ; - - ini = iniparser_load(ini_name); - if (ini==NULL) { - fprintf(stderr, "cannot parse file: %s\n", ini_name); - return -1 ; - } - iniparser_dump(ini, stderr); - - /* Get pizza attributes */ - printf("Pizza:\n"); - - b = iniparser_getboolean(ini, "pizza:ham", -1); - printf("Ham: [%d]\n", b); - b = iniparser_getboolean(ini, "pizza:mushrooms", -1); - printf("Mushrooms: [%d]\n", b); - b = iniparser_getboolean(ini, "pizza:capres", -1); - printf("Capres: [%d]\n", b); - b = iniparser_getboolean(ini, "pizza:cheese", -1); - printf("Cheese: [%d]\n", b); - - /* Get wine attributes */ - printf("Wine:\n"); - s = iniparser_getstring(ini, "wine:grape", NULL); + dictionary* ini; + + /* Some temporary variables to hold query results */ + int b; + int i; + double d; + char* s; + + ini = iniparser_load(ini_name); + if (ini == NULL) + { + fprintf(stderr, "cannot parse file: %s\n", ini_name); + return -1; + } + iniparser_dump(ini, stderr); + + /* Get pizza attributes */ + printf("Pizza:\n"); + + b = iniparser_getboolean(ini, "pizza:ham", -1); + printf("Ham: [%d]\n", b); + b = iniparser_getboolean(ini, "pizza:mushrooms", -1); + printf("Mushrooms: [%d]\n", b); + b = iniparser_getboolean(ini, "pizza:capres", -1); + printf("Capres: [%d]\n", b); + b = iniparser_getboolean(ini, "pizza:cheese", -1); + printf("Cheese: [%d]\n", b); + + /* Get wine attributes */ + printf("Wine:\n"); + s = iniparser_getstring(ini, "wine:grape", NULL); printf("Grape: [%s]\n", s ? s : "UNDEF"); i = iniparser_getint(ini, "wine:year", -1); printf("Year: [%d]\n", i); - s = iniparser_getstring(ini, "wine:country", NULL); + s = iniparser_getstring(ini, "wine:country", NULL); printf("Country: [%s]\n", s ? s : "UNDEF"); d = iniparser_getdouble(ini, "wine:alcohol", -1.0); printf("Alcohol: [%g]\n", d); - iniparser_freedict(ini); - return 0 ; + iniparser_freedict(ini); + return 0; } - - diff --git a/ext_libs/iniParser/test/parse.c b/ext_libs/iniParser/test/parse.c index 9c420c66..940a44fb 100644 --- a/ext_libs/iniParser/test/parse.c +++ b/ext_libs/iniParser/test/parse.c @@ -39,20 +39,23 @@ #include "iniparser.h" -int main(int argc, char * argv[]) +int main(int argc, char* argv[]) { - dictionary * ini ; - char * ini_name ; + dictionary* ini; + char* ini_name; - if (argc<2) { + if (argc < 2) + { ini_name = "twisted.ini"; - } else { - ini_name = argv[1] ; - } + } + else + { + ini_name = argv[1]; + } ini = iniparser_load(ini_name); iniparser_dump(ini, stdout); iniparser_freedict(ini); - return 0 ; + return 0; } diff --git a/ext_libs/iniParser/test/sandbox.c b/ext_libs/iniParser/test/sandbox.c index 36c1e160..6a10ac8a 100644 --- a/ext_libs/iniParser/test/sandbox.c +++ b/ext_libs/iniParser/test/sandbox.c @@ -35,10 +35,11 @@ #include #include "../src/iniparser.h" -char *ini_file = "../example.ini"; +char* ini_file = "../example.ini"; -int main() { - dictionary* d = iniparser_load(ini_file); - iniparser_dump_ini(d, stdout); - iniparser_freedict(d); +int main() +{ + dictionary* d = iniparser_load(ini_file); + iniparser_dump_ini(d, stdout); + iniparser_freedict(d); } diff --git a/ext_libs/iniParser/test/twisted-genhuge.py b/ext_libs/iniParser/test/twisted-genhuge.py index 3a4a2cad..d42edd39 100644 --- a/ext_libs/iniParser/test/twisted-genhuge.py +++ b/ext_libs/iniParser/test/twisted-genhuge.py @@ -28,17 +28,16 @@ # 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. -#-- +# -- # -*- coding: utf-8 -*- import os import sys -if __name__=="__main__": - f=open('twisted-massive.ini', 'w') +if __name__ == "__main__": + f = open('twisted-massive.ini', 'w') for i in range(100): f.write('[%03d]\n' % i) for j in range(100): f.write('key-%03d=1;\n' % j) f.close() - diff --git a/ext_libs/json/json/autolink.h b/ext_libs/json/json/autolink.h old mode 100755 new mode 100644 index 02328d1f..a38df5e8 --- a/ext_libs/json/json/autolink.h +++ b/ext_libs/json/json/autolink.h @@ -4,21 +4,21 @@ // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE #ifndef JSON_AUTOLINK_H_INCLUDED -# define JSON_AUTOLINK_H_INCLUDED +#define JSON_AUTOLINK_H_INCLUDED -# include "config.h" +#include "config.h" -# ifdef JSON_IN_CPPTL -# include -# endif +#ifdef JSON_IN_CPPTL +#include +#endif -# if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && !defined(JSON_IN_CPPTL) -# define CPPTL_AUTOLINK_NAME "json" -# undef CPPTL_AUTOLINK_DLL -# ifdef JSON_DLL -# define CPPTL_AUTOLINK_DLL -# endif -# include "autolink.h" -# endif +#if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && !defined(JSON_IN_CPPTL) +#define CPPTL_AUTOLINK_NAME "json" +#undef CPPTL_AUTOLINK_DLL +#ifdef JSON_DLL +#define CPPTL_AUTOLINK_DLL +#endif +#include "autolink.h" +#endif #endif // JSON_AUTOLINK_H_INCLUDED diff --git a/ext_libs/json/json/config.h b/ext_libs/json/json/config.h old mode 100755 new mode 100644 index d3fab364..c57273dd --- a/ext_libs/json/json/config.h +++ b/ext_libs/json/json/config.h @@ -4,7 +4,7 @@ // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE #ifndef JSON_CONFIG_H_INCLUDED -# define JSON_CONFIG_H_INCLUDED +#define JSON_CONFIG_H_INCLUDED /// If defined, indicates that json library is embedded in CppTL library. //# define JSON_IN_CPPTL 1 @@ -26,23 +26,23 @@ /// If defined, indicates that Json use exception to report invalid type manipulation /// instead of C assert macro. -# define JSON_USE_EXCEPTION 1 +#define JSON_USE_EXCEPTION 1 -# ifdef JSON_IN_CPPTL -# include -# ifndef JSON_USE_CPPTL -# define JSON_USE_CPPTL 1 -# endif -# endif +#ifdef JSON_IN_CPPTL +#include +#ifndef JSON_USE_CPPTL +#define JSON_USE_CPPTL 1 +#endif +#endif -# ifdef JSON_IN_CPPTL -# define JSON_API CPPTL_API -# elif defined(JSON_DLL_BUILD) -# define JSON_API __declspec(dllexport) -# elif defined(JSON_DLL) -# define JSON_API __declspec(dllimport) -# else -# define JSON_API -# endif +#ifdef JSON_IN_CPPTL +#define JSON_API CPPTL_API +#elif defined(JSON_DLL_BUILD) +#define JSON_API __declspec(dllexport) +#elif defined(JSON_DLL) +#define JSON_API __declspec(dllimport) +#else +#define JSON_API +#endif #endif // JSON_CONFIG_H_INCLUDED diff --git a/ext_libs/json/json/features.h b/ext_libs/json/json/features.h old mode 100755 new mode 100644 index 3169cb1c..d5de93d5 --- a/ext_libs/json/json/features.h +++ b/ext_libs/json/json/features.h @@ -3,45 +3,44 @@ // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - #ifndef CPPTL_JSON_FEATURES_H_INCLUDED -# define CPPTL_JSON_FEATURES_H_INCLUDED - -# include "forwards.h" - -namespace Json { - - /** \brief Configuration passed to reader and writer. - * This configuration object can be used to force the Reader or Writer - * to behave in a standard conforming way. - */ - class JSON_API Features - { - public: - /** \brief A configuration that allows all features and assumes all strings are UTF-8. - * - C & C++ comments are allowed - * - Root object can be any JSON value - * - Assumes Value strings are encoded in UTF-8 - */ - static Features all(); - - /** \brief A configuration that is strictly compatible with the JSON specification. - * - Comments are forbidden. - * - Root object must be either an array or an object value. - * - Assumes Value strings are encoded in UTF-8 - */ - static Features strictMode(); - - /** \brief Initialize the configuration like JsonConfig::allFeatures; - */ - Features(); - - /// \c true if comments are allowed. Default: \c true. - bool allowComments_; - - /// \c true if root must be either an array or an object value. Default: \c false. - bool strictRoot_; - }; +#define CPPTL_JSON_FEATURES_H_INCLUDED + +#include "forwards.h" + +namespace Json +{ +/** \brief Configuration passed to reader and writer. + * This configuration object can be used to force the Reader or Writer + * to behave in a standard conforming way. + */ +class JSON_API Features +{ +public: + /** \brief A configuration that allows all features and assumes all strings are UTF-8. + * - C & C++ comments are allowed + * - Root object can be any JSON value + * - Assumes Value strings are encoded in UTF-8 + */ + static Features all(); + + /** \brief A configuration that is strictly compatible with the JSON specification. + * - Comments are forbidden. + * - Root object must be either an array or an object value. + * - Assumes Value strings are encoded in UTF-8 + */ + static Features strictMode(); + + /** \brief Initialize the configuration like JsonConfig::allFeatures; + */ + Features(); + + /// \c true if comments are allowed. Default: \c true. + bool allowComments_; + + /// \c true if root must be either an array or an object value. Default: \c false. + bool strictRoot_; +}; } // namespace Json diff --git a/ext_libs/json/json/forwards.h b/ext_libs/json/json/forwards.h old mode 100755 new mode 100644 index 10c7eddb..04b96a0d --- a/ext_libs/json/json/forwards.h +++ b/ext_libs/json/json/forwards.h @@ -3,43 +3,41 @@ // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - #ifndef JSON_FORWARDS_H_INCLUDED -# define JSON_FORWARDS_H_INCLUDED - -# include "config.h" - -namespace Json { - - // writer.h - class FastWriter; - class StyledWriter; - - // reader.h - class Reader; - - // features.h - class Features; - - // value.h - typedef int Int; - typedef unsigned int UInt; - class StaticString; - class Path; - class PathArgument; - class Value; - class ValueIteratorBase; - class ValueIterator; - class ValueConstIterator; +#define JSON_FORWARDS_H_INCLUDED + +#include "config.h" + +namespace Json +{ +// writer.h +class FastWriter; +class StyledWriter; + +// reader.h +class Reader; + +// features.h +class Features; + +// value.h +typedef int Int; +typedef unsigned int UInt; +class StaticString; +class Path; +class PathArgument; +class Value; +class ValueIteratorBase; +class ValueIterator; +class ValueConstIterator; #ifdef JSON_VALUE_USE_INTERNAL_MAP - class ValueAllocator; - class ValueMapAllocator; - class ValueInternalLink; - class ValueInternalArray; - class ValueInternalMap; +class ValueAllocator; +class ValueMapAllocator; +class ValueInternalLink; +class ValueInternalArray; +class ValueInternalMap; #endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP } // namespace Json - #endif // JSON_FORWARDS_H_INCLUDED diff --git a/ext_libs/json/json/json.h b/ext_libs/json/json/json.h old mode 100755 new mode 100644 index 5ad8d68e..8f10ac2b --- a/ext_libs/json/json/json.h +++ b/ext_libs/json/json/json.h @@ -3,14 +3,13 @@ // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - #ifndef JSON_JSON_H_INCLUDED -# define JSON_JSON_H_INCLUDED +#define JSON_JSON_H_INCLUDED -# include "autolink.h" -# include "value.h" -# include "reader.h" -# include "writer.h" -# include "features.h" +#include "autolink.h" +#include "value.h" +#include "reader.h" +#include "writer.h" +#include "features.h" #endif // JSON_JSON_H_INCLUDED diff --git a/ext_libs/json/json/reader.h b/ext_libs/json/json/reader.h old mode 100755 new mode 100644 index c3414e0b..8503280c --- a/ext_libs/json/json/reader.h +++ b/ext_libs/json/json/reader.h @@ -3,199 +3,177 @@ // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - #ifndef CPPTL_JSON_READER_H_INCLUDED -# define CPPTL_JSON_READER_H_INCLUDED - -# include "features.h" -# include "value.h" -# include -# include -# include -# include - -namespace Json { - - /** \brief Unserialize a JSON document into a Value. - * - */ - class JSON_API Reader - { - public: - typedef char Char; - typedef const Char *Location; - - /** \brief Constructs a Reader allowing all features - * for parsing. - */ - Reader(); - - /** \brief Constructs a Reader allowing the specified feature set - * for parsing. - */ - Reader( const Features &features ); - - /** \brief Read a Value from a JSON document. - * \param document UTF-8 encoded string containing the document to read. - * \param root [out] Contains the root value of the document if it was - * successfully parsed. - * \param collectComments \c true to collect comment and allow writing them back during - * serialization, \c false to discard comments. - * This parameter is ignored if Features::allowComments_ - * is \c false. - * \return \c true if the document was successfully parsed, \c false if an error occurred. - */ - bool parse( const std::string &document, - Value &root, - bool collectComments = true ); - - /** \brief Read a Value from a JSON document. - * \param document UTF-8 encoded string containing the document to read. - * \param root [out] Contains the root value of the document if it was - * successfully parsed. - * \param collectComments \c true to collect comment and allow writing them back during - * serialization, \c false to discard comments. - * This parameter is ignored if Features::allowComments_ - * is \c false. - * \return \c true if the document was successfully parsed, \c false if an error occurred. - */ - bool parse( const char *beginDoc, const char *endDoc, - Value &root, - bool collectComments = true ); - - /// \brief Parse from input stream. - /// \see Json::operator>>(std::istream&, Json::Value&). - bool parse( std::istream &is, - Value &root, - bool collectComments = true ); - - /** \brief Returns a user friendly string that list errors in the parsed document. - * \return Formatted error message with the list of errors with their location in - * the parsed document. An empty string is returned if no error occurred - * during parsing. - */ - std::string getFormatedErrorMessages() const; - - private: - enum TokenType - { - tokenEndOfStream = 0, - tokenObjectBegin, - tokenObjectEnd, - tokenArrayBegin, - tokenArrayEnd, - tokenString, - tokenNumber, - tokenTrue, - tokenFalse, - tokenNull, - tokenArraySeparator, - tokenMemberSeparator, - tokenComment, - tokenError - }; - - class Token - { - public: - TokenType type_; - Location start_; - Location end_; - }; - - class ErrorInfo - { - public: - Token token_; - std::string message_; - Location extra_; - }; - - typedef std::deque Errors; - - bool expectToken( TokenType type, Token &token, const char *message ); - bool readToken( Token &token ); - void skipSpaces(); - bool match( Location pattern, - int patternLength ); - bool readComment(); - bool readCStyleComment(); - bool readCppStyleComment(); - bool readString(); - void readNumber(); - bool readValue(); - bool readObject( Token &token ); - bool readArray( Token &token ); - bool decodeNumber( Token &token ); - bool decodeString( Token &token ); - bool decodeString( Token &token, std::string &decoded ); - bool decodeDouble( Token &token ); - bool decodeUnicodeCodePoint( Token &token, - Location ¤t, - Location end, - unsigned int &unicode ); - bool decodeUnicodeEscapeSequence( Token &token, - Location ¤t, - Location end, - unsigned int &unicode ); - bool addError( const std::string &message, - Token &token, - Location extra = 0 ); - bool recoverFromError( TokenType skipUntilToken ); - bool addErrorAndRecover( const std::string &message, - Token &token, - TokenType skipUntilToken ); - void skipUntilSpace(); - Value ¤tValue(); - Char getNextChar(); - void getLocationLineAndColumn( Location location, - int &line, - int &column ) const; - std::string getLocationLineAndColumn( Location location ) const; - void addComment( Location begin, - Location end, - CommentPlacement placement ); - void skipCommentTokens( Token &token ); - - typedef std::stack Nodes; - Nodes nodes_; - Errors errors_; - std::string document_; - Location begin_; - Location end_; - Location current_; - Location lastValueEnd_; - Value *lastValue_; - std::string commentsBefore_; - Features features_; - bool collectComments_; - }; - - /** \brief Read from 'sin' into 'root'. - - Always keep comments from the input JSON. - - This can be used to read a file into a particular sub-object. - For example: - \code - Json::Value root; - cin >> root["dir"]["file"]; - cout << root; - \endcode - Result: - \verbatim +#define CPPTL_JSON_READER_H_INCLUDED + +#include "features.h" +#include "value.h" +#include +#include +#include +#include + +namespace Json +{ +/** \brief Unserialize a JSON document into a Value. + * + */ +class JSON_API Reader +{ +public: + typedef char Char; + typedef const Char* Location; + + /** \brief Constructs a Reader allowing all features + * for parsing. + */ + Reader(); + + /** \brief Constructs a Reader allowing the specified feature set + * for parsing. + */ + Reader(const Features& features); + + /** \brief Read a Value from a JSON document. + * \param document UTF-8 encoded string containing the document to read. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param collectComments \c true to collect comment and allow writing them back during + * serialization, \c false to discard comments. + * This parameter is ignored if Features::allowComments_ + * is \c false. + * \return \c true if the document was successfully parsed, \c false if an error occurred. + */ + bool parse(const std::string& document, Value& root, bool collectComments = true); + + /** \brief Read a Value from a JSON document. + * \param document UTF-8 encoded string containing the document to read. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param collectComments \c true to collect comment and allow writing them back during + * serialization, \c false to discard comments. + * This parameter is ignored if Features::allowComments_ + * is \c false. + * \return \c true if the document was successfully parsed, \c false if an error occurred. + */ + bool parse(const char* beginDoc, const char* endDoc, Value& root, bool collectComments = true); + + /// \brief Parse from input stream. + /// \see Json::operator>>(std::istream&, Json::Value&). + bool parse(std::istream& is, Value& root, bool collectComments = true); + + /** \brief Returns a user friendly string that list errors in the parsed document. + * \return Formatted error message with the list of errors with their location in + * the parsed document. An empty string is returned if no error occurred + * during parsing. + */ + std::string getFormatedErrorMessages() const; + +private: + enum TokenType + { + tokenEndOfStream = 0, + tokenObjectBegin, + tokenObjectEnd, + tokenArrayBegin, + tokenArrayEnd, + tokenString, + tokenNumber, + tokenTrue, + tokenFalse, + tokenNull, + tokenArraySeparator, + tokenMemberSeparator, + tokenComment, + tokenError + }; + + class Token + { + public: + TokenType type_; + Location start_; + Location end_; + }; + + class ErrorInfo { - "dir": { - "file": { - // The input stream JSON would be nested here. - } - } - } - \endverbatim - \throw std::exception on parse error. - \see Json::operator<<() - */ - std::istream& operator>>( std::istream&, Value& ); + public: + Token token_; + std::string message_; + Location extra_; + }; + + typedef std::deque Errors; + + bool expectToken(TokenType type, Token& token, const char* message); + bool readToken(Token& token); + void skipSpaces(); + bool match(Location pattern, int patternLength); + bool readComment(); + bool readCStyleComment(); + bool readCppStyleComment(); + bool readString(); + void readNumber(); + bool readValue(); + bool readObject(Token& token); + bool readArray(Token& token); + bool decodeNumber(Token& token); + bool decodeString(Token& token); + bool decodeString(Token& token, std::string& decoded); + bool decodeDouble(Token& token); + bool decodeUnicodeCodePoint(Token& token, Location& current, Location end, unsigned int& unicode); + bool decodeUnicodeEscapeSequence(Token& token, Location& current, Location end, unsigned int& unicode); + bool addError(const std::string& message, Token& token, Location extra = 0); + bool recoverFromError(TokenType skipUntilToken); + bool addErrorAndRecover(const std::string& message, Token& token, TokenType skipUntilToken); + void skipUntilSpace(); + Value& currentValue(); + Char getNextChar(); + void getLocationLineAndColumn(Location location, int& line, int& column) const; + std::string getLocationLineAndColumn(Location location) const; + void addComment(Location begin, Location end, CommentPlacement placement); + void skipCommentTokens(Token& token); + + typedef std::stack Nodes; + Nodes nodes_; + Errors errors_; + std::string document_; + Location begin_; + Location end_; + Location current_; + Location lastValueEnd_; + Value* lastValue_; + std::string commentsBefore_; + Features features_; + bool collectComments_; +}; + +/** \brief Read from 'sin' into 'root'. + + Always keep comments from the input JSON. + + This can be used to read a file into a particular sub-object. + For example: + \code + Json::Value root; + cin >> root["dir"]["file"]; + cout << root; + \endcode + Result: + \verbatim + { + "dir": { + "file": { + // The input stream JSON would be nested here. + } + } + } + \endverbatim + \throw std::exception on parse error. + \see Json::operator<<() +*/ +std::istream& operator>>(std::istream&, Value&); } // namespace Json diff --git a/ext_libs/json/json/value.h b/ext_libs/json/json/value.h old mode 100755 new mode 100644 index 6ad1e250..a07a1a44 --- a/ext_libs/json/json/value.h +++ b/ext_libs/json/json/value.h @@ -3,1073 +3,1013 @@ // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - #ifndef CPPTL_JSON_H_INCLUDED -# define CPPTL_JSON_H_INCLUDED +#define CPPTL_JSON_H_INCLUDED -# include "forwards.h" -# include -# include +#include "forwards.h" +#include +#include -# ifndef JSON_USE_CPPTL_SMALLMAP -# include -# else -# include -# endif -# ifdef JSON_USE_CPPTL -# include -# endif +#ifndef JSON_USE_CPPTL_SMALLMAP +#include +#else +#include +#endif +#ifdef JSON_USE_CPPTL +#include +#endif /** \brief JSON (JavaScript Object Notation). */ -namespace Json { - - /** \brief Type of the value held by a Value object. - */ - enum ValueType - { - nullValue = 0, ///< 'null' value - intValue, ///< signed integer value - uintValue, ///< unsigned integer value - realValue, ///< double value - stringValue, ///< UTF-8 string value - booleanValue, ///< bool value - arrayValue, ///< array value (ordered list) - objectValue ///< object value (collection of name/value pairs). - }; +namespace Json +{ +/** \brief Type of the value held by a Value object. + */ +enum ValueType +{ + nullValue = 0, ///< 'null' value + intValue, ///< signed integer value + uintValue, ///< unsigned integer value + realValue, ///< double value + stringValue, ///< UTF-8 string value + booleanValue, ///< bool value + arrayValue, ///< array value (ordered list) + objectValue ///< object value (collection of name/value pairs). +}; - enum CommentPlacement - { - commentBefore = 0, ///< a comment placed on the line before a value - commentAfterOnSameLine, ///< a comment just after a value on the same line - commentAfter, ///< a comment on the line after a value (only make sense for root value) - numberOfCommentPlacement - }; +enum CommentPlacement +{ + commentBefore = 0, ///< a comment placed on the line before a value + commentAfterOnSameLine, ///< a comment just after a value on the same line + commentAfter, ///< a comment on the line after a value (only make sense for root value) + numberOfCommentPlacement +}; //# ifdef JSON_USE_CPPTL // typedef CppTL::AnyEnumerator EnumMemberNames; // typedef CppTL::AnyEnumerator EnumValues; //# endif - /** \brief Lightweight wrapper to tag static string. - * - * Value constructor and objectValue member assignement takes advantage of the - * StaticString and avoid the cost of string duplication when storing the - * string or the member name. - * - * Example of usage: - * \code - * Json::Value aValue( StaticString("some text") ); - * Json::Value object; - * static const StaticString code("code"); - * object[code] = 1234; - * \endcode - */ - class JSON_API StaticString - { - public: - explicit StaticString( const char *czstring ) - : str_( czstring ) - { - } +/** \brief Lightweight wrapper to tag static string. + * + * Value constructor and objectValue member assignement takes advantage of the + * StaticString and avoid the cost of string duplication when storing the + * string or the member name. + * + * Example of usage: + * \code + * Json::Value aValue( StaticString("some text") ); + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ +class JSON_API StaticString +{ +public: + explicit StaticString(const char* czstring) : str_(czstring) {} - operator const char *() const - { - return str_; - } + operator const char*() const { return str_; } - const char *c_str() const - { - return str_; - } + const char* c_str() const { return str_; } - private: - const char *str_; - }; +private: + const char* str_; +}; - /** \brief Represents a JSON value. - * - * This class is a discriminated union wrapper that can represents a: - * - signed integer [range: Value::minInt - Value::maxInt] - * - unsigned integer (range: 0 - Value::maxUInt) - * - double - * - UTF-8 string - * - boolean - * - 'null' - * - an ordered list of Value - * - collection of name/value pairs (javascript object) - * - * The type of the held value is represented by a #ValueType and - * can be obtained using type(). - * - * values of an #objectValue or #arrayValue can be accessed using operator[]() methods. - * Non const methods will automatically create the a #nullValue element - * if it does not exist. - * The sequence of an #arrayValue will be automatically resize and initialized - * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. - * - * The get() methods can be used to obtanis default value in the case the required element - * does not exist. - * - * It is possible to iterate over the list of a #objectValue values using - * the getMemberNames() method. - */ - class JSON_API Value - { - friend class ValueIteratorBase; -# ifdef JSON_VALUE_USE_INTERNAL_MAP - friend class ValueInternalLink; - friend class ValueInternalMap; -# endif - public: - typedef std::vector Members; - typedef ValueIterator iterator; - typedef ValueConstIterator const_iterator; - typedef Json::UInt UInt; - typedef Json::Int Int; - typedef UInt ArrayIndex; - - static const Value null; - static const Int minInt; - static const Int maxInt; - static const UInt maxUInt; - - private: +/** \brief Represents a JSON value. + * + * This class is a discriminated union wrapper that can represents a: + * - signed integer [range: Value::minInt - Value::maxInt] + * - unsigned integer (range: 0 - Value::maxUInt) + * - double + * - UTF-8 string + * - boolean + * - 'null' + * - an ordered list of Value + * - collection of name/value pairs (javascript object) + * + * The type of the held value is represented by a #ValueType and + * can be obtained using type(). + * + * values of an #objectValue or #arrayValue can be accessed using operator[]() methods. + * Non const methods will automatically create the a #nullValue element + * if it does not exist. + * The sequence of an #arrayValue will be automatically resize and initialized + * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. + * + * The get() methods can be used to obtanis default value in the case the required element + * does not exist. + * + * It is possible to iterate over the list of a #objectValue values using + * the getMemberNames() method. + */ +class JSON_API Value +{ + friend class ValueIteratorBase; +#ifdef JSON_VALUE_USE_INTERNAL_MAP + friend class ValueInternalLink; + friend class ValueInternalMap; +#endif +public: + typedef std::vector Members; + typedef ValueIterator iterator; + typedef ValueConstIterator const_iterator; + typedef Json::UInt UInt; + typedef Json::Int Int; + typedef UInt ArrayIndex; + + static const Value null; + static const Int minInt; + static const Int maxInt; + static const UInt maxUInt; + +private: #ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION -# ifndef JSON_VALUE_USE_INTERNAL_MAP - class CZString - { - public: - enum DuplicationPolicy - { +#ifndef JSON_VALUE_USE_INTERNAL_MAP + class CZString + { + public: + enum DuplicationPolicy + { noDuplication = 0, duplicate, duplicateOnCopy - }; - CZString( int index ); - CZString( const char *cstr, DuplicationPolicy allocate ); - CZString( const CZString &other ); - ~CZString(); - CZString &operator =( const CZString &other ); - bool operator<( const CZString &other ) const; - bool operator==( const CZString &other ) const; - int index() const; - const char *c_str() const; - bool isStaticString() const; - private: - void swap( CZString &other ); - const char *cstr_; - int index_; - }; - - public: -# ifndef JSON_USE_CPPTL_SMALLMAP - typedef std::map ObjectValues; -# else - typedef CppTL::SmallMap ObjectValues; -# endif // ifndef JSON_USE_CPPTL_SMALLMAP -# endif // ifndef JSON_VALUE_USE_INTERNAL_MAP + }; + CZString(int index); + CZString(const char* cstr, DuplicationPolicy allocate); + CZString(const CZString& other); + ~CZString(); + CZString& operator=(const CZString& other); + bool operator<(const CZString& other) const; + bool operator==(const CZString& other) const; + int index() const; + const char* c_str() const; + bool isStaticString() const; + + private: + void swap(CZString& other); + const char* cstr_; + int index_; + }; + +public: +#ifndef JSON_USE_CPPTL_SMALLMAP + typedef std::map ObjectValues; +#else + typedef CppTL::SmallMap ObjectValues; +#endif // ifndef JSON_USE_CPPTL_SMALLMAP +#endif // ifndef JSON_VALUE_USE_INTERNAL_MAP #endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - public: - /** \brief Create a default Value of the given type. - - This is a very useful constructor. - To create an empty array, pass arrayValue. - To create an empty object, pass objectValue. - Another Value can then be set to this one by assignment. - This is useful since clear() and resize() will not alter types. - - Examples: - \code - Json::Value null_value; // null - Json::Value arr_value(Json::arrayValue); // [] - Json::Value obj_value(Json::objectValue); // {} - \endcode - */ - Value( ValueType type = nullValue ); - Value( Int value ); - Value( UInt value ); - Value( double value ); - Value( const char *value ); - Value( const char *beginValue, const char *endValue ); - /** \brief Constructs a value from a static string. - - * Like other value string constructor but do not duplicate the string for - * internal storage. The given string must remain alive after the call to this - * constructor. - * Example of usage: - * \code - * Json::Value aValue( StaticString("some text") ); - * \endcode - */ - Value( const StaticString &value ); - Value( const std::string &value ); -# ifdef JSON_USE_CPPTL - Value( const CppTL::ConstString &value ); -# endif - Value( bool value ); - Value( const Value &other ); - ~Value(); - - Value &operator=( const Value &other ); - /// Swap values. - /// \note Currently, comments are intentionally not swapped, for - /// both logic and efficiency. - void swap( Value &other ); - - ValueType type() const; - - bool operator <( const Value &other ) const; - bool operator <=( const Value &other ) const; - bool operator >=( const Value &other ) const; - bool operator >( const Value &other ) const; - - bool operator ==( const Value &other ) const; - bool operator !=( const Value &other ) const; - - int compare( const Value &other ); - - const char *asCString() const; - std::string asString() const; -# ifdef JSON_USE_CPPTL - CppTL::ConstString asConstString() const; -# endif - Int asInt() const; - UInt asUInt() const; - double asDouble() const; - bool asBool() const; - - bool isNull() const; - bool isBool() const; - bool isInt() const; - bool isUInt() const; - bool isIntegral() const; - bool isDouble() const; - bool isNumeric() const; - bool isString() const; - bool isArray() const; - bool isObject() const; - - bool isConvertibleTo( ValueType other ) const; - - /// Number of values in array or object - UInt size() const; - - /// \brief Return true if empty array, empty object, or null; - /// otherwise, false. - bool empty() const; - - /// Return isNull() - bool operator!() const; - - /// Remove all object members and array elements. - /// \pre type() is arrayValue, objectValue, or nullValue - /// \post type() is unchanged - void clear(); - - /// Resize the array to size elements. - /// New elements are initialized to null. - /// May only be called on nullValue or arrayValue. - /// \pre type() is arrayValue or nullValue - /// \post type() is arrayValue - void resize( UInt size ); - - /// Access an array element (zero based index ). - /// If the array contains less than index element, then null value are inserted - /// in the array so that its size is index+1. - /// (You may need to say 'value[0u]' to get your compiler to distinguish - /// this from the operator[] which takes a string.) - Value &operator[]( UInt index ); - /// Access an array element (zero based index ) - /// (You may need to say 'value[0u]' to get your compiler to distinguish - /// this from the operator[] which takes a string.) - const Value &operator[]( UInt index ) const; - /// If the array contains at least index+1 elements, returns the element value, - /// otherwise returns defaultValue. - Value get( UInt index, - const Value &defaultValue ) const; - /// Return true if index < size(). - bool isValidIndex( UInt index ) const; - /// \brief Append value to array at the end. - /// - /// Equivalent to jsonvalue[jsonvalue.size()] = value; - Value &append( const Value &value ); - - /// Access an object value by name, create a null member if it does not exist. - Value &operator[]( const char *key ); - /// Access an object value by name, returns null if there is no member with that name. - const Value &operator[]( const char *key ) const; - /// Access an object value by name, create a null member if it does not exist. - Value &operator[]( const std::string &key ); - /// Access an object value by name, returns null if there is no member with that name. - const Value &operator[]( const std::string &key ) const; - /** \brief Access an object value by name, create a null member if it does not exist. - - * If the object as no entry for that name, then the member name used to store - * the new entry is not duplicated. - * Example of use: - * \code - * Json::Value object; - * static const StaticString code("code"); - * object[code] = 1234; - * \endcode - */ - Value &operator[]( const StaticString &key ); -# ifdef JSON_USE_CPPTL - /// Access an object value by name, create a null member if it does not exist. - Value &operator[]( const CppTL::ConstString &key ); - /// Access an object value by name, returns null if there is no member with that name. - const Value &operator[]( const CppTL::ConstString &key ) const; -# endif - /// Return the member named key if it exist, defaultValue otherwise. - Value get( const char *key, - const Value &defaultValue ) const; - /// Return the member named key if it exist, defaultValue otherwise. - Value get( const std::string &key, - const Value &defaultValue ) const; -# ifdef JSON_USE_CPPTL - /// Return the member named key if it exist, defaultValue otherwise. - Value get( const CppTL::ConstString &key, - const Value &defaultValue ) const; -# endif - /// \brief Remove and return the named member. - /// - /// Do nothing if it did not exist. - /// \return the removed Value, or null. - /// \pre type() is objectValue or nullValue - /// \post type() is unchanged - Value removeMember( const char* key ); - /// Same as removeMember(const char*) - Value removeMember( const std::string &key ); - - /// Return true if the object has a member named key. - bool isMember( const char *key ) const; - /// Return true if the object has a member named key. - bool isMember( const std::string &key ) const; -# ifdef JSON_USE_CPPTL - /// Return true if the object has a member named key. - bool isMember( const CppTL::ConstString &key ) const; -# endif - - /// \brief Return a list of the member names. - /// - /// If null, return an empty list. - /// \pre type() is objectValue or nullValue - /// \post if type() was nullValue, it remains nullValue - Members getMemberNames() const; +public: + /** \brief Create a default Value of the given type. -//# ifdef JSON_USE_CPPTL -// EnumMemberNames enumMemberNames() const; -// EnumValues enumValues() const; -//# endif + This is a very useful constructor. + To create an empty array, pass arrayValue. + To create an empty object, pass objectValue. + Another Value can then be set to this one by assignment. + This is useful since clear() and resize() will not alter types. + + Examples: + \code + Json::Value null_value; // null + Json::Value arr_value(Json::arrayValue); // [] + Json::Value obj_value(Json::objectValue); // {} + \endcode + */ + Value(ValueType type = nullValue); + Value(Int value); + Value(UInt value); + Value(double value); + Value(const char* value); + Value(const char* beginValue, const char* endValue); + /** \brief Constructs a value from a static string. + + * Like other value string constructor but do not duplicate the string for + * internal storage. The given string must remain alive after the call to this + * constructor. + * Example of usage: + * \code + * Json::Value aValue( StaticString("some text") ); + * \endcode + */ + Value(const StaticString& value); + Value(const std::string& value); +#ifdef JSON_USE_CPPTL + Value(const CppTL::ConstString& value); +#endif + Value(bool value); + Value(const Value& other); + ~Value(); + + Value& operator=(const Value& other); + /// Swap values. + /// \note Currently, comments are intentionally not swapped, for + /// both logic and efficiency. + void swap(Value& other); + + ValueType type() const; + + bool operator<(const Value& other) const; + bool operator<=(const Value& other) const; + bool operator>=(const Value& other) const; + bool operator>(const Value& other) const; + + bool operator==(const Value& other) const; + bool operator!=(const Value& other) const; + + int compare(const Value& other); + + const char* asCString() const; + std::string asString() const; +#ifdef JSON_USE_CPPTL + CppTL::ConstString asConstString() const; +#endif + Int asInt() const; + UInt asUInt() const; + double asDouble() const; + bool asBool() const; + + bool isNull() const; + bool isBool() const; + bool isInt() const; + bool isUInt() const; + bool isIntegral() const; + bool isDouble() const; + bool isNumeric() const; + bool isString() const; + bool isArray() const; + bool isObject() const; + + bool isConvertibleTo(ValueType other) const; + + /// Number of values in array or object + UInt size() const; + + /// \brief Return true if empty array, empty object, or null; + /// otherwise, false. + bool empty() const; + + /// Return isNull() + bool operator!() const; + + /// Remove all object members and array elements. + /// \pre type() is arrayValue, objectValue, or nullValue + /// \post type() is unchanged + void clear(); + + /// Resize the array to size elements. + /// New elements are initialized to null. + /// May only be called on nullValue or arrayValue. + /// \pre type() is arrayValue or nullValue + /// \post type() is arrayValue + void resize(UInt size); + + /// Access an array element (zero based index ). + /// If the array contains less than index element, then null value are inserted + /// in the array so that its size is index+1. + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + Value& operator[](UInt index); + /// Access an array element (zero based index ) + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + const Value& operator[](UInt index) const; + /// If the array contains at least index+1 elements, returns the element value, + /// otherwise returns defaultValue. + Value get(UInt index, const Value& defaultValue) const; + /// Return true if index < size(). + bool isValidIndex(UInt index) const; + /// \brief Append value to array at the end. + /// + /// Equivalent to jsonvalue[jsonvalue.size()] = value; + Value& append(const Value& value); + + /// Access an object value by name, create a null member if it does not exist. + Value& operator[](const char* key); + /// Access an object value by name, returns null if there is no member with that name. + const Value& operator[](const char* key) const; + /// Access an object value by name, create a null member if it does not exist. + Value& operator[](const std::string& key); + /// Access an object value by name, returns null if there is no member with that name. + const Value& operator[](const std::string& key) const; + /** \brief Access an object value by name, create a null member if it does not exist. + + * If the object as no entry for that name, then the member name used to store + * the new entry is not duplicated. + * Example of use: + * \code + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ + Value& operator[](const StaticString& key); +#ifdef JSON_USE_CPPTL + /// Access an object value by name, create a null member if it does not exist. + Value& operator[](const CppTL::ConstString& key); + /// Access an object value by name, returns null if there is no member with that name. + const Value& operator[](const CppTL::ConstString& key) const; +#endif + /// Return the member named key if it exist, defaultValue otherwise. + Value get(const char* key, const Value& defaultValue) const; + /// Return the member named key if it exist, defaultValue otherwise. + Value get(const std::string& key, const Value& defaultValue) const; +#ifdef JSON_USE_CPPTL + /// Return the member named key if it exist, defaultValue otherwise. + Value get(const CppTL::ConstString& key, const Value& defaultValue) const; +#endif + /// \brief Remove and return the named member. + /// + /// Do nothing if it did not exist. + /// \return the removed Value, or null. + /// \pre type() is objectValue or nullValue + /// \post type() is unchanged + Value removeMember(const char* key); + /// Same as removeMember(const char*) + Value removeMember(const std::string& key); + + /// Return true if the object has a member named key. + bool isMember(const char* key) const; + /// Return true if the object has a member named key. + bool isMember(const std::string& key) const; +#ifdef JSON_USE_CPPTL + /// Return true if the object has a member named key. + bool isMember(const CppTL::ConstString& key) const; +#endif - /// Comments must be //... or /* ... */ - void setComment( const char *comment, - CommentPlacement placement ); - /// Comments must be //... or /* ... */ - void setComment( const std::string &comment, - CommentPlacement placement ); - bool hasComment( CommentPlacement placement ) const; - /// Include delimiters and embedded newlines. - std::string getComment( CommentPlacement placement ) const; + /// \brief Return a list of the member names. + /// + /// If null, return an empty list. + /// \pre type() is objectValue or nullValue + /// \post if type() was nullValue, it remains nullValue + Members getMemberNames() const; - std::string toStyledString() const; + //# ifdef JSON_USE_CPPTL + // EnumMemberNames enumMemberNames() const; + // EnumValues enumValues() const; + //# endif - const_iterator begin() const; - const_iterator end() const; + /// Comments must be //... or /* ... */ + void setComment(const char* comment, CommentPlacement placement); + /// Comments must be //... or /* ... */ + void setComment(const std::string& comment, CommentPlacement placement); + bool hasComment(CommentPlacement placement) const; + /// Include delimiters and embedded newlines. + std::string getComment(CommentPlacement placement) const; - iterator begin(); - iterator end(); + std::string toStyledString() const; - private: - Value &resolveReference( const char *key, - bool isStatic ); + const_iterator begin() const; + const_iterator end() const; -# ifdef JSON_VALUE_USE_INTERNAL_MAP - inline bool isItemAvailable() const + iterator begin(); + iterator end(); + +private: + Value& resolveReference(const char* key, bool isStatic); + +#ifdef JSON_VALUE_USE_INTERNAL_MAP + inline bool isItemAvailable() const { return itemIsUsed_ == 0; } + + inline void setItemUsed(bool isUsed = true) { itemIsUsed_ = isUsed ? 1 : 0; } + + inline bool isMemberNameStatic() const { return memberNameIsStatic_ == 0; } + + inline void setMemberNameIsStatic(bool isStatic) { memberNameIsStatic_ = isStatic ? 1 : 0; } +#endif // # ifdef JSON_VALUE_USE_INTERNAL_MAP + +private: + struct CommentInfo + { + CommentInfo(); + ~CommentInfo(); + + void setComment(const char* text); + + char* comment_; + }; + + // struct MemberNamesTransform + //{ + // typedef const char *result_type; + // const char *operator()( const CZString &name ) const + // { + // return name.c_str(); + // } + //}; + + union ValueHolder + { + Int int_; + UInt uint_; + double real_; + bool bool_; + char* string_; +#ifdef JSON_VALUE_USE_INTERNAL_MAP + ValueInternalArray* array_; + ValueInternalMap* map_; +#else + ObjectValues* map_; +#endif + } value_; + ValueType type_ : 8; + int allocated_ : 1; // Notes: if declared as bool, bitfield is useless. +#ifdef JSON_VALUE_USE_INTERNAL_MAP + unsigned int itemIsUsed_ : 1; // used by the ValueInternalMap container. + int memberNameIsStatic_ : 1; // used by the ValueInternalMap container. +#endif + CommentInfo* comments_; +}; + +/** \brief Experimental and untested: represents an element of the "path" to access a node. + */ +class PathArgument +{ +public: + friend class Path; + + PathArgument(); + PathArgument(UInt index); + PathArgument(const char* key); + PathArgument(const std::string& key); + +private: + enum Kind + { + kindNone = 0, + kindIndex, + kindKey + }; + std::string key_; + UInt index_; + Kind kind_; +}; + +/** \brief Experimental and untested: represents a "path" to access a node. + * + * Syntax: + * - "." => root node + * - ".[n]" => elements at index 'n' of root node (an array value) + * - ".name" => member named 'name' of root node (an object value) + * - ".name1.name2.name3" + * - ".[0][1][2].name1[3]" + * - ".%" => member name is provided as parameter + * - ".[%]" => index is provied as parameter + */ +class Path +{ +public: + Path(const std::string& path, + const PathArgument& a1 = PathArgument(), + const PathArgument& a2 = PathArgument(), + const PathArgument& a3 = PathArgument(), + const PathArgument& a4 = PathArgument(), + const PathArgument& a5 = PathArgument()); + + const Value& resolve(const Value& root) const; + Value resolve(const Value& root, const Value& defaultValue) const; + /// Creates the "path" to access the specified node and returns a reference on the node. + Value& make(Value& root) const; + +private: + typedef std::vector InArgs; + typedef std::vector Args; + + void makePath(const std::string& path, const InArgs& in); + void + addPathInArg(const std::string& path, const InArgs& in, InArgs::const_iterator& itInArg, PathArgument::Kind kind); + void invalidPath(const std::string& path, int location); + + Args args_; +}; + +/** \brief Experimental do not use: Allocator to customize member name and string value memory management done by Value. + * + * - makeMemberName() and releaseMemberName() are called to respectively duplicate and + * free an Json::objectValue member name. + * - duplicateStringValue() and releaseStringValue() are called similarly to + * duplicate and free a Json::stringValue value. + */ +class ValueAllocator +{ +public: + enum + { + unknown = (unsigned)-1 + }; + + virtual ~ValueAllocator(); + + virtual char* makeMemberName(const char* memberName) = 0; + virtual void releaseMemberName(char* memberName) = 0; + virtual char* duplicateStringValue(const char* value, unsigned int length = unknown) = 0; + virtual void releaseStringValue(char* value) = 0; +}; + +#ifdef JSON_VALUE_USE_INTERNAL_MAP +/** \brief Allocator to customize Value internal map. + * Below is an example of a simple implementation (default implementation actually + * use memory pool for speed). + * \code + class DefaultValueMapAllocator : public ValueMapAllocator + { + public: // overridden from ValueMapAllocator + virtual ValueInternalMap *newMap() { - return itemIsUsed_ == 0; + return new ValueInternalMap(); } - inline void setItemUsed( bool isUsed = true ) + virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) { - itemIsUsed_ = isUsed ? 1 : 0; + return new ValueInternalMap( other ); } - inline bool isMemberNameStatic() const + virtual void destructMap( ValueInternalMap *map ) { - return memberNameIsStatic_ == 0; + delete map; } - inline void setMemberNameIsStatic( bool isStatic ) + virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) { - memberNameIsStatic_ = isStatic ? 1 : 0; + return new ValueInternalLink[size]; } -# endif // # ifdef JSON_VALUE_USE_INTERNAL_MAP - private: - struct CommentInfo + virtual void releaseMapBuckets( ValueInternalLink *links ) { - CommentInfo(); - ~CommentInfo(); - - void setComment( const char *text ); - - char *comment_; - }; + delete [] links; + } - //struct MemberNamesTransform - //{ - // typedef const char *result_type; - // const char *operator()( const CZString &name ) const - // { - // return name.c_str(); - // } - //}; + virtual ValueInternalLink *allocateMapLink() + { + return new ValueInternalLink(); + } - union ValueHolder + virtual void releaseMapLink( ValueInternalLink *link ) { - Int int_; - UInt uint_; - double real_; - bool bool_; - char *string_; -# ifdef JSON_VALUE_USE_INTERNAL_MAP - ValueInternalArray *array_; - ValueInternalMap *map_; -#else - ObjectValues *map_; -# endif - } value_; - ValueType type_ : 8; - int allocated_ : 1; // Notes: if declared as bool, bitfield is useless. -# ifdef JSON_VALUE_USE_INTERNAL_MAP - unsigned int itemIsUsed_ : 1; // used by the ValueInternalMap container. - int memberNameIsStatic_ : 1; // used by the ValueInternalMap container. -# endif - CommentInfo *comments_; + delete link; + } }; + * \endcode + */ +class JSON_API ValueMapAllocator +{ +public: + virtual ~ValueMapAllocator(); + virtual ValueInternalMap* newMap() = 0; + virtual ValueInternalMap* newMapCopy(const ValueInternalMap& other) = 0; + virtual void destructMap(ValueInternalMap* map) = 0; + virtual ValueInternalLink* allocateMapBuckets(unsigned int size) = 0; + virtual void releaseMapBuckets(ValueInternalLink* links) = 0; + virtual ValueInternalLink* allocateMapLink() = 0; + virtual void releaseMapLink(ValueInternalLink* link) = 0; +}; +/** \brief ValueInternalMap hash-map bucket chain link (for internal use only). + * \internal previous_ & next_ allows for bidirectional traversal. + */ +class JSON_API ValueInternalLink +{ +public: + enum + { + itemPerLink = 6 + }; // sizeof(ValueInternalLink) = 128 on 32 bits architecture. + enum InternalFlags + { + flagAvailable = 0, + flagUsed = 1 + }; + + ValueInternalLink(); + + ~ValueInternalLink(); + + Value items_[itemPerLink]; + char* keys_[itemPerLink]; + ValueInternalLink* previous_; + ValueInternalLink* next_; +}; - /** \brief Experimental and untested: represents an element of the "path" to access a node. - */ - class PathArgument - { - public: - friend class Path; +/** \brief A linked page based hash-table implementation used internally by Value. + * \internal ValueInternalMap is a tradional bucket based hash-table, with a linked + * list in each bucket to handle collision. There is an addional twist in that + * each node of the collision linked list is a page containing a fixed amount of + * value. This provides a better compromise between memory usage and speed. + * + * Each bucket is made up of a chained list of ValueInternalLink. The last + * link of a given bucket can be found in the 'previous_' field of the following bucket. + * The last link of the last bucket is stored in tailLink_ as it has no following bucket. + * Only the last link of a bucket may contains 'available' item. The last link always + * contains at least one element unless is it the bucket one very first link. + */ +class JSON_API ValueInternalMap +{ + friend class ValueIteratorBase; + friend class Value; - PathArgument(); - PathArgument( UInt index ); - PathArgument( const char *key ); - PathArgument( const std::string &key ); +public: + typedef unsigned int HashKey; + typedef unsigned int BucketIndex; - private: - enum Kind - { - kindNone = 0, - kindIndex, - kindKey - }; - std::string key_; - UInt index_; - Kind kind_; - }; +#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + struct IteratorState + { + IteratorState() : map_(0), link_(0), itemIndex_(0), bucketIndex_(0) {} + ValueInternalMap* map_; + ValueInternalLink* link_; + BucketIndex itemIndex_; + BucketIndex bucketIndex_; + }; +#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - /** \brief Experimental and untested: represents a "path" to access a node. - * - * Syntax: - * - "." => root node - * - ".[n]" => elements at index 'n' of root node (an array value) - * - ".name" => member named 'name' of root node (an object value) - * - ".name1.name2.name3" - * - ".[0][1][2].name1[3]" - * - ".%" => member name is provided as parameter - * - ".[%]" => index is provied as parameter - */ - class Path - { - public: - Path( const std::string &path, - const PathArgument &a1 = PathArgument(), - const PathArgument &a2 = PathArgument(), - const PathArgument &a3 = PathArgument(), - const PathArgument &a4 = PathArgument(), - const PathArgument &a5 = PathArgument() ); - - const Value &resolve( const Value &root ) const; - Value resolve( const Value &root, - const Value &defaultValue ) const; - /// Creates the "path" to access the specified node and returns a reference on the node. - Value &make( Value &root ) const; - - private: - typedef std::vector InArgs; - typedef std::vector Args; - - void makePath( const std::string &path, - const InArgs &in ); - void addPathInArg( const std::string &path, - const InArgs &in, - InArgs::const_iterator &itInArg, - PathArgument::Kind kind ); - void invalidPath( const std::string &path, - int location ); - - Args args_; - }; + ValueInternalMap(); + ValueInternalMap(const ValueInternalMap& other); + ValueInternalMap& operator=(const ValueInternalMap& other); + ~ValueInternalMap(); - /** \brief Experimental do not use: Allocator to customize member name and string value memory management done by Value. - * - * - makeMemberName() and releaseMemberName() are called to respectively duplicate and - * free an Json::objectValue member name. - * - duplicateStringValue() and releaseStringValue() are called similarly to - * duplicate and free a Json::stringValue value. - */ - class ValueAllocator - { - public: - enum { unknown = (unsigned)-1 }; + void swap(ValueInternalMap& other); - virtual ~ValueAllocator(); + BucketIndex size() const; - virtual char *makeMemberName( const char *memberName ) = 0; - virtual void releaseMemberName( char *memberName ) = 0; - virtual char *duplicateStringValue( const char *value, - unsigned int length = unknown ) = 0; - virtual void releaseStringValue( char *value ) = 0; - }; + void clear(); -#ifdef JSON_VALUE_USE_INTERNAL_MAP - /** \brief Allocator to customize Value internal map. - * Below is an example of a simple implementation (default implementation actually - * use memory pool for speed). - * \code - class DefaultValueMapAllocator : public ValueMapAllocator - { - public: // overridden from ValueMapAllocator - virtual ValueInternalMap *newMap() - { - return new ValueInternalMap(); - } - - virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) - { - return new ValueInternalMap( other ); - } - - virtual void destructMap( ValueInternalMap *map ) - { - delete map; - } - - virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) - { - return new ValueInternalLink[size]; - } - - virtual void releaseMapBuckets( ValueInternalLink *links ) - { - delete [] links; - } - - virtual ValueInternalLink *allocateMapLink() - { - return new ValueInternalLink(); - } - - virtual void releaseMapLink( ValueInternalLink *link ) - { - delete link; - } - }; - * \endcode - */ - class JSON_API ValueMapAllocator - { - public: - virtual ~ValueMapAllocator(); - virtual ValueInternalMap *newMap() = 0; - virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) = 0; - virtual void destructMap( ValueInternalMap *map ) = 0; - virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) = 0; - virtual void releaseMapBuckets( ValueInternalLink *links ) = 0; - virtual ValueInternalLink *allocateMapLink() = 0; - virtual void releaseMapLink( ValueInternalLink *link ) = 0; - }; + bool reserveDelta(BucketIndex growth); - /** \brief ValueInternalMap hash-map bucket chain link (for internal use only). - * \internal previous_ & next_ allows for bidirectional traversal. - */ - class JSON_API ValueInternalLink - { - public: - enum { itemPerLink = 6 }; // sizeof(ValueInternalLink) = 128 on 32 bits architecture. - enum InternalFlags { - flagAvailable = 0, - flagUsed = 1 - }; + bool reserve(BucketIndex newItemCount); - ValueInternalLink(); + const Value* find(const char* key) const; - ~ValueInternalLink(); + Value* find(const char* key); - Value items_[itemPerLink]; - char *keys_[itemPerLink]; - ValueInternalLink *previous_; - ValueInternalLink *next_; - }; + Value& resolveReference(const char* key, bool isStatic); + void remove(const char* key); - /** \brief A linked page based hash-table implementation used internally by Value. - * \internal ValueInternalMap is a tradional bucket based hash-table, with a linked - * list in each bucket to handle collision. There is an addional twist in that - * each node of the collision linked list is a page containing a fixed amount of - * value. This provides a better compromise between memory usage and speed. - * - * Each bucket is made up of a chained list of ValueInternalLink. The last - * link of a given bucket can be found in the 'previous_' field of the following bucket. - * The last link of the last bucket is stored in tailLink_ as it has no following bucket. - * Only the last link of a bucket may contains 'available' item. The last link always - * contains at least one element unless is it the bucket one very first link. - */ - class JSON_API ValueInternalMap - { - friend class ValueIteratorBase; - friend class Value; - public: - typedef unsigned int HashKey; - typedef unsigned int BucketIndex; - -# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - struct IteratorState - { - IteratorState() - : map_(0) - , link_(0) - , itemIndex_(0) - , bucketIndex_(0) - { - } - ValueInternalMap *map_; - ValueInternalLink *link_; - BucketIndex itemIndex_; - BucketIndex bucketIndex_; - }; -# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + void doActualRemove(ValueInternalLink* link, BucketIndex index, BucketIndex bucketIndex); - ValueInternalMap(); - ValueInternalMap( const ValueInternalMap &other ); - ValueInternalMap &operator =( const ValueInternalMap &other ); - ~ValueInternalMap(); + ValueInternalLink*& getLastLinkInBucket(BucketIndex bucketIndex); - void swap( ValueInternalMap &other ); + Value& setNewItem(const char* key, bool isStatic, ValueInternalLink* link, BucketIndex index); - BucketIndex size() const; + Value& unsafeAdd(const char* key, bool isStatic, HashKey hashedKey); - void clear(); + HashKey hash(const char* key) const; - bool reserveDelta( BucketIndex growth ); + int compare(const ValueInternalMap& other) const; - bool reserve( BucketIndex newItemCount ); +private: + void makeBeginIterator(IteratorState& it) const; + void makeEndIterator(IteratorState& it) const; + static bool equals(const IteratorState& x, const IteratorState& other); + static void increment(IteratorState& iterator); + static void incrementBucket(IteratorState& iterator); + static void decrement(IteratorState& iterator); + static const char* key(const IteratorState& iterator); + static const char* key(const IteratorState& iterator, bool& isStatic); + static Value& value(const IteratorState& iterator); + static int distance(const IteratorState& x, const IteratorState& y); - const Value *find( const char *key ) const; +private: + ValueInternalLink* buckets_; + ValueInternalLink* tailLink_; + BucketIndex bucketsSize_; + BucketIndex itemCount_; +}; - Value *find( const char *key ); +/** \brief A simplified deque implementation used internally by Value. + * \internal + * It is based on a list of fixed "page", each page contains a fixed number of items. + * Instead of using a linked-list, a array of pointer is used for fast item look-up. + * Look-up for an element is as follow: + * - compute page index: pageIndex = itemIndex / itemsPerPage + * - look-up item in page: pages_[pageIndex][itemIndex % itemsPerPage] + * + * Insertion is amortized constant time (only the array containing the index of pointers + * need to be reallocated when items are appended). + */ +class JSON_API ValueInternalArray +{ + friend class Value; + friend class ValueIteratorBase; - Value &resolveReference( const char *key, - bool isStatic ); +public: + enum + { + itemsPerPage = 8 + }; // should be a power of 2 for fast divide and modulo. + typedef Value::ArrayIndex ArrayIndex; + typedef unsigned int PageIndex; - void remove( const char *key ); +#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + struct IteratorState // Must be a POD + { + IteratorState() : array_(0), currentPageIndex_(0), currentItemIndex_(0) {} + ValueInternalArray* array_; + Value** currentPageIndex_; + unsigned int currentItemIndex_; + }; +#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - void doActualRemove( ValueInternalLink *link, - BucketIndex index, - BucketIndex bucketIndex ); + ValueInternalArray(); + ValueInternalArray(const ValueInternalArray& other); + ValueInternalArray& operator=(const ValueInternalArray& other); + ~ValueInternalArray(); + void swap(ValueInternalArray& other); - ValueInternalLink *&getLastLinkInBucket( BucketIndex bucketIndex ); + void clear(); + void resize(ArrayIndex newSize); - Value &setNewItem( const char *key, - bool isStatic, - ValueInternalLink *link, - BucketIndex index ); + Value& resolveReference(ArrayIndex index); - Value &unsafeAdd( const char *key, - bool isStatic, - HashKey hashedKey ); + Value* find(ArrayIndex index) const; - HashKey hash( const char *key ) const; + ArrayIndex size() const; - int compare( const ValueInternalMap &other ) const; + int compare(const ValueInternalArray& other) const; - private: - void makeBeginIterator( IteratorState &it ) const; - void makeEndIterator( IteratorState &it ) const; - static bool equals( const IteratorState &x, const IteratorState &other ); - static void increment( IteratorState &iterator ); - static void incrementBucket( IteratorState &iterator ); - static void decrement( IteratorState &iterator ); - static const char *key( const IteratorState &iterator ); - static const char *key( const IteratorState &iterator, bool &isStatic ); - static Value &value( const IteratorState &iterator ); - static int distance( const IteratorState &x, const IteratorState &y ); +private: + static bool equals(const IteratorState& x, const IteratorState& other); + static void increment(IteratorState& iterator); + static void decrement(IteratorState& iterator); + static Value& dereference(const IteratorState& iterator); + static Value& unsafeDereference(const IteratorState& iterator); + static int distance(const IteratorState& x, const IteratorState& y); + static ArrayIndex indexOf(const IteratorState& iterator); + void makeBeginIterator(IteratorState& it) const; + void makeEndIterator(IteratorState& it) const; + void makeIterator(IteratorState& it, ArrayIndex index) const; - private: - ValueInternalLink *buckets_; - ValueInternalLink *tailLink_; - BucketIndex bucketsSize_; - BucketIndex itemCount_; - }; + void makeIndexValid(ArrayIndex index); - /** \brief A simplified deque implementation used internally by Value. - * \internal - * It is based on a list of fixed "page", each page contains a fixed number of items. - * Instead of using a linked-list, a array of pointer is used for fast item look-up. - * Look-up for an element is as follow: - * - compute page index: pageIndex = itemIndex / itemsPerPage - * - look-up item in page: pages_[pageIndex][itemIndex % itemsPerPage] - * - * Insertion is amortized constant time (only the array containing the index of pointers - * need to be reallocated when items are appended). - */ - class JSON_API ValueInternalArray - { - friend class Value; - friend class ValueIteratorBase; - public: - enum { itemsPerPage = 8 }; // should be a power of 2 for fast divide and modulo. - typedef Value::ArrayIndex ArrayIndex; - typedef unsigned int PageIndex; - -# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - struct IteratorState // Must be a POD - { - IteratorState() - : array_(0) - , currentPageIndex_(0) - , currentItemIndex_(0) - { - } - ValueInternalArray *array_; - Value **currentPageIndex_; - unsigned int currentItemIndex_; - }; -# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - - ValueInternalArray(); - ValueInternalArray( const ValueInternalArray &other ); - ValueInternalArray &operator =( const ValueInternalArray &other ); - ~ValueInternalArray(); - void swap( ValueInternalArray &other ); - - void clear(); - void resize( ArrayIndex newSize ); - - Value &resolveReference( ArrayIndex index ); - - Value *find( ArrayIndex index ) const; - - ArrayIndex size() const; - - int compare( const ValueInternalArray &other ) const; - - private: - static bool equals( const IteratorState &x, const IteratorState &other ); - static void increment( IteratorState &iterator ); - static void decrement( IteratorState &iterator ); - static Value &dereference( const IteratorState &iterator ); - static Value &unsafeDereference( const IteratorState &iterator ); - static int distance( const IteratorState &x, const IteratorState &y ); - static ArrayIndex indexOf( const IteratorState &iterator ); - void makeBeginIterator( IteratorState &it ) const; - void makeEndIterator( IteratorState &it ) const; - void makeIterator( IteratorState &it, ArrayIndex index ) const; - - void makeIndexValid( ArrayIndex index ); - - Value **pages_; - ArrayIndex size_; - PageIndex pageCount_; - }; + Value** pages_; + ArrayIndex size_; + PageIndex pageCount_; +}; - /** \brief Experimental: do not use. Allocator to customize Value internal array. - * Below is an example of a simple implementation (actual implementation use - * memory pool). - \code +/** \brief Experimental: do not use. Allocator to customize Value internal array. + * Below is an example of a simple implementation (actual implementation use + * memory pool). + \code class DefaultValueArrayAllocator : public ValueArrayAllocator { public: // overridden from ValueArrayAllocator - virtual ~DefaultValueArrayAllocator() - { - } +virtual ~DefaultValueArrayAllocator() +{ +} - virtual ValueInternalArray *newArray() - { - return new ValueInternalArray(); - } +virtual ValueInternalArray *newArray() +{ + return new ValueInternalArray(); +} - virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) - { - return new ValueInternalArray( other ); - } +virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) +{ + return new ValueInternalArray( other ); +} - virtual void destruct( ValueInternalArray *array ) - { - delete array; - } +virtual void destruct( ValueInternalArray *array ) +{ + delete array; +} - virtual void reallocateArrayPageIndex( Value **&indexes, - ValueInternalArray::PageIndex &indexCount, - ValueInternalArray::PageIndex minNewIndexCount ) - { - ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1; - if ( minNewIndexCount > newIndexCount ) - newIndexCount = minNewIndexCount; - void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount ); - if ( !newIndexes ) - throw std::bad_alloc(); - indexCount = newIndexCount; - indexes = static_cast( newIndexes ); - } - virtual void releaseArrayPageIndex( Value **indexes, - ValueInternalArray::PageIndex indexCount ) - { - if ( indexes ) - free( indexes ); - } +virtual void reallocateArrayPageIndex( Value **&indexes, + ValueInternalArray::PageIndex &indexCount, + ValueInternalArray::PageIndex minNewIndexCount ) +{ + ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1; + if ( minNewIndexCount > newIndexCount ) + newIndexCount = minNewIndexCount; + void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount ); + if ( !newIndexes ) + throw std::bad_alloc(); + indexCount = newIndexCount; + indexes = static_cast( newIndexes ); +} +virtual void releaseArrayPageIndex( Value **indexes, + ValueInternalArray::PageIndex indexCount ) +{ + if ( indexes ) + free( indexes ); +} - virtual Value *allocateArrayPage() - { - return static_cast( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) ); - } +virtual Value *allocateArrayPage() +{ + return static_cast( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) ); +} - virtual void releaseArrayPage( Value *value ) - { - if ( value ) - free( value ); - } +virtual void releaseArrayPage( Value *value ) +{ + if ( value ) + free( value ); +} +}; + \endcode + */ +class JSON_API ValueArrayAllocator +{ +public: + virtual ~ValueArrayAllocator(); + virtual ValueInternalArray* newArray() = 0; + virtual ValueInternalArray* newArrayCopy(const ValueInternalArray& other) = 0; + virtual void destructArray(ValueInternalArray* array) = 0; + /** \brief Reallocate array page index. + * Reallocates an array of pointer on each page. + * \param indexes [input] pointer on the current index. May be \c NULL. + * [output] pointer on the new index of at least + * \a minNewIndexCount pages. + * \param indexCount [input] current number of pages in the index. + * [output] number of page the reallocated index can handle. + * \b MUST be >= \a minNewIndexCount. + * \param minNewIndexCount Minimum number of page the new index must be able to + * handle. + */ + virtual void reallocateArrayPageIndex(Value**& indexes, + ValueInternalArray::PageIndex& indexCount, + ValueInternalArray::PageIndex minNewIndexCount) = 0; + virtual void releaseArrayPageIndex(Value** indexes, ValueInternalArray::PageIndex indexCount) = 0; + virtual Value* allocateArrayPage() = 0; + virtual void releaseArrayPage(Value* value) = 0; }; - \endcode - */ - class JSON_API ValueArrayAllocator - { - public: - virtual ~ValueArrayAllocator(); - virtual ValueInternalArray *newArray() = 0; - virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) = 0; - virtual void destructArray( ValueInternalArray *array ) = 0; - /** \brief Reallocate array page index. - * Reallocates an array of pointer on each page. - * \param indexes [input] pointer on the current index. May be \c NULL. - * [output] pointer on the new index of at least - * \a minNewIndexCount pages. - * \param indexCount [input] current number of pages in the index. - * [output] number of page the reallocated index can handle. - * \b MUST be >= \a minNewIndexCount. - * \param minNewIndexCount Minimum number of page the new index must be able to - * handle. - */ - virtual void reallocateArrayPageIndex( Value **&indexes, - ValueInternalArray::PageIndex &indexCount, - ValueInternalArray::PageIndex minNewIndexCount ) = 0; - virtual void releaseArrayPageIndex( Value **indexes, - ValueInternalArray::PageIndex indexCount ) = 0; - virtual Value *allocateArrayPage() = 0; - virtual void releaseArrayPage( Value *value ) = 0; - }; #endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP +/** \brief base class for Value iterators. + * + */ +class ValueIteratorBase +{ +public: + typedef unsigned int size_t; + typedef int difference_type; + typedef ValueIteratorBase SelfType; - /** \brief base class for Value iterators. - * - */ - class ValueIteratorBase - { - public: - typedef unsigned int size_t; - typedef int difference_type; - typedef ValueIteratorBase SelfType; - - ValueIteratorBase(); + ValueIteratorBase(); #ifndef JSON_VALUE_USE_INTERNAL_MAP - explicit ValueIteratorBase( const Value::ObjectValues::iterator ¤t ); + explicit ValueIteratorBase(const Value::ObjectValues::iterator& current); #else - ValueIteratorBase( const ValueInternalArray::IteratorState &state ); - ValueIteratorBase( const ValueInternalMap::IteratorState &state ); + ValueIteratorBase(const ValueInternalArray::IteratorState& state); + ValueIteratorBase(const ValueInternalMap::IteratorState& state); #endif - bool operator ==( const SelfType &other ) const - { - return isEqual( other ); - } - - bool operator !=( const SelfType &other ) const - { - return !isEqual( other ); - } + bool operator==(const SelfType& other) const { return isEqual(other); } - difference_type operator -( const SelfType &other ) const - { - return computeDistance( other ); - } + bool operator!=(const SelfType& other) const { return !isEqual(other); } - /// Return either the index or the member name of the referenced value as a Value. - Value key() const; + difference_type operator-(const SelfType& other) const { return computeDistance(other); } - /// Return the index of the referenced Value. -1 if it is not an arrayValue. - UInt index() const; + /// Return either the index or the member name of the referenced value as a Value. + Value key() const; - /// Return the member name of the referenced Value. "" if it is not an objectValue. - const char *memberName() const; + /// Return the index of the referenced Value. -1 if it is not an arrayValue. + UInt index() const; - protected: - Value &deref() const; + /// Return the member name of the referenced Value. "" if it is not an objectValue. + const char* memberName() const; - void increment(); +protected: + Value& deref() const; - void decrement(); + void increment(); - difference_type computeDistance( const SelfType &other ) const; + void decrement(); - bool isEqual( const SelfType &other ) const; + difference_type computeDistance(const SelfType& other) const; - void copy( const SelfType &other ); + bool isEqual(const SelfType& other) const; - private: -#ifndef JSON_VALUE_USE_INTERNAL_MAP - Value::ObjectValues::iterator current_; - // Indicates that iterator is for a null value. - bool isNull_; -#else - union - { - ValueInternalArray::IteratorState array_; - ValueInternalMap::IteratorState map_; - } iterator_; - bool isArray_; -#endif - }; + void copy(const SelfType& other); - /** \brief const iterator for object and array value. - * - */ - class ValueConstIterator : public ValueIteratorBase - { - friend class Value; - public: - typedef unsigned int size_t; - typedef int difference_type; - typedef const Value &reference; - typedef const Value *pointer; - typedef ValueConstIterator SelfType; - - ValueConstIterator(); - private: - /*! \internal Use by Value to create an iterator. - */ +private: #ifndef JSON_VALUE_USE_INTERNAL_MAP - explicit ValueConstIterator( const Value::ObjectValues::iterator ¤t ); + Value::ObjectValues::iterator current_; + // Indicates that iterator is for a null value. + bool isNull_; #else - ValueConstIterator( const ValueInternalArray::IteratorState &state ); - ValueConstIterator( const ValueInternalMap::IteratorState &state ); + union + { + ValueInternalArray::IteratorState array_; + ValueInternalMap::IteratorState map_; + } iterator_; + bool isArray_; #endif - public: - SelfType &operator =( const ValueIteratorBase &other ); - - SelfType operator++( int ) - { - SelfType temp( *this ); - ++*this; - return temp; - } - - SelfType operator--( int ) - { - SelfType temp( *this ); - --*this; - return temp; - } - - SelfType &operator--() - { - decrement(); - return *this; - } +}; - SelfType &operator++() - { - increment(); - return *this; - } +/** \brief const iterator for object and array value. + * + */ +class ValueConstIterator : public ValueIteratorBase +{ + friend class Value; - reference operator *() const - { - return deref(); - } - }; +public: + typedef unsigned int size_t; + typedef int difference_type; + typedef const Value& reference; + typedef const Value* pointer; + typedef ValueConstIterator SelfType; + ValueConstIterator(); - /** \brief Iterator for object and array value. - */ - class ValueIterator : public ValueIteratorBase - { - friend class Value; - public: - typedef unsigned int size_t; - typedef int difference_type; - typedef Value &reference; - typedef Value *pointer; - typedef ValueIterator SelfType; - - ValueIterator(); - ValueIterator( const ValueConstIterator &other ); - ValueIterator( const ValueIterator &other ); - private: - /*! \internal Use by Value to create an iterator. - */ +private: + /*! \internal Use by Value to create an iterator. + */ #ifndef JSON_VALUE_USE_INTERNAL_MAP - explicit ValueIterator( const Value::ObjectValues::iterator ¤t ); + explicit ValueConstIterator(const Value::ObjectValues::iterator& current); #else - ValueIterator( const ValueInternalArray::IteratorState &state ); - ValueIterator( const ValueInternalMap::IteratorState &state ); + ValueConstIterator(const ValueInternalArray::IteratorState& state); + ValueConstIterator(const ValueInternalMap::IteratorState& state); #endif - public: - - SelfType &operator =( const SelfType &other ); - - SelfType operator++( int ) - { - SelfType temp( *this ); - ++*this; - return temp; - } - - SelfType operator--( int ) - { - SelfType temp( *this ); - --*this; - return temp; - } - - SelfType &operator--() - { - decrement(); - return *this; - } - - SelfType &operator++() - { - increment(); - return *this; - } - - reference operator *() const - { - return deref(); - } - }; +public: + SelfType& operator=(const ValueIteratorBase& other); + + SelfType operator++(int) + { + SelfType temp(*this); + ++*this; + return temp; + } + + SelfType operator--(int) + { + SelfType temp(*this); + --*this; + return temp; + } + + SelfType& operator--() + { + decrement(); + return *this; + } + + SelfType& operator++() + { + increment(); + return *this; + } + + reference operator*() const { return deref(); } +}; +/** \brief Iterator for object and array value. + */ +class ValueIterator : public ValueIteratorBase +{ + friend class Value; + +public: + typedef unsigned int size_t; + typedef int difference_type; + typedef Value& reference; + typedef Value* pointer; + typedef ValueIterator SelfType; + + ValueIterator(); + ValueIterator(const ValueConstIterator& other); + ValueIterator(const ValueIterator& other); + +private: + /*! \internal Use by Value to create an iterator. + */ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + explicit ValueIterator(const Value::ObjectValues::iterator& current); +#else + ValueIterator(const ValueInternalArray::IteratorState& state); + ValueIterator(const ValueInternalMap::IteratorState& state); +#endif +public: + SelfType& operator=(const SelfType& other); + + SelfType operator++(int) + { + SelfType temp(*this); + ++*this; + return temp; + } + + SelfType operator--(int) + { + SelfType temp(*this); + --*this; + return temp; + } + + SelfType& operator--() + { + decrement(); + return *this; + } + + SelfType& operator++() + { + increment(); + return *this; + } + + reference operator*() const { return deref(); } +}; } // namespace Json - #endif // CPPTL_JSON_H_INCLUDED diff --git a/ext_libs/json/json/writer.h b/ext_libs/json/json/writer.h old mode 100755 new mode 100644 index d04ecbf2..3f94cd58 --- a/ext_libs/json/json/writer.h +++ b/ext_libs/json/json/writer.h @@ -4,176 +4,174 @@ // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE #ifndef JSON_WRITER_H_INCLUDED -# define JSON_WRITER_H_INCLUDED - -# include "value.h" -# include -# include -# include - -namespace Json { - - class Value; - - /** \brief Abstract class for writers. - */ - class JSON_API Writer - { - public: - virtual ~Writer(); - - virtual std::string write( const Value &root, bool noNewLine=false ) = 0; - }; - - /** \brief Outputs a Value in JSON format without formatting (not human friendly). - * - * The JSON document is written in a single line. It is not intended for 'human' consumption, - * but may be usefull to support feature such as RPC where bandwith is limited. - * \sa Reader, Value - */ - class JSON_API FastWriter : public Writer - { - public: - FastWriter(); - virtual ~FastWriter(){} - - void enableYAMLCompatibility(); - - public: // overridden from Writer - virtual std::string write( const Value &root, bool noNewLine=false ); - - private: - void writeValue( const Value &value ); - - std::string document_; - bool yamlCompatiblityEnabled_; - }; - - /** \brief Writes a Value in JSON format in a human friendly way. - * - * The rules for line break and indent are as follow: - * - Object value: - * - if empty then print {} without indent and line break - * - if not empty the print '{', line break & indent, print one value per line - * and then unindent and line break and print '}'. - * - Array value: - * - if empty then print [] without indent and line break - * - if the array contains no object value, empty array or some other value types, - * and all the values fit on one lines, then print the array on a single line. - * - otherwise, it the values do not fit on one line, or the array contains - * object or non empty array, then print one value per line. - * - * If the Value have comments then they are outputed according to their #CommentPlacement. - * - * \sa Reader, Value, Value::setComment() - */ - class JSON_API StyledWriter: public Writer - { - public: - StyledWriter(); - virtual ~StyledWriter(){} - - public: // overridden from Writer - /** \brief Serialize a Value in JSON format. - * \param root Value to serialize. - * \return String containing the JSON document that represents the root value. - */ - virtual std::string write( const Value &root, bool noNewLine=false ); - - private: - void writeValue( const Value &value ); - void writeArrayValue( const Value &value ); - bool isMultineArray( const Value &value ); - void pushValue( const std::string &value ); - void writeIndent(); - void writeWithIndent( const std::string &value ); - void indent(); - void unindent(); - void writeCommentBeforeValue( const Value &root ); - void writeCommentAfterValueOnSameLine( const Value &root ); - bool hasCommentForValue( const Value &value ); - static std::string normalizeEOL( const std::string &text ); - - typedef std::vector ChildValues; - - ChildValues childValues_; - std::string document_; - std::string indentString_; - int rightMargin_; - int indentSize_; - bool addChildValues_; - }; - - /** \brief Writes a Value in JSON format in a human friendly way, - to a stream rather than to a string. - * - * The rules for line break and indent are as follow: - * - Object value: - * - if empty then print {} without indent and line break - * - if not empty the print '{', line break & indent, print one value per line - * and then unindent and line break and print '}'. - * - Array value: - * - if empty then print [] without indent and line break - * - if the array contains no object value, empty array or some other value types, - * and all the values fit on one lines, then print the array on a single line. - * - otherwise, it the values do not fit on one line, or the array contains - * object or non empty array, then print one value per line. - * - * If the Value have comments then they are outputed according to their #CommentPlacement. - * - * \param indentation Each level will be indented by this amount extra. - * \sa Reader, Value, Value::setComment() - */ - class JSON_API StyledStreamWriter - { - public: - StyledStreamWriter( std::string indentation="\t"); - ~StyledStreamWriter(){} - - public: - /** \brief Serialize a Value in JSON format. - * \param out Stream to write to. (Can be ostringstream, e.g.) - * \param root Value to serialize. - * \note There is no point in deriving from Writer, since write() should not return a value. - */ - void write( std::ostream &out, const Value &root, bool noNewLine=false ); - - private: - void writeValue( const Value &value ); - void writeArrayValue( const Value &value ); - bool isMultineArray( const Value &value ); - void pushValue( const std::string &value ); - void writeIndent(); - void writeWithIndent( const std::string &value ); - void indent(); - void unindent(); - void writeCommentBeforeValue( const Value &root ); - void writeCommentAfterValueOnSameLine( const Value &root ); - bool hasCommentForValue( const Value &value ); - static std::string normalizeEOL( const std::string &text ); - - typedef std::vector ChildValues; - - ChildValues childValues_; - std::ostream* document_; - std::string indentString_; - int rightMargin_; - std::string indentation_; - bool addChildValues_; - }; - - std::string JSON_API valueToString( Int value ); - std::string JSON_API valueToString( UInt value ); - std::string JSON_API valueToString( double value ); - std::string JSON_API valueToString( bool value ); - std::string JSON_API valueToQuotedString( const char *value ); - - /// \brief Output using the StyledStreamWriter. - /// \see Json::operator>>() - std::ostream& operator<<( std::ostream&, const Value &root ); +#define JSON_WRITER_H_INCLUDED + +#include "value.h" +#include +#include +#include + +namespace Json +{ +class Value; + +/** \brief Abstract class for writers. + */ +class JSON_API Writer +{ +public: + virtual ~Writer(); + + virtual std::string write(const Value& root, bool noNewLine = false) = 0; +}; + +/** \brief Outputs a Value in JSON format without formatting (not human friendly). + * + * The JSON document is written in a single line. It is not intended for 'human' consumption, + * but may be usefull to support feature such as RPC where bandwith is limited. + * \sa Reader, Value + */ +class JSON_API FastWriter : public Writer +{ +public: + FastWriter(); + virtual ~FastWriter() {} + + void enableYAMLCompatibility(); + +public: // overridden from Writer + virtual std::string write(const Value& root, bool noNewLine = false); + +private: + void writeValue(const Value& value); + + std::string document_; + bool yamlCompatiblityEnabled_; +}; + +/** \brief Writes a Value in JSON format in a human friendly way. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per line + * and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value types, + * and all the values fit on one lines, then print the array on a single line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * If the Value have comments then they are outputed according to their #CommentPlacement. + * + * \sa Reader, Value, Value::setComment() + */ +class JSON_API StyledWriter : public Writer +{ +public: + StyledWriter(); + virtual ~StyledWriter() {} + +public: // overridden from Writer + /** \brief Serialize a Value in JSON format. + * \param root Value to serialize. + * \return String containing the JSON document that represents the root value. + */ + virtual std::string write(const Value& root, bool noNewLine = false); + +private: + void writeValue(const Value& value); + void writeArrayValue(const Value& value); + bool isMultineArray(const Value& value); + void pushValue(const std::string& value); + void writeIndent(); + void writeWithIndent(const std::string& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(const Value& root); + void writeCommentAfterValueOnSameLine(const Value& root); + bool hasCommentForValue(const Value& value); + static std::string normalizeEOL(const std::string& text); + + typedef std::vector ChildValues; + + ChildValues childValues_; + std::string document_; + std::string indentString_; + int rightMargin_; + int indentSize_; + bool addChildValues_; +}; + +/** \brief Writes a Value in JSON format in a human friendly way, + to a stream rather than to a string. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per line + * and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value types, + * and all the values fit on one lines, then print the array on a single line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * If the Value have comments then they are outputed according to their #CommentPlacement. + * + * \param indentation Each level will be indented by this amount extra. + * \sa Reader, Value, Value::setComment() + */ +class JSON_API StyledStreamWriter +{ +public: + StyledStreamWriter(std::string indentation = "\t"); + ~StyledStreamWriter() {} + +public: + /** \brief Serialize a Value in JSON format. + * \param out Stream to write to. (Can be ostringstream, e.g.) + * \param root Value to serialize. + * \note There is no point in deriving from Writer, since write() should not return a value. + */ + void write(std::ostream& out, const Value& root, bool noNewLine = false); + +private: + void writeValue(const Value& value); + void writeArrayValue(const Value& value); + bool isMultineArray(const Value& value); + void pushValue(const std::string& value); + void writeIndent(); + void writeWithIndent(const std::string& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(const Value& root); + void writeCommentAfterValueOnSameLine(const Value& root); + bool hasCommentForValue(const Value& value); + static std::string normalizeEOL(const std::string& text); + + typedef std::vector ChildValues; + + ChildValues childValues_; + std::ostream* document_; + std::string indentString_; + int rightMargin_; + std::string indentation_; + bool addChildValues_; +}; + +std::string JSON_API valueToString(Int value); +std::string JSON_API valueToString(UInt value); +std::string JSON_API valueToString(double value); +std::string JSON_API valueToString(bool value); +std::string JSON_API valueToQuotedString(const char* value); + +/// \brief Output using the StyledStreamWriter. +/// \see Json::operator>>() +std::ostream& operator<<(std::ostream&, const Value& root); } // namespace Json - - #endif // JSON_WRITER_H_INCLUDED diff --git a/ext_libs/json/json_batchallocator.h b/ext_libs/json/json_batchallocator.h index 01e7139c..5e64f79f 100644 --- a/ext_libs/json/json_batchallocator.h +++ b/ext_libs/json/json_batchallocator.h @@ -4,15 +4,15 @@ // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE #ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED -# define JSONCPP_BATCHALLOCATOR_H_INCLUDED +#define JSONCPP_BATCHALLOCATOR_H_INCLUDED -# include -# include +#include +#include -# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - -namespace Json { +#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION +namespace Json +{ /* Fast memory allocator. * * This memory allocator allocates memory for a batch of object (specified by @@ -25,106 +25,102 @@ namespace Json { * The in-place new operator must be used to construct the object using the pointer * returned by allocate. */ -template +template class BatchAllocator { public: - typedef AllocatedType Type; - - BatchAllocator( unsigned int objectsPerPage = 255 ) - : freeHead_( 0 ) - , objectsPerPage_( objectsPerPage ) - { -// printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() ); - assert( sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *) ); // We must be able to store a slist in the object free space. - assert( objectsPerPage >= 16 ); - batches_ = allocateBatch( 0 ); // allocated a dummy page - currentBatch_ = batches_; - } - - ~BatchAllocator() - { - for ( BatchInfo *batch = batches_; batch; ) - { - BatchInfo *nextBatch = batch->next_; - free( batch ); - batch = nextBatch; - } - } - - /// allocate space for an array of objectPerAllocation object. - /// @warning it is the responsability of the caller to call objects constructors. - AllocatedType *allocate() - { - if ( freeHead_ ) // returns node from free list. - { - AllocatedType *object = freeHead_; - freeHead_ = *(AllocatedType **)object; - return object; - } - if ( currentBatch_->used_ == currentBatch_->end_ ) - { - currentBatch_ = currentBatch_->next_; - while ( currentBatch_ && currentBatch_->used_ == currentBatch_->end_ ) + typedef AllocatedType Type; + + BatchAllocator(unsigned int objectsPerPage = 255) : freeHead_(0), objectsPerPage_(objectsPerPage) + { + // printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() ); + assert(sizeof(AllocatedType) * objectPerAllocation >= + sizeof(AllocatedType*)); // We must be able to store a slist in the object free space. + assert(objectsPerPage >= 16); + batches_ = allocateBatch(0); // allocated a dummy page + currentBatch_ = batches_; + } + + ~BatchAllocator() + { + for (BatchInfo* batch = batches_; batch;) + { + BatchInfo* nextBatch = batch->next_; + free(batch); + batch = nextBatch; + } + } + + /// allocate space for an array of objectPerAllocation object. + /// @warning it is the responsability of the caller to call objects constructors. + AllocatedType* allocate() + { + if (freeHead_) // returns node from free list. + { + AllocatedType* object = freeHead_; + freeHead_ = *(AllocatedType**)object; + return object; + } + if (currentBatch_->used_ == currentBatch_->end_) + { currentBatch_ = currentBatch_->next_; - - if ( !currentBatch_ ) // no free batch found, allocate a new one - { - currentBatch_ = allocateBatch( objectsPerPage_ ); - currentBatch_->next_ = batches_; // insert at the head of the list - batches_ = currentBatch_; - } - } - AllocatedType *allocated = currentBatch_->used_; - currentBatch_->used_ += objectPerAllocation; - return allocated; - } - - /// Release the object. - /// @warning it is the responsability of the caller to actually destruct the object. - void release( AllocatedType *object ) - { - assert( object != 0 ); - *(AllocatedType **)object = freeHead_; - freeHead_ = object; - } + while (currentBatch_ && currentBatch_->used_ == currentBatch_->end_) + currentBatch_ = currentBatch_->next_; + + if (!currentBatch_) // no free batch found, allocate a new one + { + currentBatch_ = allocateBatch(objectsPerPage_); + currentBatch_->next_ = batches_; // insert at the head of the list + batches_ = currentBatch_; + } + } + AllocatedType* allocated = currentBatch_->used_; + currentBatch_->used_ += objectPerAllocation; + return allocated; + } + + /// Release the object. + /// @warning it is the responsability of the caller to actually destruct the object. + void release(AllocatedType* object) + { + assert(object != 0); + *(AllocatedType**)object = freeHead_; + freeHead_ = object; + } private: - struct BatchInfo - { - BatchInfo *next_; - AllocatedType *used_; - AllocatedType *end_; - AllocatedType buffer_[objectPerAllocation]; - }; - - // disabled copy constructor and assignement operator. - BatchAllocator( const BatchAllocator & ); - void operator =( const BatchAllocator &); - - static BatchInfo *allocateBatch( unsigned int objectsPerPage ) - { - const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType)* objectPerAllocation - + sizeof(AllocatedType) * objectPerAllocation * objectsPerPage; - BatchInfo *batch = static_cast( malloc( mallocSize ) ); - batch->next_ = 0; - batch->used_ = batch->buffer_; - batch->end_ = batch->buffer_ + objectsPerPage; - return batch; - } - - BatchInfo *batches_; - BatchInfo *currentBatch_; - /// Head of a single linked list within the allocated space of freeed object - AllocatedType *freeHead_; - unsigned int objectsPerPage_; + struct BatchInfo + { + BatchInfo* next_; + AllocatedType* used_; + AllocatedType* end_; + AllocatedType buffer_[objectPerAllocation]; + }; + + // disabled copy constructor and assignement operator. + BatchAllocator(const BatchAllocator&); + void operator=(const BatchAllocator&); + + static BatchInfo* allocateBatch(unsigned int objectsPerPage) + { + const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType) * objectPerAllocation + + sizeof(AllocatedType) * objectPerAllocation * objectsPerPage; + BatchInfo* batch = static_cast(malloc(mallocSize)); + batch->next_ = 0; + batch->used_ = batch->buffer_; + batch->end_ = batch->buffer_ + objectsPerPage; + return batch; + } + + BatchInfo* batches_; + BatchInfo* currentBatch_; + /// Head of a single linked list within the allocated space of freeed object + AllocatedType* freeHead_; + unsigned int objectsPerPage_; }; - } // namespace Json -# endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION +#endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION #endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED - diff --git a/ext_libs/json/json_reader.cpp b/ext_libs/json/json_reader.cpp index e7c40988..c290bdff 100644 --- a/ext_libs/json/json_reader.cpp +++ b/ext_libs/json/json_reader.cpp @@ -12,881 +12,775 @@ #include #include -#if _MSC_VER >= 1400 // VC++ 8.0 -#pragma warning( disable : 4996 ) // disable warning about strdup being deprecated. +#if _MSC_VER >= 1400 // VC++ 8.0 +#pragma warning(disable : 4996) // disable warning about strdup being deprecated. #endif -namespace Json { - +namespace Json +{ // Implementation of class Features // //////////////////////////////// -Features::Features() - : allowComments_( true ) - , strictRoot_( false ) -{ -} - +Features::Features() : allowComments_(true), strictRoot_(false) {} -Features -Features::all() +Features Features::all() { - return Features(); + return Features(); } - -Features -Features::strictMode() +Features Features::strictMode() { - Features features; - features.allowComments_ = false; - features.strictRoot_ = true; - return features; + Features features; + features.allowComments_ = false; + features.strictRoot_ = true; + return features; } // Implementation of class Reader // //////////////////////////////// - -static inline bool -in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 ) +static inline bool in(Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4) { - return c == c1 || c == c2 || c == c3 || c == c4; + return c == c1 || c == c2 || c == c3 || c == c4; } static inline bool -in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5 ) + in(Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5) { - return c == c1 || c == c2 || c == c3 || c == c4 || c == c5; + return c == c1 || c == c2 || c == c3 || c == c4 || c == c5; } - -static bool -containsNewLine( Reader::Location begin, - Reader::Location end ) +static bool containsNewLine(Reader::Location begin, Reader::Location end) { - for ( ;begin < end; ++begin ) - if ( *begin == '\n' || *begin == '\r' ) - return true; - return false; + for (; begin < end; ++begin) + if (*begin == '\n' || *begin == '\r') + return true; + return false; } static std::string codePointToUTF8(unsigned int cp) { - std::string result; - - // based on description from http://en.wikipedia.org/wiki/UTF-8 - - if (cp <= 0x7f) - { - result.resize(1); - result[0] = static_cast(cp); - } - else if (cp <= 0x7FF) - { - result.resize(2); - result[1] = static_cast(0x80 | (0x3f & cp)); - result[0] = static_cast(0xC0 | (0x1f & (cp >> 6))); - } - else if (cp <= 0xFFFF) - { - result.resize(3); - result[2] = static_cast(0x80 | (0x3f & cp)); - result[1] = 0x80 | static_cast((0x3f & (cp >> 6))); - result[0] = 0xE0 | static_cast((0xf & (cp >> 12))); - } - else if (cp <= 0x10FFFF) - { - result.resize(4); - result[3] = static_cast(0x80 | (0x3f & cp)); - result[2] = static_cast(0x80 | (0x3f & (cp >> 6))); - result[1] = static_cast(0x80 | (0x3f & (cp >> 12))); - result[0] = static_cast(0xF0 | (0x7 & (cp >> 18))); - } - - return result; + std::string result; + + // based on description from http://en.wikipedia.org/wiki/UTF-8 + + if (cp <= 0x7f) + { + result.resize(1); + result[0] = static_cast(cp); + } + else if (cp <= 0x7FF) + { + result.resize(2); + result[1] = static_cast(0x80 | (0x3f & cp)); + result[0] = static_cast(0xC0 | (0x1f & (cp >> 6))); + } + else if (cp <= 0xFFFF) + { + result.resize(3); + result[2] = static_cast(0x80 | (0x3f & cp)); + result[1] = 0x80 | static_cast((0x3f & (cp >> 6))); + result[0] = 0xE0 | static_cast((0xf & (cp >> 12))); + } + else if (cp <= 0x10FFFF) + { + result.resize(4); + result[3] = static_cast(0x80 | (0x3f & cp)); + result[2] = static_cast(0x80 | (0x3f & (cp >> 6))); + result[1] = static_cast(0x80 | (0x3f & (cp >> 12))); + result[0] = static_cast(0xF0 | (0x7 & (cp >> 18))); + } + + return result; } - // Class Reader // ////////////////////////////////////////////////////////////////// -Reader::Reader() - : features_( Features::all() ) -{ +Reader::Reader() : features_(Features::all()) {} + +Reader::Reader(const Features& features) : features_(features) {} + +bool Reader::parse(const std::string& document, Value& root, bool collectComments) +{ + document_ = document; + const char* begin = document_.c_str(); + const char* end = begin + document_.length(); + return parse(begin, end, root, collectComments); +} + +bool Reader::parse(std::istream& sin, Value& root, bool collectComments) +{ + // std::istream_iterator begin(sin); + // std::istream_iterator end; + // Those would allow streamed input from a file, if parse() were a + // template function. + + // Since std::string is reference-counted, this at least does not + // create an extra copy. + std::string doc; + std::getline(sin, doc, (char)EOF); + return parse(doc, root, collectComments); +} + +bool Reader::parse(const char* beginDoc, const char* endDoc, Value& root, bool collectComments) +{ + if (!features_.allowComments_) + { + collectComments = false; + } + + begin_ = beginDoc; + end_ = endDoc; + collectComments_ = collectComments; + current_ = begin_; + lastValueEnd_ = 0; + lastValue_ = 0; + commentsBefore_ = ""; + errors_.clear(); + while (!nodes_.empty()) + nodes_.pop(); + nodes_.push(&root); + + bool successful = readValue(); + Token token; + skipCommentTokens(token); + if (collectComments_ && !commentsBefore_.empty()) + root.setComment(commentsBefore_, commentAfter); + if (features_.strictRoot_) + { + if (!root.isArray() && !root.isObject()) + { + // Set error location to start of doc, ideally should be first token found in doc + token.type_ = tokenError; + token.start_ = beginDoc; + token.end_ = endDoc; + addError("A valid JSON document must be either an array or an object value.", token); + return false; + } + } + return successful; } - -Reader::Reader( const Features &features ) - : features_( features ) +bool Reader::readValue() { -} - - -bool -Reader::parse( const std::string &document, - Value &root, - bool collectComments ) -{ - document_ = document; - const char *begin = document_.c_str(); - const char *end = begin + document_.length(); - return parse( begin, end, root, collectComments ); -} - - -bool -Reader::parse( std::istream& sin, - Value &root, - bool collectComments ) -{ - //std::istream_iterator begin(sin); - //std::istream_iterator end; - // Those would allow streamed input from a file, if parse() were a - // template function. - - // Since std::string is reference-counted, this at least does not - // create an extra copy. - std::string doc; - std::getline(sin, doc, (char)EOF); - return parse( doc, root, collectComments ); -} - -bool -Reader::parse( const char *beginDoc, const char *endDoc, - Value &root, - bool collectComments ) -{ - if ( !features_.allowComments_ ) - { - collectComments = false; - } - - begin_ = beginDoc; - end_ = endDoc; - collectComments_ = collectComments; - current_ = begin_; - lastValueEnd_ = 0; - lastValue_ = 0; - commentsBefore_ = ""; - errors_.clear(); - while ( !nodes_.empty() ) - nodes_.pop(); - nodes_.push( &root ); - - bool successful = readValue(); - Token token; - skipCommentTokens( token ); - if ( collectComments_ && !commentsBefore_.empty() ) - root.setComment( commentsBefore_, commentAfter ); - if ( features_.strictRoot_ ) - { - if ( !root.isArray() && !root.isObject() ) - { - // Set error location to start of doc, ideally should be first token found in doc - token.type_ = tokenError; - token.start_ = beginDoc; - token.end_ = endDoc; - addError( "A valid JSON document must be either an array or an object value.", - token ); - return false; - } - } - return successful; -} - - -bool -Reader::readValue() -{ - Token token; - skipCommentTokens( token ); - bool successful = true; - - if ( collectComments_ && !commentsBefore_.empty() ) - { - currentValue().setComment( commentsBefore_, commentBefore ); - commentsBefore_ = ""; - } - - - switch ( token.type_ ) - { - case tokenObjectBegin: - successful = readObject( token ); - break; - case tokenArrayBegin: - successful = readArray( token ); - break; - case tokenNumber: - successful = decodeNumber( token ); - break; - case tokenString: - successful = decodeString( token ); - break; - case tokenTrue: - currentValue() = true; - break; - case tokenFalse: - currentValue() = false; - break; - case tokenNull: - currentValue() = Value(); - break; - default: - return addError( "Syntax error: value, object or array expected.", token ); - } - - if ( collectComments_ ) - { - lastValueEnd_ = current_; - lastValue_ = ¤tValue(); - } - - return successful; -} - - -void -Reader::skipCommentTokens( Token &token ) -{ - if ( features_.allowComments_ ) - { - do - { - readToken( token ); - } - while ( token.type_ == tokenComment ); - } - else - { - readToken( token ); - } -} - - -bool -Reader::expectToken( TokenType type, Token &token, const char *message ) -{ - readToken( token ); - if ( token.type_ != type ) - return addError( message, token ); - return true; -} - - -bool -Reader::readToken( Token &token ) -{ - skipSpaces(); - token.start_ = current_; - Char c = getNextChar(); - bool ok = true; - switch ( c ) - { - case '{': - token.type_ = tokenObjectBegin; - break; - case '}': - token.type_ = tokenObjectEnd; - break; - case '[': - token.type_ = tokenArrayBegin; - break; - case ']': - token.type_ = tokenArrayEnd; - break; - case '"': - token.type_ = tokenString; - ok = readString(); - break; - case '/': - token.type_ = tokenComment; - ok = readComment(); - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '-': - token.type_ = tokenNumber; - readNumber(); - break; - case 't': - token.type_ = tokenTrue; - ok = match( "rue", 3 ); - break; - case 'f': - token.type_ = tokenFalse; - ok = match( "alse", 4 ); - break; - case 'n': - token.type_ = tokenNull; - ok = match( "ull", 3 ); - break; - case ',': - token.type_ = tokenArraySeparator; - break; - case ':': - token.type_ = tokenMemberSeparator; - break; - case 0: - token.type_ = tokenEndOfStream; - break; - default: - ok = false; - break; - } - if ( !ok ) - token.type_ = tokenError; - token.end_ = current_; - return true; -} - - -void -Reader::skipSpaces() -{ - while ( current_ != end_ ) - { - Char c = *current_; - if ( c == ' ' || c == '\t' || c == '\r' || c == '\n' ) - ++current_; - else - break; - } -} - - -bool -Reader::match( Location pattern, - int patternLength ) -{ - if ( end_ - current_ < patternLength ) - return false; - int index = patternLength; - while ( index-- ) - if ( current_[index] != pattern[index] ) - return false; - current_ += patternLength; - return true; -} - - -bool -Reader::readComment() -{ - Location commentBegin = current_ - 1; - Char c = getNextChar(); - bool successful = false; - if ( c == '*' ) - successful = readCStyleComment(); - else if ( c == '/' ) - successful = readCppStyleComment(); - if ( !successful ) - return false; - - if ( collectComments_ ) - { - CommentPlacement placement = commentBefore; - if ( lastValueEnd_ && !containsNewLine( lastValueEnd_, commentBegin ) ) - { - if ( c != '*' || !containsNewLine( commentBegin, current_ ) ) - placement = commentAfterOnSameLine; - } - - addComment( commentBegin, current_, placement ); - } - return true; -} - - -void -Reader::addComment( Location begin, - Location end, - CommentPlacement placement ) -{ - assert( collectComments_ ); - if ( placement == commentAfterOnSameLine ) - { - assert( lastValue_ != 0 ); - lastValue_->setComment( std::string( begin, end ), placement ); - } - else - { - if ( !commentsBefore_.empty() ) - commentsBefore_ += "\n"; - commentsBefore_ += std::string( begin, end ); - } -} - - -bool -Reader::readCStyleComment() -{ - while ( current_ != end_ ) - { - Char c = getNextChar(); - if ( c == '*' && *current_ == '/' ) - break; - } - return getNextChar() == '/'; -} - - -bool -Reader::readCppStyleComment() -{ - while ( current_ != end_ ) - { - Char c = getNextChar(); - if ( c == '\r' || c == '\n' ) - break; - } - return true; -} - - -void -Reader::readNumber() -{ - while ( current_ != end_ ) - { - if ( !(*current_ >= '0' && *current_ <= '9') && - !in( *current_, '.', 'e', 'E', '+', '-' ) ) - break; - ++current_; - } -} - -bool -Reader::readString() -{ - Char c = 0; - while ( current_ != end_ ) - { - c = getNextChar(); - if ( c == '\\' ) - getNextChar(); - else if ( c == '"' ) - break; - } - return c == '"'; -} - - -bool -Reader::readObject( Token &tokenStart ) -{ - Token tokenName; - std::string name; - currentValue() = Value( objectValue ); - (void) tokenStart; - while ( readToken( tokenName ) ) - { - bool initialTokenOk = true; - while ( tokenName.type_ == tokenComment && initialTokenOk ) - initialTokenOk = readToken( tokenName ); - if ( !initialTokenOk ) - break; - if ( tokenName.type_ == tokenObjectEnd && name.empty() ) // empty object - return true; - if ( tokenName.type_ != tokenString ) - break; - - name = ""; - if ( !decodeString( tokenName, name ) ) - return recoverFromError( tokenObjectEnd ); - - Token colon; - if ( !readToken( colon ) || colon.type_ != tokenMemberSeparator ) - { - return addErrorAndRecover( "Missing ':' after object member name", - colon, - tokenObjectEnd ); - } - Value &value = currentValue()[ name ]; - nodes_.push( &value ); - bool ok = readValue(); - nodes_.pop(); - if ( !ok ) // error already set - return recoverFromError( tokenObjectEnd ); - - Token comma; - if ( !readToken( comma ) - || ( comma.type_ != tokenObjectEnd && - comma.type_ != tokenArraySeparator && - comma.type_ != tokenComment ) ) - { - return addErrorAndRecover( "Missing ',' or '}' in object declaration", - comma, - tokenObjectEnd ); - } - bool finalizeTokenOk = true; - while ( comma.type_ == tokenComment && - finalizeTokenOk ) - finalizeTokenOk = readToken( comma ); - if ( comma.type_ == tokenObjectEnd ) - return true; - } - return addErrorAndRecover( "Missing '}' or object member name", - tokenName, - tokenObjectEnd ); -} - - -bool -Reader::readArray( Token &tokenStart ) -{ - currentValue() = Value( arrayValue ); - skipSpaces(); - (void) tokenStart; - if ( *current_ == ']' ) // empty array - { - Token endArray; - readToken( endArray ); - return true; - } - int index = 0; - while ( true ) - { - Value &value = currentValue()[ index++ ]; - nodes_.push( &value ); - bool ok = readValue(); - nodes_.pop(); - if ( !ok ) // error already set - return recoverFromError( tokenArrayEnd ); - - Token token; - // Accept Comment after last item in the array. - ok = readToken( token ); - while ( token.type_ == tokenComment && ok ) - { - ok = readToken( token ); - } - bool badTokenType = ( token.type_ != tokenArraySeparator && - token.type_ != tokenArrayEnd ); - if ( !ok || badTokenType ) - { - return addErrorAndRecover( "Missing ',' or ']' in array declaration", - token, - tokenArrayEnd ); - } - if ( token.type_ == tokenArrayEnd ) - break; - } - return true; -} - - -bool -Reader::decodeNumber( Token &token ) -{ - bool isDouble = false; - for ( Location inspect = token.start_; inspect != token.end_; ++inspect ) - { - isDouble = isDouble - || in( *inspect, '.', 'e', 'E', '+' ) - || ( *inspect == '-' && inspect != token.start_ ); - } - if ( isDouble ) - return decodeDouble( token ); - Location current = token.start_; - bool isNegative = *current == '-'; - if ( isNegative ) - ++current; - Value::UInt threshold = (isNegative ? Value::UInt(-Value::minInt) - : Value::maxUInt) / 10; - Value::UInt value = 0; - while ( current < token.end_ ) - { - Char c = *current++; - if ( c < '0' || c > '9' ) - return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token ); - if ( value >= threshold ) - return decodeDouble( token ); - value = value * 10 + Value::UInt(c - '0'); - } - if ( isNegative ) - currentValue() = -Value::Int( value ); - else if ( value <= Value::UInt(Value::maxInt) ) - currentValue() = Value::Int( value ); - else - currentValue() = value; - return true; -} - - -bool -Reader::decodeDouble( Token &token ) -{ - double value = 0; - const int bufferSize = 32; - int count; - int length = int(token.end_ - token.start_); - if ( length <= bufferSize ) - { - Char buffer[bufferSize]; - memcpy( buffer, token.start_, length ); - buffer[length] = 0; - count = sscanf( buffer, "%lf", &value ); - } - else - { - std::string buffer( token.start_, token.end_ ); - count = sscanf( buffer.c_str(), "%lf", &value ); - } - - if ( count != 1 ) - return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token ); - currentValue() = value; - return true; -} - - -bool -Reader::decodeString( Token &token ) -{ - std::string decoded; - if ( !decodeString( token, decoded ) ) - return false; - currentValue() = decoded; - return true; -} - - -bool -Reader::decodeString( Token &token, std::string &decoded ) -{ - decoded.reserve( token.end_ - token.start_ - 2 ); - Location current = token.start_ + 1; // skip '"' - Location end = token.end_ - 1; // do not include '"' - while ( current != end ) - { - Char c = *current++; - if ( c == '"' ) - break; - else if ( c == '\\' ) - { - if ( current == end ) - return addError( "Empty escape sequence in string", token, current ); - Char escape = *current++; - switch ( escape ) - { - case '"': decoded += '"'; break; - case '/': decoded += '/'; break; - case '\\': decoded += '\\'; break; - case 'b': decoded += '\b'; break; - case 'f': decoded += '\f'; break; - case 'n': decoded += '\n'; break; - case 'r': decoded += '\r'; break; - case 't': decoded += '\t'; break; - case 'u': - { - unsigned int unicode; - if ( !decodeUnicodeCodePoint( token, current, end, unicode ) ) - return false; - decoded += codePointToUTF8(unicode); - } + Token token; + skipCommentTokens(token); + bool successful = true; + + if (collectComments_ && !commentsBefore_.empty()) + { + currentValue().setComment(commentsBefore_, commentBefore); + commentsBefore_ = ""; + } + + switch (token.type_) + { + case tokenObjectBegin: + successful = readObject(token); break; - default: - return addError( "Bad escape sequence in string", token, current ); - } - } - else - { - decoded += c; - } - } - return true; -} - -bool -Reader::decodeUnicodeCodePoint( Token &token, - Location ¤t, - Location end, - unsigned int &unicode ) -{ - - if ( !decodeUnicodeEscapeSequence( token, current, end, unicode ) ) - return false; - if (unicode >= 0xD800 && unicode <= 0xDBFF) - { - // surrogate pairs - if (end - current < 6) - return addError( "additional six characters expected to parse unicode surrogate pair.", token, current ); - unsigned int surrogatePair; - if (*(current++) == '\\' && *(current++)== 'u') - { - if (decodeUnicodeEscapeSequence( token, current, end, surrogatePair )) - { - unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); - } - else - return false; - } - else - return addError( "expecting another \\u token to begin the second half of a unicode surrogate pair", token, current ); - } - return true; -} + case tokenArrayBegin: + successful = readArray(token); + break; + case tokenNumber: + successful = decodeNumber(token); + break; + case tokenString: + successful = decodeString(token); + break; + case tokenTrue: + currentValue() = true; + break; + case tokenFalse: + currentValue() = false; + break; + case tokenNull: + currentValue() = Value(); + break; + default: + return addError("Syntax error: value, object or array expected.", token); + } -bool -Reader::decodeUnicodeEscapeSequence( Token &token, - Location ¤t, - Location end, - unsigned int &unicode ) -{ - if ( end - current < 4 ) - return addError( "Bad unicode escape sequence in string: four digits expected.", token, current ); - unicode = 0; - for ( int index =0; index < 4; ++index ) - { - Char c = *current++; - unicode *= 16; - if ( c >= '0' && c <= '9' ) - unicode += c - '0'; - else if ( c >= 'a' && c <= 'f' ) - unicode += c - 'a' + 10; - else if ( c >= 'A' && c <= 'F' ) - unicode += c - 'A' + 10; - else - return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", token, current ); - } - return true; -} + if (collectComments_) + { + lastValueEnd_ = current_; + lastValue_ = ¤tValue(); + } + return successful; +} -bool -Reader::addError( const std::string &message, - Token &token, - Location extra ) +void Reader::skipCommentTokens(Token& token) { - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = extra; - errors_.push_back( info ); - return false; -} - + if (features_.allowComments_) + { + do + { + readToken(token); + } while (token.type_ == tokenComment); + } + else + { + readToken(token); + } +} -bool -Reader::recoverFromError( TokenType skipUntilToken ) +bool Reader::expectToken(TokenType type, Token& token, const char* message) { - int errorCount = int(errors_.size()); - Token skip; - while ( true ) - { - if ( !readToken(skip) ) - errors_.resize( errorCount ); // discard errors caused by recovery - if ( skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream ) - break; - } - errors_.resize( errorCount ); - return false; + readToken(token); + if (token.type_ != type) + return addError(message, token); + return true; } - -bool -Reader::addErrorAndRecover( const std::string &message, - Token &token, - TokenType skipUntilToken ) +bool Reader::readToken(Token& token) { - addError( message, token ); - return recoverFromError( skipUntilToken ); + skipSpaces(); + token.start_ = current_; + Char c = getNextChar(); + bool ok = true; + switch (c) + { + case '{': + token.type_ = tokenObjectBegin; + break; + case '}': + token.type_ = tokenObjectEnd; + break; + case '[': + token.type_ = tokenArrayBegin; + break; + case ']': + token.type_ = tokenArrayEnd; + break; + case '"': + token.type_ = tokenString; + ok = readString(); + break; + case '/': + token.type_ = tokenComment; + ok = readComment(); + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '-': + token.type_ = tokenNumber; + readNumber(); + break; + case 't': + token.type_ = tokenTrue; + ok = match("rue", 3); + break; + case 'f': + token.type_ = tokenFalse; + ok = match("alse", 4); + break; + case 'n': + token.type_ = tokenNull; + ok = match("ull", 3); + break; + case ',': + token.type_ = tokenArraySeparator; + break; + case ':': + token.type_ = tokenMemberSeparator; + break; + case 0: + token.type_ = tokenEndOfStream; + break; + default: + ok = false; + break; + } + if (!ok) + token.type_ = tokenError; + token.end_ = current_; + return true; } +void Reader::skipSpaces() +{ + while (current_ != end_) + { + Char c = *current_; + if (c == ' ' || c == '\t' || c == '\r' || c == '\n') + ++current_; + else + break; + } +} -Value & -Reader::currentValue() +bool Reader::match(Location pattern, int patternLength) { - return *(nodes_.top()); + if (end_ - current_ < patternLength) + return false; + int index = patternLength; + while (index--) + if (current_[index] != pattern[index]) + return false; + current_ += patternLength; + return true; +} + +bool Reader::readComment() +{ + Location commentBegin = current_ - 1; + Char c = getNextChar(); + bool successful = false; + if (c == '*') + successful = readCStyleComment(); + else if (c == '/') + successful = readCppStyleComment(); + if (!successful) + return false; + + if (collectComments_) + { + CommentPlacement placement = commentBefore; + if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) + { + if (c != '*' || !containsNewLine(commentBegin, current_)) + placement = commentAfterOnSameLine; + } + + addComment(commentBegin, current_, placement); + } + return true; +} + +void Reader::addComment(Location begin, Location end, CommentPlacement placement) +{ + assert(collectComments_); + if (placement == commentAfterOnSameLine) + { + assert(lastValue_ != 0); + lastValue_->setComment(std::string(begin, end), placement); + } + else + { + if (!commentsBefore_.empty()) + commentsBefore_ += "\n"; + commentsBefore_ += std::string(begin, end); + } +} + +bool Reader::readCStyleComment() +{ + while (current_ != end_) + { + Char c = getNextChar(); + if (c == '*' && *current_ == '/') + break; + } + return getNextChar() == '/'; } +bool Reader::readCppStyleComment() +{ + while (current_ != end_) + { + Char c = getNextChar(); + if (c == '\r' || c == '\n') + break; + } + return true; +} -Reader::Char -Reader::getNextChar() +void Reader::readNumber() { - if ( current_ == end_ ) - return 0; - return *current_++; + while (current_ != end_) + { + if (!(*current_ >= '0' && *current_ <= '9') && !in(*current_, '.', 'e', 'E', '+', '-')) + break; + ++current_; + } } +bool Reader::readString() +{ + Char c = 0; + while (current_ != end_) + { + c = getNextChar(); + if (c == '\\') + getNextChar(); + else if (c == '"') + break; + } + return c == '"'; +} + +bool Reader::readObject(Token& tokenStart) +{ + Token tokenName; + std::string name; + currentValue() = Value(objectValue); + (void)tokenStart; + while (readToken(tokenName)) + { + bool initialTokenOk = true; + while (tokenName.type_ == tokenComment && initialTokenOk) + initialTokenOk = readToken(tokenName); + if (!initialTokenOk) + break; + if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object + return true; + if (tokenName.type_ != tokenString) + break; + + name = ""; + if (!decodeString(tokenName, name)) + return recoverFromError(tokenObjectEnd); + + Token colon; + if (!readToken(colon) || colon.type_ != tokenMemberSeparator) + { + return addErrorAndRecover("Missing ':' after object member name", colon, tokenObjectEnd); + } + Value& value = currentValue()[name]; + nodes_.push(&value); + bool ok = readValue(); + nodes_.pop(); + if (!ok) // error already set + return recoverFromError(tokenObjectEnd); + + Token comma; + if (!readToken(comma) || + (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && comma.type_ != tokenComment)) + { + return addErrorAndRecover("Missing ',' or '}' in object declaration", comma, tokenObjectEnd); + } + bool finalizeTokenOk = true; + while (comma.type_ == tokenComment && finalizeTokenOk) + finalizeTokenOk = readToken(comma); + if (comma.type_ == tokenObjectEnd) + return true; + } + return addErrorAndRecover("Missing '}' or object member name", tokenName, tokenObjectEnd); +} + +bool Reader::readArray(Token& tokenStart) +{ + currentValue() = Value(arrayValue); + skipSpaces(); + (void)tokenStart; + if (*current_ == ']') // empty array + { + Token endArray; + readToken(endArray); + return true; + } + int index = 0; + while (true) + { + Value& value = currentValue()[index++]; + nodes_.push(&value); + bool ok = readValue(); + nodes_.pop(); + if (!ok) // error already set + return recoverFromError(tokenArrayEnd); + + Token token; + // Accept Comment after last item in the array. + ok = readToken(token); + while (token.type_ == tokenComment && ok) + { + ok = readToken(token); + } + bool badTokenType = (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd); + if (!ok || badTokenType) + { + return addErrorAndRecover("Missing ',' or ']' in array declaration", token, tokenArrayEnd); + } + if (token.type_ == tokenArrayEnd) + break; + } + return true; +} + +bool Reader::decodeNumber(Token& token) +{ + bool isDouble = false; + for (Location inspect = token.start_; inspect != token.end_; ++inspect) + { + isDouble = isDouble || in(*inspect, '.', 'e', 'E', '+') || (*inspect == '-' && inspect != token.start_); + } + if (isDouble) + return decodeDouble(token); + Location current = token.start_; + bool isNegative = *current == '-'; + if (isNegative) + ++current; + Value::UInt threshold = (isNegative ? Value::UInt(-Value::minInt) : Value::maxUInt) / 10; + Value::UInt value = 0; + while (current < token.end_) + { + Char c = *current++; + if (c < '0' || c > '9') + return addError("'" + std::string(token.start_, token.end_) + "' is not a number.", token); + if (value >= threshold) + return decodeDouble(token); + value = value * 10 + Value::UInt(c - '0'); + } + if (isNegative) + currentValue() = -Value::Int(value); + else if (value <= Value::UInt(Value::maxInt)) + currentValue() = Value::Int(value); + else + currentValue() = value; + return true; +} + +bool Reader::decodeDouble(Token& token) +{ + double value = 0; + const int bufferSize = 32; + int count; + int length = int(token.end_ - token.start_); + if (length <= bufferSize) + { + Char buffer[bufferSize]; + memcpy(buffer, token.start_, length); + buffer[length] = 0; + count = sscanf(buffer, "%lf", &value); + } + else + { + std::string buffer(token.start_, token.end_); + count = sscanf(buffer.c_str(), "%lf", &value); + } + + if (count != 1) + return addError("'" + std::string(token.start_, token.end_) + "' is not a number.", token); + currentValue() = value; + return true; +} + +bool Reader::decodeString(Token& token) +{ + std::string decoded; + if (!decodeString(token, decoded)) + return false; + currentValue() = decoded; + return true; +} + +bool Reader::decodeString(Token& token, std::string& decoded) +{ + decoded.reserve(token.end_ - token.start_ - 2); + Location current = token.start_ + 1; // skip '"' + Location end = token.end_ - 1; // do not include '"' + while (current != end) + { + Char c = *current++; + if (c == '"') + break; + else if (c == '\\') + { + if (current == end) + return addError("Empty escape sequence in string", token, current); + Char escape = *current++; + switch (escape) + { + case '"': + decoded += '"'; + break; + case '/': + decoded += '/'; + break; + case '\\': + decoded += '\\'; + break; + case 'b': + decoded += '\b'; + break; + case 'f': + decoded += '\f'; + break; + case 'n': + decoded += '\n'; + break; + case 'r': + decoded += '\r'; + break; + case 't': + decoded += '\t'; + break; + case 'u': + { + unsigned int unicode; + if (!decodeUnicodeCodePoint(token, current, end, unicode)) + return false; + decoded += codePointToUTF8(unicode); + } + break; + default: + return addError("Bad escape sequence in string", token, current); + } + } + else + { + decoded += c; + } + } + return true; +} + +bool Reader::decodeUnicodeCodePoint(Token& token, Location& current, Location end, unsigned int& unicode) +{ + if (!decodeUnicodeEscapeSequence(token, current, end, unicode)) + return false; + if (unicode >= 0xD800 && unicode <= 0xDBFF) + { + // surrogate pairs + if (end - current < 6) + return addError("additional six characters expected to parse unicode surrogate pair.", token, current); + unsigned int surrogatePair; + if (*(current++) == '\\' && *(current++) == 'u') + { + if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) + { + unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); + } + else + return false; + } + else + return addError("expecting another \\u token to begin the second half of a unicode surrogate pair", token, + current); + } + return true; +} + +bool Reader::decodeUnicodeEscapeSequence(Token& token, Location& current, Location end, unsigned int& unicode) +{ + if (end - current < 4) + return addError("Bad unicode escape sequence in string: four digits expected.", token, current); + unicode = 0; + for (int index = 0; index < 4; ++index) + { + Char c = *current++; + unicode *= 16; + if (c >= '0' && c <= '9') + unicode += c - '0'; + else if (c >= 'a' && c <= 'f') + unicode += c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + unicode += c - 'A' + 10; + else + return addError("Bad unicode escape sequence in string: hexadecimal digit expected.", token, current); + } + return true; +} + +bool Reader::addError(const std::string& message, Token& token, Location extra) +{ + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = extra; + errors_.push_back(info); + return false; +} + +bool Reader::recoverFromError(TokenType skipUntilToken) +{ + int errorCount = int(errors_.size()); + Token skip; + while (true) + { + if (!readToken(skip)) + errors_.resize(errorCount); // discard errors caused by recovery + if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream) + break; + } + errors_.resize(errorCount); + return false; +} -void -Reader::getLocationLineAndColumn( Location location, - int &line, - int &column ) const +bool Reader::addErrorAndRecover(const std::string& message, Token& token, TokenType skipUntilToken) { - Location current = begin_; - Location lastLineStart = current; - line = 0; - while ( current < location && current != end_ ) - { - Char c = *current++; - if ( c == '\r' ) - { - if ( *current == '\n' ) - ++current; - lastLineStart = current; - ++line; - } - else if ( c == '\n' ) - { - lastLineStart = current; - ++line; - } - } - // column & line start at 1 - column = int(location - lastLineStart) + 1; - ++line; + addError(message, token); + return recoverFromError(skipUntilToken); } +Value& Reader::currentValue() +{ + return *(nodes_.top()); +} -std::string -Reader::getLocationLineAndColumn( Location location ) const +Reader::Char Reader::getNextChar() { - int line, column; - getLocationLineAndColumn( location, line, column ); - char buffer[18+16+16+1]; - sprintf( buffer, "Line %d, Column %d", line, column ); - return buffer; + if (current_ == end_) + return 0; + return *current_++; } +void Reader::getLocationLineAndColumn(Location location, int& line, int& column) const +{ + Location current = begin_; + Location lastLineStart = current; + line = 0; + while (current < location && current != end_) + { + Char c = *current++; + if (c == '\r') + { + if (*current == '\n') + ++current; + lastLineStart = current; + ++line; + } + else if (c == '\n') + { + lastLineStart = current; + ++line; + } + } + // column & line start at 1 + column = int(location - lastLineStart) + 1; + ++line; +} -std::string -Reader::getFormatedErrorMessages() const +std::string Reader::getLocationLineAndColumn(Location location) const { - std::string formattedMessage; - for ( Errors::const_iterator itError = errors_.begin(); - itError != errors_.end(); - ++itError ) - { - const ErrorInfo &error = *itError; - formattedMessage += "* " + getLocationLineAndColumn( error.token_.start_ ) + "\n"; - formattedMessage += " " + error.message_ + "\n"; - if ( error.extra_ ) - formattedMessage += "See " + getLocationLineAndColumn( error.extra_ ) + " for detail.\n"; - } - return formattedMessage; + int line, column; + getLocationLineAndColumn(location, line, column); + char buffer[18 + 16 + 16 + 1]; + sprintf(buffer, "Line %d, Column %d", line, column); + return buffer; } +std::string Reader::getFormatedErrorMessages() const +{ + std::string formattedMessage; + for (Errors::const_iterator itError = errors_.begin(); itError != errors_.end(); ++itError) + { + const ErrorInfo& error = *itError; + formattedMessage += "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; + formattedMessage += " " + error.message_ + "\n"; + if (error.extra_) + formattedMessage += "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n"; + } + return formattedMessage; +} -std::istream& operator>>( std::istream &sin, Value &root ) +std::istream& operator>>(std::istream& sin, Value& root) { Json::Reader reader; bool ok = reader.parse(sin, root, true); - //JSON_ASSERT( ok ); - if (!ok) throw std::runtime_error(reader.getFormatedErrorMessages()); + // JSON_ASSERT( ok ); + if (!ok) + throw std::runtime_error(reader.getFormatedErrorMessages()); return sin; } - } // namespace Json diff --git a/ext_libs/json/json_value.cpp b/ext_libs/json/json_value.cpp index b82d6efe..6f03ee23 100644 --- a/ext_libs/json/json_value.cpp +++ b/ext_libs/json/json_value.cpp @@ -11,28 +11,30 @@ #include #include #ifdef JSON_USE_CPPTL -# include +#include #endif -#include // size_t +#include // size_t #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR -# include "json_batchallocator.h" +#include "json_batchallocator.h" #endif // #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR -#define JSON_ASSERT_UNREACHABLE assert( false ) -#define JSON_ASSERT( condition ) assert( condition ); // @todo <= change this into an exception throw -#define JSON_ASSERT_MESSAGE( condition, message ) if (!( condition )) throw std::runtime_error( message ); - -namespace Json { +#define JSON_ASSERT_UNREACHABLE assert(false) +#define JSON_ASSERT(condition) assert(condition); // @todo <= change this into an exception throw +#define JSON_ASSERT_MESSAGE(condition, message) \ + if (!(condition)) \ + throw std::runtime_error(message); +namespace Json +{ const Value Value::null; -const Int Value::minInt = Int( ~(UInt(-1)/2) ); -const Int Value::maxInt = Int( UInt(-1)/2 ); +const Int Value::minInt = Int(~(UInt(-1) / 2)); +const Int Value::maxInt = Int(UInt(-1) / 2); const UInt Value::maxUInt = UInt(-1); // A "safe" implementation of strdup. Allow null pointer to be passed. // Also avoid warning on msvc80. // -//inline char *safeStringDup( const char *czstring ) +// inline char *safeStringDup( const char *czstring ) //{ // if ( czstring ) // { @@ -44,7 +46,7 @@ const UInt Value::maxUInt = UInt(-1); // return 0; //} // -//inline char *safeStringDup( const std::string &str ) +// inline char *safeStringDup( const std::string &str ) //{ // if ( !str.empty() ) // { @@ -57,65 +59,53 @@ const UInt Value::maxUInt = UInt(-1); // return 0; //} -ValueAllocator::~ValueAllocator() -{ -} +ValueAllocator::~ValueAllocator() {} class DefaultValueAllocator : public ValueAllocator { public: - virtual ~DefaultValueAllocator() - { - } - - virtual char *makeMemberName( const char *memberName ) - { - return duplicateStringValue( memberName ); - } - - virtual void releaseMemberName( char *memberName ) - { - releaseStringValue( memberName ); - } - - virtual char *duplicateStringValue( const char *value, - unsigned int length = unknown ) - { - //@todo invesgate this old optimization - //if ( !value || value[0] == 0 ) - // return 0; - - if ( length == unknown ) - length = (unsigned int)strlen(value); - char *newString = static_cast( malloc( length + 1 ) ); - memcpy( newString, value, length ); - newString[length] = 0; - return newString; - } - - virtual void releaseStringValue( char *value ) - { - if ( value ) - free( value ); - } + virtual ~DefaultValueAllocator() {} + + virtual char* makeMemberName(const char* memberName) { return duplicateStringValue(memberName); } + + virtual void releaseMemberName(char* memberName) { releaseStringValue(memberName); } + + virtual char* duplicateStringValue(const char* value, unsigned int length = unknown) + { + //@todo invesgate this old optimization + // if ( !value || value[0] == 0 ) + // return 0; + + if (length == unknown) + length = (unsigned int)strlen(value); + char* newString = static_cast(malloc(length + 1)); + memcpy(newString, value, length); + newString[length] = 0; + return newString; + } + + virtual void releaseStringValue(char* value) + { + if (value) + free(value); + } }; -static ValueAllocator *&valueAllocator() +static ValueAllocator*& valueAllocator() { - static DefaultValueAllocator defaultAllocator; - static ValueAllocator *valueAllocator = &defaultAllocator; - return valueAllocator; + static DefaultValueAllocator defaultAllocator; + static ValueAllocator* valueAllocator = &defaultAllocator; + return valueAllocator; } -static struct DummyValueAllocatorInitializer { - DummyValueAllocatorInitializer() - { - valueAllocator(); // ensure valueAllocator() statics are initialized before main(). - } +static struct DummyValueAllocatorInitializer +{ + DummyValueAllocatorInitializer() + { + valueAllocator(); // ensure valueAllocator() statics are initialized before main(). + } } dummyValueAllocatorInitializer; - - // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// @@ -124,12 +114,11 @@ static struct DummyValueAllocatorInitializer { // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// #ifdef JSON_VALUE_USE_INTERNAL_MAP -# include "json_internalarray.inl" -# include "json_internalmap.inl" +#include "json_internalarray.inl" +#include "json_internalmap.inl" #endif // JSON_VALUE_USE_INTERNAL_MAP -# include "json_valueiterator.inl" - +#include "json_valueiterator.inl" // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// @@ -139,31 +128,24 @@ static struct DummyValueAllocatorInitializer { // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// - -Value::CommentInfo::CommentInfo() - : comment_( 0 ) -{ -} +Value::CommentInfo::CommentInfo() : comment_(0) {} Value::CommentInfo::~CommentInfo() { - if ( comment_ ) - valueAllocator()->releaseStringValue( comment_ ); + if (comment_) + valueAllocator()->releaseStringValue(comment_); } - -void -Value::CommentInfo::setComment( const char *text ) +void Value::CommentInfo::setComment(const char* text) { - if ( comment_ ) - valueAllocator()->releaseStringValue( comment_ ); - JSON_ASSERT( text ); - JSON_ASSERT_MESSAGE( text[0]=='\0' || text[0]=='/', "Comments must start with /"); - // It seems that /**/ style comments are acceptable as well. - comment_ = valueAllocator()->duplicateStringValue( text ); + if (comment_) + valueAllocator()->releaseStringValue(comment_); + JSON_ASSERT(text); + JSON_ASSERT_MESSAGE(text[0] == '\0' || text[0] == '/', "Comments must start with /"); + // It seems that /**/ style comments are acceptable as well. + comment_ = valueAllocator()->duplicateStringValue(text); } - // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// @@ -171,93 +153,75 @@ Value::CommentInfo::setComment( const char *text ) // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// -# ifndef JSON_VALUE_USE_INTERNAL_MAP +#ifndef JSON_VALUE_USE_INTERNAL_MAP // Notes: index_ indicates if the string was allocated when // a string is stored. -Value::CZString::CZString( int index ) - : cstr_( 0 ) - , index_( index ) -{ -} +Value::CZString::CZString(int index) : cstr_(0), index_(index) {} -Value::CZString::CZString( const char *cstr, DuplicationPolicy allocate ) - : cstr_( allocate == duplicate ? valueAllocator()->makeMemberName(cstr) - : cstr ) - , index_( allocate ) +Value::CZString::CZString(const char* cstr, DuplicationPolicy allocate) : + cstr_(allocate == duplicate ? valueAllocator()->makeMemberName(cstr) : cstr), index_(allocate) { } -Value::CZString::CZString( const CZString &other ) -: cstr_( other.index_ != noDuplication && other.cstr_ != 0 - ? valueAllocator()->makeMemberName( other.cstr_ ) - : other.cstr_ ) - , index_( other.cstr_ ? (other.index_ == noDuplication ? noDuplication : duplicate) - : other.index_ ) +Value::CZString::CZString(const CZString& other) : + cstr_(other.index_ != noDuplication && other.cstr_ != 0 ? valueAllocator()->makeMemberName(other.cstr_) : + other.cstr_), + index_(other.cstr_ ? (other.index_ == noDuplication ? noDuplication : duplicate) : other.index_) { } Value::CZString::~CZString() { - if ( cstr_ && index_ == duplicate ) - valueAllocator()->releaseMemberName( const_cast( cstr_ ) ); + if (cstr_ && index_ == duplicate) + valueAllocator()->releaseMemberName(const_cast(cstr_)); } -void -Value::CZString::swap( CZString &other ) +void Value::CZString::swap(CZString& other) { - std::swap( cstr_, other.cstr_ ); - std::swap( index_, other.index_ ); + std::swap(cstr_, other.cstr_); + std::swap(index_, other.index_); } -Value::CZString & -Value::CZString::operator =( const CZString &other ) +Value::CZString& Value::CZString::operator=(const CZString& other) { - CZString temp( other ); - swap( temp ); - return *this; + CZString temp(other); + swap(temp); + return *this; } -bool -Value::CZString::operator<( const CZString &other ) const +bool Value::CZString::operator<(const CZString& other) const { - if ( cstr_ ) - return strcmp( cstr_, other.cstr_ ) < 0; - return index_ < other.index_; + if (cstr_) + return strcmp(cstr_, other.cstr_) < 0; + return index_ < other.index_; } -bool -Value::CZString::operator==( const CZString &other ) const +bool Value::CZString::operator==(const CZString& other) const { - if ( cstr_ ) - return strcmp( cstr_, other.cstr_ ) == 0; - return index_ == other.index_; + if (cstr_) + return strcmp(cstr_, other.cstr_) == 0; + return index_ == other.index_; } - -int -Value::CZString::index() const +int Value::CZString::index() const { - return index_; + return index_; } - -const char * -Value::CZString::c_str() const +const char* Value::CZString::c_str() const { - return cstr_; + return cstr_; } -bool -Value::CZString::isStaticString() const +bool Value::CZString::isStaticString() const { - return index_ == noDuplication; + return index_ == noDuplication; } #endif // ifndef JSON_VALUE_USE_INTERNAL_MAP - // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// @@ -270,970 +234,878 @@ Value::CZString::isStaticString() const * memset( this, 0, sizeof(Value) ) * This optimization is used in ValueInternalMap fast allocator. */ -Value::Value( ValueType type ) - : type_( type ) - , allocated_( 0 ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) +Value::Value(ValueType type) : + type_(type), + allocated_(0), + comments_(0) +#ifdef JSON_VALUE_USE_INTERNAL_MAP + , + itemIsUsed_(0) #endif { - switch ( type ) - { - case nullValue: - break; - case intValue: - case uintValue: - value_.int_ = 0; - break; - case realValue: - value_.real_ = 0.0; - break; - case stringValue: - value_.string_ = 0; - break; + switch (type) + { + case nullValue: + break; + case intValue: + case uintValue: + value_.int_ = 0; + break; + case realValue: + value_.real_ = 0.0; + break; + case stringValue: + value_.string_ = 0; + break; #ifndef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - case objectValue: - value_.map_ = new ObjectValues(); - break; + case arrayValue: + case objectValue: + value_.map_ = new ObjectValues(); + break; #else - case arrayValue: - value_.array_ = arrayAllocator()->newArray(); - break; - case objectValue: - value_.map_ = mapAllocator()->newMap(); - break; + case arrayValue: + value_.array_ = arrayAllocator()->newArray(); + break; + case objectValue: + value_.map_ = mapAllocator()->newMap(); + break; #endif - case booleanValue: - value_.bool_ = false; - break; - default: - JSON_ASSERT_UNREACHABLE; - } + case booleanValue: + value_.bool_ = false; + break; + default: + JSON_ASSERT_UNREACHABLE; + } } - -Value::Value( Int value ) - : type_( intValue ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) +Value::Value(Int value) : + type_(intValue), + comments_(0) +#ifdef JSON_VALUE_USE_INTERNAL_MAP + , + itemIsUsed_(0) #endif { - value_.int_ = value; + value_.int_ = value; } - -Value::Value( UInt value ) - : type_( uintValue ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) +Value::Value(UInt value) : + type_(uintValue), + comments_(0) +#ifdef JSON_VALUE_USE_INTERNAL_MAP + , + itemIsUsed_(0) #endif { - value_.uint_ = value; + value_.uint_ = value; } -Value::Value( double value ) - : type_( realValue ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) +Value::Value(double value) : + type_(realValue), + comments_(0) +#ifdef JSON_VALUE_USE_INTERNAL_MAP + , + itemIsUsed_(0) #endif { - value_.real_ = value; + value_.real_ = value; } -Value::Value( const char *value ) - : type_( stringValue ) - , allocated_( true ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) +Value::Value(const char* value) : + type_(stringValue), + allocated_(true), + comments_(0) +#ifdef JSON_VALUE_USE_INTERNAL_MAP + , + itemIsUsed_(0) #endif { - value_.string_ = valueAllocator()->duplicateStringValue( value ); + value_.string_ = valueAllocator()->duplicateStringValue(value); } - -Value::Value( const char *beginValue, - const char *endValue ) - : type_( stringValue ) - , allocated_( true ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) +Value::Value(const char* beginValue, const char* endValue) : + type_(stringValue), + allocated_(true), + comments_(0) +#ifdef JSON_VALUE_USE_INTERNAL_MAP + , + itemIsUsed_(0) #endif { - value_.string_ = valueAllocator()->duplicateStringValue( beginValue, - UInt(endValue - beginValue) ); + value_.string_ = valueAllocator()->duplicateStringValue(beginValue, UInt(endValue - beginValue)); } - -Value::Value( const std::string &value ) - : type_( stringValue ) - , allocated_( true ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) +Value::Value(const std::string& value) : + type_(stringValue), + allocated_(true), + comments_(0) +#ifdef JSON_VALUE_USE_INTERNAL_MAP + , + itemIsUsed_(0) #endif { - value_.string_ = valueAllocator()->duplicateStringValue( value.c_str(), - (unsigned int)value.length() ); - + value_.string_ = valueAllocator()->duplicateStringValue(value.c_str(), (unsigned int)value.length()); } -Value::Value( const StaticString &value ) - : type_( stringValue ) - , allocated_( false ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) +Value::Value(const StaticString& value) : + type_(stringValue), + allocated_(false), + comments_(0) +#ifdef JSON_VALUE_USE_INTERNAL_MAP + , + itemIsUsed_(0) #endif { - value_.string_ = const_cast( value.c_str() ); + value_.string_ = const_cast(value.c_str()); } - -# ifdef JSON_USE_CPPTL -Value::Value( const CppTL::ConstString &value ) - : type_( stringValue ) - , allocated_( true ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) +#ifdef JSON_USE_CPPTL +Value::Value(const CppTL::ConstString& value) : + type_(stringValue), + allocated_(true), + comments_(0) +#ifdef JSON_VALUE_USE_INTERNAL_MAP + , + itemIsUsed_(0) #endif { - value_.string_ = valueAllocator()->duplicateStringValue( value, value.length() ); + value_.string_ = valueAllocator()->duplicateStringValue(value, value.length()); } -# endif +#endif -Value::Value( bool value ) - : type_( booleanValue ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) +Value::Value(bool value) : + type_(booleanValue), + comments_(0) +#ifdef JSON_VALUE_USE_INTERNAL_MAP + , + itemIsUsed_(0) #endif { - value_.bool_ = value; + value_.bool_ = value; } - -Value::Value( const Value &other ) - : type_( other.type_ ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) +Value::Value(const Value& other) : + type_(other.type_), + comments_(0) +#ifdef JSON_VALUE_USE_INTERNAL_MAP + , + itemIsUsed_(0) #endif { - switch ( type_ ) - { - case nullValue: - case intValue: - case uintValue: - case realValue: - case booleanValue: - value_ = other.value_; - break; - case stringValue: - if ( other.value_.string_ ) - { - value_.string_ = valueAllocator()->duplicateStringValue( other.value_.string_ ); - allocated_ = true; - } - else - value_.string_ = 0; - break; + switch (type_) + { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + value_ = other.value_; + break; + case stringValue: + if (other.value_.string_) + { + value_.string_ = valueAllocator()->duplicateStringValue(other.value_.string_); + allocated_ = true; + } + else + value_.string_ = 0; + break; #ifndef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - case objectValue: - value_.map_ = new ObjectValues( *other.value_.map_ ); - break; + case arrayValue: + case objectValue: + value_.map_ = new ObjectValues(*other.value_.map_); + break; #else - case arrayValue: - value_.array_ = arrayAllocator()->newArrayCopy( *other.value_.array_ ); - break; - case objectValue: - value_.map_ = mapAllocator()->newMapCopy( *other.value_.map_ ); - break; + case arrayValue: + value_.array_ = arrayAllocator()->newArrayCopy(*other.value_.array_); + break; + case objectValue: + value_.map_ = mapAllocator()->newMapCopy(*other.value_.map_); + break; #endif - default: - JSON_ASSERT_UNREACHABLE; - } - if ( other.comments_ ) - { - comments_ = new CommentInfo[numberOfCommentPlacement]; - for ( int comment =0; comment < numberOfCommentPlacement; ++comment ) - { - const CommentInfo &otherComment = other.comments_[comment]; - if ( otherComment.comment_ ) - comments_[comment].setComment( otherComment.comment_ ); - } - } + default: + JSON_ASSERT_UNREACHABLE; + } + if (other.comments_) + { + comments_ = new CommentInfo[numberOfCommentPlacement]; + for (int comment = 0; comment < numberOfCommentPlacement; ++comment) + { + const CommentInfo& otherComment = other.comments_[comment]; + if (otherComment.comment_) + comments_[comment].setComment(otherComment.comment_); + } + } } - Value::~Value() { - switch ( type_ ) - { - case nullValue: - case intValue: - case uintValue: - case realValue: - case booleanValue: - break; - case stringValue: - if ( allocated_ ) - valueAllocator()->releaseStringValue( value_.string_ ); - break; + switch (type_) + { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + break; + case stringValue: + if (allocated_) + valueAllocator()->releaseStringValue(value_.string_); + break; #ifndef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - case objectValue: - delete value_.map_; - break; + case arrayValue: + case objectValue: + delete value_.map_; + break; #else - case arrayValue: - arrayAllocator()->destructArray( value_.array_ ); - break; - case objectValue: - mapAllocator()->destructMap( value_.map_ ); - break; + case arrayValue: + arrayAllocator()->destructArray(value_.array_); + break; + case objectValue: + mapAllocator()->destructMap(value_.map_); + break; #endif - default: - JSON_ASSERT_UNREACHABLE; - } - - if ( comments_ ) - delete[] comments_; -} - -Value & -Value::operator=( const Value &other ) -{ - Value temp( other ); - swap( temp ); - return *this; -} - -void -Value::swap( Value &other ) -{ - ValueType temp = type_; - type_ = other.type_; - other.type_ = temp; - std::swap( value_, other.value_ ); - int temp2 = allocated_; - allocated_ = other.allocated_; - other.allocated_ = temp2; -} - -ValueType -Value::type() const -{ - return type_; -} - - -int -Value::compare( const Value &other ) -{ - /* - int typeDelta = other.type_ - type_; - switch ( type_ ) - { - case nullValue: - - return other.type_ == type_; - case intValue: - if ( other.type_.isNumeric() - case uintValue: - case realValue: - case booleanValue: - break; - case stringValue, - break; - case arrayValue: - delete value_.array_; - break; - case objectValue: - delete value_.map_; - default: - JSON_ASSERT_UNREACHABLE; - } - */ - (void) other; - return 0; // unreachable -} - -bool -Value::operator <( const Value &other ) const -{ - int typeDelta = type_ - other.type_; - if ( typeDelta ) - return typeDelta < 0 ? true : false; - switch ( type_ ) - { - case nullValue: - return false; - case intValue: - return value_.int_ < other.value_.int_; - case uintValue: - return value_.uint_ < other.value_.uint_; - case realValue: - return value_.real_ < other.value_.real_; - case booleanValue: - return value_.bool_ < other.value_.bool_; - case stringValue: - return ( value_.string_ == 0 && other.value_.string_ ) - || ( other.value_.string_ - && value_.string_ - && strcmp( value_.string_, other.value_.string_ ) < 0 ); + default: + JSON_ASSERT_UNREACHABLE; + } + + if (comments_) + delete[] comments_; +} + +Value& Value::operator=(const Value& other) +{ + Value temp(other); + swap(temp); + return *this; +} + +void Value::swap(Value& other) +{ + ValueType temp = type_; + type_ = other.type_; + other.type_ = temp; + std::swap(value_, other.value_); + int temp2 = allocated_; + allocated_ = other.allocated_; + other.allocated_ = temp2; +} + +ValueType Value::type() const +{ + return type_; +} + +int Value::compare(const Value& other) +{ + /* + int typeDelta = other.type_ - type_; + switch ( type_ ) + { + case nullValue: + + return other.type_ == type_; + case intValue: + if ( other.type_.isNumeric() + case uintValue: + case realValue: + case booleanValue: + break; + case stringValue, + break; + case arrayValue: + delete value_.array_; + break; + case objectValue: + delete value_.map_; + default: + JSON_ASSERT_UNREACHABLE; + } + */ + (void)other; + return 0; // unreachable +} + +bool Value::operator<(const Value& other) const +{ + int typeDelta = type_ - other.type_; + if (typeDelta) + return typeDelta < 0 ? true : false; + switch (type_) + { + case nullValue: + return false; + case intValue: + return value_.int_ < other.value_.int_; + case uintValue: + return value_.uint_ < other.value_.uint_; + case realValue: + return value_.real_ < other.value_.real_; + case booleanValue: + return value_.bool_ < other.value_.bool_; + case stringValue: + return (value_.string_ == 0 && other.value_.string_) || + (other.value_.string_ && value_.string_ && strcmp(value_.string_, other.value_.string_) < 0); #ifndef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - case objectValue: - { - int delta = int( value_.map_->size() - other.value_.map_->size() ); - if ( delta ) - return delta < 0; - return (*value_.map_) < (*other.value_.map_); - } + case arrayValue: + case objectValue: + { + int delta = int(value_.map_->size() - other.value_.map_->size()); + if (delta) + return delta < 0; + return (*value_.map_) < (*other.value_.map_); + } #else - case arrayValue: - return value_.array_->compare( *(other.value_.array_) ) < 0; - case objectValue: - return value_.map_->compare( *(other.value_.map_) ) < 0; + case arrayValue: + return value_.array_->compare(*(other.value_.array_)) < 0; + case objectValue: + return value_.map_->compare(*(other.value_.map_)) < 0; #endif - default: - JSON_ASSERT_UNREACHABLE; - } - return 0; // unreachable + default: + JSON_ASSERT_UNREACHABLE; + } + return 0; // unreachable } -bool -Value::operator <=( const Value &other ) const +bool Value::operator<=(const Value& other) const { - return !(other > *this); + return !(other > *this); } -bool -Value::operator >=( const Value &other ) const +bool Value::operator>=(const Value& other) const { - return !(*this < other); + return !(*this < other); } -bool -Value::operator >( const Value &other ) const +bool Value::operator>(const Value& other) const { - return other < *this; + return other < *this; } -bool -Value::operator ==( const Value &other ) const +bool Value::operator==(const Value& other) const { - //if ( type_ != other.type_ ) - // GCC 2.95.3 says: - // attempt to take address of bit-field structure member `Json::Value::type_' - // Beats me, but a temp solves the problem. - int temp = other.type_; - if ( type_ != temp ) - return false; - switch ( type_ ) - { - case nullValue: - return true; - case intValue: - return value_.int_ == other.value_.int_; - case uintValue: - return value_.uint_ == other.value_.uint_; - case realValue: - return value_.real_ == other.value_.real_; - case booleanValue: - return value_.bool_ == other.value_.bool_; - case stringValue: - return ( value_.string_ == other.value_.string_ ) - || ( other.value_.string_ - && value_.string_ - && strcmp( value_.string_, other.value_.string_ ) == 0 ); + // if ( type_ != other.type_ ) + // GCC 2.95.3 says: + // attempt to take address of bit-field structure member `Json::Value::type_' + // Beats me, but a temp solves the problem. + int temp = other.type_; + if (type_ != temp) + return false; + switch (type_) + { + case nullValue: + return true; + case intValue: + return value_.int_ == other.value_.int_; + case uintValue: + return value_.uint_ == other.value_.uint_; + case realValue: + return value_.real_ == other.value_.real_; + case booleanValue: + return value_.bool_ == other.value_.bool_; + case stringValue: + return (value_.string_ == other.value_.string_) || + (other.value_.string_ && value_.string_ && strcmp(value_.string_, other.value_.string_) == 0); #ifndef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - case objectValue: - return value_.map_->size() == other.value_.map_->size() - && (*value_.map_) == (*other.value_.map_); + case arrayValue: + case objectValue: + return value_.map_->size() == other.value_.map_->size() && (*value_.map_) == (*other.value_.map_); #else - case arrayValue: - return value_.array_->compare( *(other.value_.array_) ) == 0; - case objectValue: - return value_.map_->compare( *(other.value_.map_) ) == 0; + case arrayValue: + return value_.array_->compare(*(other.value_.array_)) == 0; + case objectValue: + return value_.map_->compare(*(other.value_.map_)) == 0; #endif - default: - JSON_ASSERT_UNREACHABLE; - } - return 0; // unreachable -} - -bool -Value::operator !=( const Value &other ) const -{ - return !( *this == other ); -} - -const char * -Value::asCString() const -{ - JSON_ASSERT( type_ == stringValue ); - return value_.string_; -} - - -std::string -Value::asString() const -{ - switch ( type_ ) - { - case nullValue: - return ""; - case stringValue: - return value_.string_ ? value_.string_ : ""; - case booleanValue: - return value_.bool_ ? "true" : "false"; - case intValue: - case uintValue: - case realValue: - case arrayValue: - case objectValue: - JSON_ASSERT_MESSAGE( false, "Type is not convertible to string" ); - default: - JSON_ASSERT_UNREACHABLE; - } - return ""; // unreachable -} - -# ifdef JSON_USE_CPPTL -CppTL::ConstString -Value::asConstString() const -{ - return CppTL::ConstString( asString().c_str() ); -} -# endif - -Value::Int -Value::asInt() const -{ - switch ( type_ ) - { - case nullValue: - return 0; - case intValue: - return value_.int_; - case uintValue: - JSON_ASSERT_MESSAGE( value_.uint_ < (unsigned)maxInt, "integer out of signed integer range" ); - return value_.uint_; - case realValue: - JSON_ASSERT_MESSAGE( value_.real_ >= minInt && value_.real_ <= maxInt, "Real out of signed integer range" ); - return Int( value_.real_ ); - case booleanValue: - return value_.bool_ ? 1 : 0; - case stringValue: - case arrayValue: - case objectValue: - JSON_ASSERT_MESSAGE( false, "Type is not convertible to int" ); - default: - JSON_ASSERT_UNREACHABLE; - } - return 0; // unreachable; -} - -Value::UInt -Value::asUInt() const -{ - switch ( type_ ) - { - case nullValue: - return 0; - case intValue: - JSON_ASSERT_MESSAGE( value_.int_ >= 0, "Negative integer can not be converted to unsigned integer" ); - return value_.int_; - case uintValue: - return value_.uint_; - case realValue: - JSON_ASSERT_MESSAGE( value_.real_ >= 0 && value_.real_ <= maxUInt, "Real out of unsigned integer range" ); - return UInt( value_.real_ ); - case booleanValue: - return value_.bool_ ? 1 : 0; - case stringValue: - case arrayValue: - case objectValue: - JSON_ASSERT_MESSAGE( false, "Type is not convertible to uint" ); - default: - JSON_ASSERT_UNREACHABLE; - } - return 0; // unreachable; -} - -double -Value::asDouble() const -{ - switch ( type_ ) - { - case nullValue: - return 0.0; - case intValue: - return value_.int_; - case uintValue: - return value_.uint_; - case realValue: - return value_.real_; - case booleanValue: - return value_.bool_ ? 1.0 : 0.0; - case stringValue: - case arrayValue: - case objectValue: - JSON_ASSERT_MESSAGE( false, "Type is not convertible to double" ); - default: - JSON_ASSERT_UNREACHABLE; - } - return 0; // unreachable; -} - -bool -Value::asBool() const -{ - switch ( type_ ) - { - case nullValue: - return false; - case intValue: - case uintValue: - return value_.int_ != 0; - case realValue: - return value_.real_ != 0.0; - case booleanValue: - return value_.bool_; - case stringValue: - return value_.string_ && value_.string_[0] != 0; - case arrayValue: - case objectValue: - return value_.map_->size() != 0; - default: - JSON_ASSERT_UNREACHABLE; - } - return false; // unreachable; -} - - -bool -Value::isConvertibleTo( ValueType other ) const -{ - switch ( type_ ) - { - case nullValue: - return true; - case intValue: - return ( other == nullValue && value_.int_ == 0 ) - || other == intValue - || ( other == uintValue && value_.int_ >= 0 ) - || other == realValue - || other == stringValue - || other == booleanValue; - case uintValue: - return ( other == nullValue && value_.uint_ == 0 ) - || ( other == intValue && value_.uint_ <= (unsigned)maxInt ) - || other == uintValue - || other == realValue - || other == stringValue - || other == booleanValue; - case realValue: - return ( other == nullValue && value_.real_ == 0.0 ) - || ( other == intValue && value_.real_ >= minInt && value_.real_ <= maxInt ) - || ( other == uintValue && value_.real_ >= 0 && value_.real_ <= maxUInt ) - || other == realValue - || other == stringValue - || other == booleanValue; - case booleanValue: - return ( other == nullValue && value_.bool_ == false ) - || other == intValue - || other == uintValue - || other == realValue - || other == stringValue - || other == booleanValue; - case stringValue: - return other == stringValue - || ( other == nullValue && (!value_.string_ || value_.string_[0] == 0) ); - case arrayValue: - return other == arrayValue - || ( other == nullValue && value_.map_->size() == 0 ); - case objectValue: - return other == objectValue - || ( other == nullValue && value_.map_->size() == 0 ); - default: - JSON_ASSERT_UNREACHABLE; - } - return false; // unreachable; + default: + JSON_ASSERT_UNREACHABLE; + } + return 0; // unreachable +} + +bool Value::operator!=(const Value& other) const +{ + return !(*this == other); +} + +const char* Value::asCString() const +{ + JSON_ASSERT(type_ == stringValue); + return value_.string_; +} + +std::string Value::asString() const +{ + switch (type_) + { + case nullValue: + return ""; + case stringValue: + return value_.string_ ? value_.string_ : ""; + case booleanValue: + return value_.bool_ ? "true" : "false"; + case intValue: + case uintValue: + case realValue: + case arrayValue: + case objectValue: + JSON_ASSERT_MESSAGE(false, "Type is not convertible to string"); + default: + JSON_ASSERT_UNREACHABLE; + } + return ""; // unreachable } +#ifdef JSON_USE_CPPTL +CppTL::ConstString Value::asConstString() const +{ + return CppTL::ConstString(asString().c_str()); +} +#endif + +Value::Int Value::asInt() const +{ + switch (type_) + { + case nullValue: + return 0; + case intValue: + return value_.int_; + case uintValue: + JSON_ASSERT_MESSAGE(value_.uint_ < (unsigned)maxInt, "integer out of signed integer range"); + return value_.uint_; + case realValue: + JSON_ASSERT_MESSAGE(value_.real_ >= minInt && value_.real_ <= maxInt, "Real out of signed integer range"); + return Int(value_.real_); + case booleanValue: + return value_.bool_ ? 1 : 0; + case stringValue: + case arrayValue: + case objectValue: + JSON_ASSERT_MESSAGE(false, "Type is not convertible to int"); + default: + JSON_ASSERT_UNREACHABLE; + } + return 0; // unreachable; +} + +Value::UInt Value::asUInt() const +{ + switch (type_) + { + case nullValue: + return 0; + case intValue: + JSON_ASSERT_MESSAGE(value_.int_ >= 0, "Negative integer can not be converted to unsigned integer"); + return value_.int_; + case uintValue: + return value_.uint_; + case realValue: + JSON_ASSERT_MESSAGE(value_.real_ >= 0 && value_.real_ <= maxUInt, "Real out of unsigned integer range"); + return UInt(value_.real_); + case booleanValue: + return value_.bool_ ? 1 : 0; + case stringValue: + case arrayValue: + case objectValue: + JSON_ASSERT_MESSAGE(false, "Type is not convertible to uint"); + default: + JSON_ASSERT_UNREACHABLE; + } + return 0; // unreachable; +} + +double Value::asDouble() const +{ + switch (type_) + { + case nullValue: + return 0.0; + case intValue: + return value_.int_; + case uintValue: + return value_.uint_; + case realValue: + return value_.real_; + case booleanValue: + return value_.bool_ ? 1.0 : 0.0; + case stringValue: + case arrayValue: + case objectValue: + JSON_ASSERT_MESSAGE(false, "Type is not convertible to double"); + default: + JSON_ASSERT_UNREACHABLE; + } + return 0; // unreachable; +} + +bool Value::asBool() const +{ + switch (type_) + { + case nullValue: + return false; + case intValue: + case uintValue: + return value_.int_ != 0; + case realValue: + return value_.real_ != 0.0; + case booleanValue: + return value_.bool_; + case stringValue: + return value_.string_ && value_.string_[0] != 0; + case arrayValue: + case objectValue: + return value_.map_->size() != 0; + default: + JSON_ASSERT_UNREACHABLE; + } + return false; // unreachable; +} + +bool Value::isConvertibleTo(ValueType other) const +{ + switch (type_) + { + case nullValue: + return true; + case intValue: + return (other == nullValue && value_.int_ == 0) || other == intValue || + (other == uintValue && value_.int_ >= 0) || other == realValue || other == stringValue || + other == booleanValue; + case uintValue: + return (other == nullValue && value_.uint_ == 0) || + (other == intValue && value_.uint_ <= (unsigned)maxInt) || other == uintValue || + other == realValue || other == stringValue || other == booleanValue; + case realValue: + return (other == nullValue && value_.real_ == 0.0) || + (other == intValue && value_.real_ >= minInt && value_.real_ <= maxInt) || + (other == uintValue && value_.real_ >= 0 && value_.real_ <= maxUInt) || other == realValue || + other == stringValue || other == booleanValue; + case booleanValue: + return (other == nullValue && value_.bool_ == false) || other == intValue || other == uintValue || + other == realValue || other == stringValue || other == booleanValue; + case stringValue: + return other == stringValue || (other == nullValue && (!value_.string_ || value_.string_[0] == 0)); + case arrayValue: + return other == arrayValue || (other == nullValue && value_.map_->size() == 0); + case objectValue: + return other == objectValue || (other == nullValue && value_.map_->size() == 0); + default: + JSON_ASSERT_UNREACHABLE; + } + return false; // unreachable; +} /// Number of values in array or object -Value::UInt -Value::size() const -{ - switch ( type_ ) - { - case nullValue: - case intValue: - case uintValue: - case realValue: - case booleanValue: - case stringValue: - return 0; +Value::UInt Value::size() const +{ + switch (type_) + { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + case stringValue: + return 0; #ifndef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: // size of the array is highest index + 1 - if ( !value_.map_->empty() ) - { - ObjectValues::const_iterator itLast = value_.map_->end(); - --itLast; - return (*itLast).first.index()+1; - } - return 0; - case objectValue: - return Int( value_.map_->size() ); + case arrayValue: // size of the array is highest index + 1 + if (!value_.map_->empty()) + { + ObjectValues::const_iterator itLast = value_.map_->end(); + --itLast; + return (*itLast).first.index() + 1; + } + return 0; + case objectValue: + return Int(value_.map_->size()); #else - case arrayValue: - return Int( value_.array_->size() ); - case objectValue: - return Int( value_.map_->size() ); + case arrayValue: + return Int(value_.array_->size()); + case objectValue: + return Int(value_.map_->size()); #endif - default: - JSON_ASSERT_UNREACHABLE; - } - return 0; // unreachable; + default: + JSON_ASSERT_UNREACHABLE; + } + return 0; // unreachable; } - -bool -Value::empty() const +bool Value::empty() const { - if ( isNull() || isArray() || isObject() ) - return size() == 0u; - else - return false; + if (isNull() || isArray() || isObject()) + return size() == 0u; + else + return false; } - -bool -Value::operator!() const +bool Value::operator!() const { - return isNull(); + return isNull(); } - -void -Value::clear() +void Value::clear() { - JSON_ASSERT( type_ == nullValue || type_ == arrayValue || type_ == objectValue ); + JSON_ASSERT(type_ == nullValue || type_ == arrayValue || type_ == objectValue); - switch ( type_ ) - { + switch (type_) + { #ifndef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - case objectValue: - value_.map_->clear(); - break; + case arrayValue: + case objectValue: + value_.map_->clear(); + break; #else - case arrayValue: - value_.array_->clear(); - break; - case objectValue: - value_.map_->clear(); - break; + case arrayValue: + value_.array_->clear(); + break; + case objectValue: + value_.map_->clear(); + break; #endif - default: - break; - } + default: + break; + } } -void -Value::resize( UInt newSize ) +void Value::resize(UInt newSize) { - JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); - if ( type_ == nullValue ) - *this = Value( arrayValue ); + JSON_ASSERT(type_ == nullValue || type_ == arrayValue); + if (type_ == nullValue) + *this = Value(arrayValue); #ifndef JSON_VALUE_USE_INTERNAL_MAP - UInt oldSize = size(); - if ( newSize == 0 ) - clear(); - else if ( newSize > oldSize ) - (*this)[ newSize - 1 ]; - else - { - for ( UInt index = newSize; index < oldSize; ++index ) - value_.map_->erase( index ); - assert( size() == newSize ); - } + UInt oldSize = size(); + if (newSize == 0) + clear(); + else if (newSize > oldSize) + (*this)[newSize - 1]; + else + { + for (UInt index = newSize; index < oldSize; ++index) + value_.map_->erase(index); + assert(size() == newSize); + } #else - value_.array_->resize( newSize ); + value_.array_->resize(newSize); #endif } - -Value & -Value::operator[]( UInt index ) +Value& Value::operator[](UInt index) { - JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); - if ( type_ == nullValue ) - *this = Value( arrayValue ); + JSON_ASSERT(type_ == nullValue || type_ == arrayValue); + if (type_ == nullValue) + *this = Value(arrayValue); #ifndef JSON_VALUE_USE_INTERNAL_MAP - CZString key( index ); - ObjectValues::iterator it = value_.map_->lower_bound( key ); - if ( it != value_.map_->end() && (*it).first == key ) - return (*it).second; - - ObjectValues::value_type defaultValue( key, null ); - it = value_.map_->insert( it, defaultValue ); - return (*it).second; + CZString key(index); + ObjectValues::iterator it = value_.map_->lower_bound(key); + if (it != value_.map_->end() && (*it).first == key) + return (*it).second; + + ObjectValues::value_type defaultValue(key, null); + it = value_.map_->insert(it, defaultValue); + return (*it).second; #else - return value_.array_->resolveReference( index ); + return value_.array_->resolveReference(index); #endif } - -const Value & -Value::operator[]( UInt index ) const +const Value& Value::operator[](UInt index) const { - JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); - if ( type_ == nullValue ) - return null; + JSON_ASSERT(type_ == nullValue || type_ == arrayValue); + if (type_ == nullValue) + return null; #ifndef JSON_VALUE_USE_INTERNAL_MAP - CZString key( index ); - ObjectValues::const_iterator it = value_.map_->find( key ); - if ( it == value_.map_->end() ) - return null; - return (*it).second; + CZString key(index); + ObjectValues::const_iterator it = value_.map_->find(key); + if (it == value_.map_->end()) + return null; + return (*it).second; #else - Value *value = value_.array_->find( index ); - return value ? *value : null; + Value* value = value_.array_->find(index); + return value ? *value : null; #endif } - -Value & -Value::operator[]( const char *key ) +Value& Value::operator[](const char* key) { - return resolveReference( key, false ); + return resolveReference(key, false); } - -Value & -Value::resolveReference( const char *key, - bool isStatic ) +Value& Value::resolveReference(const char* key, bool isStatic) { - JSON_ASSERT( type_ == nullValue || type_ == objectValue ); - if ( type_ == nullValue ) - *this = Value( objectValue ); + JSON_ASSERT(type_ == nullValue || type_ == objectValue); + if (type_ == nullValue) + *this = Value(objectValue); #ifndef JSON_VALUE_USE_INTERNAL_MAP - CZString actualKey( key, isStatic ? CZString::noDuplication - : CZString::duplicateOnCopy ); - ObjectValues::iterator it = value_.map_->lower_bound( actualKey ); - if ( it != value_.map_->end() && (*it).first == actualKey ) - return (*it).second; - - ObjectValues::value_type defaultValue( actualKey, null ); - it = value_.map_->insert( it, defaultValue ); - Value &value = (*it).second; - return value; + CZString actualKey(key, isStatic ? CZString::noDuplication : CZString::duplicateOnCopy); + ObjectValues::iterator it = value_.map_->lower_bound(actualKey); + if (it != value_.map_->end() && (*it).first == actualKey) + return (*it).second; + + ObjectValues::value_type defaultValue(actualKey, null); + it = value_.map_->insert(it, defaultValue); + Value& value = (*it).second; + return value; #else - return value_.map_->resolveReference( key, isStatic ); + return value_.map_->resolveReference(key, isStatic); #endif } - -Value -Value::get( UInt index, - const Value &defaultValue ) const +Value Value::get(UInt index, const Value& defaultValue) const { - const Value *value = &((*this)[index]); - return value == &null ? defaultValue : *value; + const Value* value = &((*this)[index]); + return value == &null ? defaultValue : *value; } - -bool -Value::isValidIndex( UInt index ) const +bool Value::isValidIndex(UInt index) const { - return index < size(); + return index < size(); } - - -const Value & -Value::operator[]( const char *key ) const +const Value& Value::operator[](const char* key) const { - JSON_ASSERT( type_ == nullValue || type_ == objectValue ); - if ( type_ == nullValue ) - return null; + JSON_ASSERT(type_ == nullValue || type_ == objectValue); + if (type_ == nullValue) + return null; #ifndef JSON_VALUE_USE_INTERNAL_MAP - CZString actualKey( key, CZString::noDuplication ); - ObjectValues::const_iterator it = value_.map_->find( actualKey ); - if ( it == value_.map_->end() ) - return null; - return (*it).second; + CZString actualKey(key, CZString::noDuplication); + ObjectValues::const_iterator it = value_.map_->find(actualKey); + if (it == value_.map_->end()) + return null; + return (*it).second; #else - const Value *value = value_.map_->find( key ); - return value ? *value : null; + const Value* value = value_.map_->find(key); + return value ? *value : null; #endif } - -Value & -Value::operator[]( const std::string &key ) +Value& Value::operator[](const std::string& key) { - return (*this)[ key.c_str() ]; + return (*this)[key.c_str()]; } - -const Value & -Value::operator[]( const std::string &key ) const +const Value& Value::operator[](const std::string& key) const { - return (*this)[ key.c_str() ]; + return (*this)[key.c_str()]; } -Value & -Value::operator[]( const StaticString &key ) +Value& Value::operator[](const StaticString& key) { - return resolveReference( key, true ); + return resolveReference(key, true); } - -# ifdef JSON_USE_CPPTL -Value & -Value::operator[]( const CppTL::ConstString &key ) +#ifdef JSON_USE_CPPTL +Value& Value::operator[](const CppTL::ConstString& key) { - return (*this)[ key.c_str() ]; + return (*this)[key.c_str()]; } - -const Value & -Value::operator[]( const CppTL::ConstString &key ) const +const Value& Value::operator[](const CppTL::ConstString& key) const { - return (*this)[ key.c_str() ]; + return (*this)[key.c_str()]; } -# endif - +#endif -Value & -Value::append( const Value &value ) +Value& Value::append(const Value& value) { - return (*this)[size()] = value; + return (*this)[size()] = value; } - -Value -Value::get( const char *key, - const Value &defaultValue ) const +Value Value::get(const char* key, const Value& defaultValue) const { - const Value *value = &((*this)[key]); - return value == &null ? defaultValue : *value; + const Value* value = &((*this)[key]); + return value == &null ? defaultValue : *value; } - -Value -Value::get( const std::string &key, - const Value &defaultValue ) const +Value Value::get(const std::string& key, const Value& defaultValue) const { - return get( key.c_str(), defaultValue ); + return get(key.c_str(), defaultValue); } -Value -Value::removeMember( const char* key ) +Value Value::removeMember(const char* key) { - JSON_ASSERT( type_ == nullValue || type_ == objectValue ); - if ( type_ == nullValue ) - return null; + JSON_ASSERT(type_ == nullValue || type_ == objectValue); + if (type_ == nullValue) + return null; #ifndef JSON_VALUE_USE_INTERNAL_MAP - CZString actualKey( key, CZString::noDuplication ); - ObjectValues::iterator it = value_.map_->find( actualKey ); - if ( it == value_.map_->end() ) - return null; - Value old(it->second); - value_.map_->erase(it); - return old; + CZString actualKey(key, CZString::noDuplication); + ObjectValues::iterator it = value_.map_->find(actualKey); + if (it == value_.map_->end()) + return null; + Value old(it->second); + value_.map_->erase(it); + return old; #else - Value *value = value_.map_->find( key ); - if (value){ - Value old(*value); - value_.map_.remove( key ); - return old; - } else { - return null; - } + Value* value = value_.map_->find(key); + if (value) + { + Value old(*value); + value_.map_.remove(key); + return old; + } + else + { + return null; + } #endif } -Value -Value::removeMember( const std::string &key ) +Value Value::removeMember(const std::string& key) { - return removeMember( key.c_str() ); + return removeMember(key.c_str()); } -# ifdef JSON_USE_CPPTL -Value -Value::get( const CppTL::ConstString &key, - const Value &defaultValue ) const +#ifdef JSON_USE_CPPTL +Value Value::get(const CppTL::ConstString& key, const Value& defaultValue) const { - return get( key.c_str(), defaultValue ); + return get(key.c_str(), defaultValue); } -# endif +#endif -bool -Value::isMember( const char *key ) const +bool Value::isMember(const char* key) const { - const Value *value = &((*this)[key]); - return value != &null; + const Value* value = &((*this)[key]); + return value != &null; } - -bool -Value::isMember( const std::string &key ) const +bool Value::isMember(const std::string& key) const { - return isMember( key.c_str() ); + return isMember(key.c_str()); } - -# ifdef JSON_USE_CPPTL -bool -Value::isMember( const CppTL::ConstString &key ) const +#ifdef JSON_USE_CPPTL +bool Value::isMember(const CppTL::ConstString& key) const { - return isMember( key.c_str() ); + return isMember(key.c_str()); } #endif -Value::Members -Value::getMemberNames() const +Value::Members Value::getMemberNames() const { - JSON_ASSERT( type_ == nullValue || type_ == objectValue ); - if ( type_ == nullValue ) - return Value::Members(); - Members members; - members.reserve( value_.map_->size() ); + JSON_ASSERT(type_ == nullValue || type_ == objectValue); + if (type_ == nullValue) + return Value::Members(); + Members members; + members.reserve(value_.map_->size()); #ifndef JSON_VALUE_USE_INTERNAL_MAP - ObjectValues::const_iterator it = value_.map_->begin(); - ObjectValues::const_iterator itEnd = value_.map_->end(); - for ( ; it != itEnd; ++it ) - members.push_back( std::string( (*it).first.c_str() ) ); + ObjectValues::const_iterator it = value_.map_->begin(); + ObjectValues::const_iterator itEnd = value_.map_->end(); + for (; it != itEnd; ++it) + members.push_back(std::string((*it).first.c_str())); #else - ValueInternalMap::IteratorState it; - ValueInternalMap::IteratorState itEnd; - value_.map_->makeBeginIterator( it ); - value_.map_->makeEndIterator( itEnd ); - for ( ; !ValueInternalMap::equals( it, itEnd ); ValueInternalMap::increment(it) ) - members.push_back( std::string( ValueInternalMap::key( it ) ) ); + ValueInternalMap::IteratorState it; + ValueInternalMap::IteratorState itEnd; + value_.map_->makeBeginIterator(it); + value_.map_->makeEndIterator(itEnd); + for (; !ValueInternalMap::equals(it, itEnd); ValueInternalMap::increment(it)) + members.push_back(std::string(ValueInternalMap::key(it))); #endif - return members; + return members; } // //# ifdef JSON_USE_CPPTL -//EnumMemberNames -//Value::enumMemberNames() const +// EnumMemberNames +// Value::enumMemberNames() const //{ // if ( type_ == objectValue ) // { @@ -1245,8 +1117,8 @@ Value::getMemberNames() const //} // // -//EnumValues -//Value::enumValues() const +// EnumValues +// Value::enumValues() const //{ // if ( type_ == objectValue || type_ == arrayValue ) // return CppTL::Enum::anyValues( *(value_.map_), @@ -1256,472 +1128,398 @@ Value::getMemberNames() const // //# endif - -bool -Value::isNull() const +bool Value::isNull() const { - return type_ == nullValue; + return type_ == nullValue; } - -bool -Value::isBool() const +bool Value::isBool() const { - return type_ == booleanValue; + return type_ == booleanValue; } - -bool -Value::isInt() const +bool Value::isInt() const { - return type_ == intValue; + return type_ == intValue; } - -bool -Value::isUInt() const +bool Value::isUInt() const { - return type_ == uintValue; + return type_ == uintValue; } - -bool -Value::isIntegral() const +bool Value::isIntegral() const { - return type_ == intValue - || type_ == uintValue - || type_ == booleanValue; + return type_ == intValue || type_ == uintValue || type_ == booleanValue; } - -bool -Value::isDouble() const +bool Value::isDouble() const { - return type_ == realValue; + return type_ == realValue; } - -bool -Value::isNumeric() const +bool Value::isNumeric() const { - return isIntegral() || isDouble(); + return isIntegral() || isDouble(); } - -bool -Value::isString() const +bool Value::isString() const { - return type_ == stringValue; + return type_ == stringValue; } - -bool -Value::isArray() const +bool Value::isArray() const { - return type_ == nullValue || type_ == arrayValue; + return type_ == nullValue || type_ == arrayValue; } - -bool -Value::isObject() const +bool Value::isObject() const { - return type_ == nullValue || type_ == objectValue; + return type_ == nullValue || type_ == objectValue; } - -void -Value::setComment( const char *comment, - CommentPlacement placement ) +void Value::setComment(const char* comment, CommentPlacement placement) { - if ( !comments_ ) - comments_ = new CommentInfo[numberOfCommentPlacement]; - comments_[placement].setComment( comment ); + if (!comments_) + comments_ = new CommentInfo[numberOfCommentPlacement]; + comments_[placement].setComment(comment); } - -void -Value::setComment( const std::string &comment, - CommentPlacement placement ) +void Value::setComment(const std::string& comment, CommentPlacement placement) { - setComment( comment.c_str(), placement ); + setComment(comment.c_str(), placement); } - -bool -Value::hasComment( CommentPlacement placement ) const +bool Value::hasComment(CommentPlacement placement) const { - return comments_ != 0 && comments_[placement].comment_ != 0; + return comments_ != 0 && comments_[placement].comment_ != 0; } -std::string -Value::getComment( CommentPlacement placement ) const +std::string Value::getComment(CommentPlacement placement) const { - if ( hasComment(placement) ) - return comments_[placement].comment_; - return ""; + if (hasComment(placement)) + return comments_[placement].comment_; + return ""; } - -std::string -Value::toStyledString() const +std::string Value::toStyledString() const { - StyledWriter writer; - return writer.write( *this ); + StyledWriter writer; + return writer.write(*this); } - -Value::const_iterator -Value::begin() const +Value::const_iterator Value::begin() const { - switch ( type_ ) - { + switch (type_) + { #ifdef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - if ( value_.array_ ) - { - ValueInternalArray::IteratorState it; - value_.array_->makeBeginIterator( it ); - return const_iterator( it ); - } - break; - case objectValue: - if ( value_.map_ ) - { - ValueInternalMap::IteratorState it; - value_.map_->makeBeginIterator( it ); - return const_iterator( it ); - } - break; + case arrayValue: + if (value_.array_) + { + ValueInternalArray::IteratorState it; + value_.array_->makeBeginIterator(it); + return const_iterator(it); + } + break; + case objectValue: + if (value_.map_) + { + ValueInternalMap::IteratorState it; + value_.map_->makeBeginIterator(it); + return const_iterator(it); + } + break; #else - case arrayValue: - case objectValue: - if ( value_.map_ ) - return const_iterator( value_.map_->begin() ); - break; + case arrayValue: + case objectValue: + if (value_.map_) + return const_iterator(value_.map_->begin()); + break; #endif - default: - break; - } - return const_iterator(); + default: + break; + } + return const_iterator(); } -Value::const_iterator -Value::end() const +Value::const_iterator Value::end() const { - switch ( type_ ) - { + switch (type_) + { #ifdef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - if ( value_.array_ ) - { - ValueInternalArray::IteratorState it; - value_.array_->makeEndIterator( it ); - return const_iterator( it ); - } - break; - case objectValue: - if ( value_.map_ ) - { - ValueInternalMap::IteratorState it; - value_.map_->makeEndIterator( it ); - return const_iterator( it ); - } - break; + case arrayValue: + if (value_.array_) + { + ValueInternalArray::IteratorState it; + value_.array_->makeEndIterator(it); + return const_iterator(it); + } + break; + case objectValue: + if (value_.map_) + { + ValueInternalMap::IteratorState it; + value_.map_->makeEndIterator(it); + return const_iterator(it); + } + break; #else - case arrayValue: - case objectValue: - if ( value_.map_ ) - return const_iterator( value_.map_->end() ); - break; + case arrayValue: + case objectValue: + if (value_.map_) + return const_iterator(value_.map_->end()); + break; #endif - default: - break; - } - return const_iterator(); + default: + break; + } + return const_iterator(); } - -Value::iterator -Value::begin() +Value::iterator Value::begin() { - switch ( type_ ) - { + switch (type_) + { #ifdef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - if ( value_.array_ ) - { - ValueInternalArray::IteratorState it; - value_.array_->makeBeginIterator( it ); - return iterator( it ); - } - break; - case objectValue: - if ( value_.map_ ) - { - ValueInternalMap::IteratorState it; - value_.map_->makeBeginIterator( it ); - return iterator( it ); - } - break; + case arrayValue: + if (value_.array_) + { + ValueInternalArray::IteratorState it; + value_.array_->makeBeginIterator(it); + return iterator(it); + } + break; + case objectValue: + if (value_.map_) + { + ValueInternalMap::IteratorState it; + value_.map_->makeBeginIterator(it); + return iterator(it); + } + break; #else - case arrayValue: - case objectValue: - if ( value_.map_ ) - return iterator( value_.map_->begin() ); - break; + case arrayValue: + case objectValue: + if (value_.map_) + return iterator(value_.map_->begin()); + break; #endif - default: - break; - } - return iterator(); + default: + break; + } + return iterator(); } -Value::iterator -Value::end() +Value::iterator Value::end() { - switch ( type_ ) - { + switch (type_) + { #ifdef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - if ( value_.array_ ) - { - ValueInternalArray::IteratorState it; - value_.array_->makeEndIterator( it ); - return iterator( it ); - } - break; - case objectValue: - if ( value_.map_ ) - { - ValueInternalMap::IteratorState it; - value_.map_->makeEndIterator( it ); - return iterator( it ); - } - break; + case arrayValue: + if (value_.array_) + { + ValueInternalArray::IteratorState it; + value_.array_->makeEndIterator(it); + return iterator(it); + } + break; + case objectValue: + if (value_.map_) + { + ValueInternalMap::IteratorState it; + value_.map_->makeEndIterator(it); + return iterator(it); + } + break; #else - case arrayValue: - case objectValue: - if ( value_.map_ ) - return iterator( value_.map_->end() ); - break; + case arrayValue: + case objectValue: + if (value_.map_) + return iterator(value_.map_->end()); + break; #endif - default: - break; - } - return iterator(); + default: + break; + } + return iterator(); } - // class PathArgument // ////////////////////////////////////////////////////////////////// -PathArgument::PathArgument() - : kind_( kindNone ) -{ -} - +PathArgument::PathArgument() : kind_(kindNone) {} -PathArgument::PathArgument( Value::UInt index ) - : index_( index ) - , kind_( kindIndex ) -{ -} - - -PathArgument::PathArgument( const char *key ) - : key_( key ) - , kind_( kindKey ) -{ -} +PathArgument::PathArgument(Value::UInt index) : index_(index), kind_(kindIndex) {} +PathArgument::PathArgument(const char* key) : key_(key), kind_(kindKey) {} -PathArgument::PathArgument( const std::string &key ) - : key_( key.c_str() ) - , kind_( kindKey ) -{ -} +PathArgument::PathArgument(const std::string& key) : key_(key.c_str()), kind_(kindKey) {} // class Path // ////////////////////////////////////////////////////////////////// -Path::Path( const std::string &path, - const PathArgument &a1, - const PathArgument &a2, - const PathArgument &a3, - const PathArgument &a4, - const PathArgument &a5 ) -{ - InArgs in; - in.push_back( &a1 ); - in.push_back( &a2 ); - in.push_back( &a3 ); - in.push_back( &a4 ); - in.push_back( &a5 ); - makePath( path, in ); -} - - -void -Path::makePath( const std::string &path, - const InArgs &in ) -{ - const char *current = path.c_str(); - const char *end = current + path.length(); - InArgs::const_iterator itInArg = in.begin(); - while ( current != end ) - { - if ( *current == '[' ) - { - ++current; - if ( *current == '%' ) - addPathInArg( path, in, itInArg, PathArgument::kindIndex ); - else - { - Value::UInt index = 0; - for ( ; current != end && *current >= '0' && *current <= '9'; ++current ) - index = index * 10 + Value::UInt(*current - '0'); - args_.push_back( index ); - } - if ( current == end || *current++ != ']' ) - invalidPath( path, int(current - path.c_str()) ); - } - else if ( *current == '%' ) - { - addPathInArg( path, in, itInArg, PathArgument::kindKey ); - ++current; - } - else if ( *current == '.' ) - { - ++current; - } - else - { - const char *beginName = current; - while ( current != end && !strchr( "[.", *current ) ) +Path::Path(const std::string& path, + const PathArgument& a1, + const PathArgument& a2, + const PathArgument& a3, + const PathArgument& a4, + const PathArgument& a5) +{ + InArgs in; + in.push_back(&a1); + in.push_back(&a2); + in.push_back(&a3); + in.push_back(&a4); + in.push_back(&a5); + makePath(path, in); +} + +void Path::makePath(const std::string& path, const InArgs& in) +{ + const char* current = path.c_str(); + const char* end = current + path.length(); + InArgs::const_iterator itInArg = in.begin(); + while (current != end) + { + if (*current == '[') + { ++current; - args_.push_back( std::string( beginName, current ) ); - } - } -} - - -void -Path::addPathInArg( const std::string &path, - const InArgs &in, - InArgs::const_iterator &itInArg, - PathArgument::Kind kind ) -{ - (void)path; - if ( itInArg == in.end() ) - { - // Error: missing argument %d - } - else if ( (*itInArg)->kind_ != kind ) - { - // Error: bad argument type - } - else - { - args_.push_back( **itInArg ); - } -} - - -void -Path::invalidPath( const std::string &path, - int location ) + if (*current == '%') + addPathInArg(path, in, itInArg, PathArgument::kindIndex); + else + { + Value::UInt index = 0; + for (; current != end && *current >= '0' && *current <= '9'; ++current) + index = index * 10 + Value::UInt(*current - '0'); + args_.push_back(index); + } + if (current == end || *current++ != ']') + invalidPath(path, int(current - path.c_str())); + } + else if (*current == '%') + { + addPathInArg(path, in, itInArg, PathArgument::kindKey); + ++current; + } + else if (*current == '.') + { + ++current; + } + else + { + const char* beginName = current; + while (current != end && !strchr("[.", *current)) + ++current; + args_.push_back(std::string(beginName, current)); + } + } +} + +void Path::addPathInArg(const std::string& path, + const InArgs& in, + InArgs::const_iterator& itInArg, + PathArgument::Kind kind) { - // Error: invalid path. + (void)path; + if (itInArg == in.end()) + { + // Error: missing argument %d + } + else if ((*itInArg)->kind_ != kind) + { + // Error: bad argument type + } + else + { + args_.push_back(**itInArg); + } +} + +void Path::invalidPath(const std::string& path, int location) +{ + // Error: invalid path. (void)path; (void)location; } - -const Value & -Path::resolve( const Value &root ) const -{ - const Value *node = &root; - for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) - { - const PathArgument &arg = *it; - if ( arg.kind_ == PathArgument::kindIndex ) - { - if ( !node->isArray() || node->isValidIndex( arg.index_ ) ) - { - // Error: unable to resolve path (array value expected at position... - } - node = &((*node)[arg.index_]); - } - else if ( arg.kind_ == PathArgument::kindKey ) - { - if ( !node->isObject() ) - { - // Error: unable to resolve path (object value expected at position...) - } - node = &((*node)[arg.key_]); - if ( node == &Value::null ) - { - // Error: unable to resolve path (object has no member named '' at position...) - } - } - } - return *node; -} - - -Value -Path::resolve( const Value &root, - const Value &defaultValue ) const -{ - const Value *node = &root; - for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) - { - const PathArgument &arg = *it; - if ( arg.kind_ == PathArgument::kindIndex ) - { - if ( !node->isArray() || node->isValidIndex( arg.index_ ) ) - return defaultValue; - node = &((*node)[arg.index_]); - } - else if ( arg.kind_ == PathArgument::kindKey ) - { - if ( !node->isObject() ) - return defaultValue; - node = &((*node)[arg.key_]); - if ( node == &Value::null ) - return defaultValue; - } - } - return *node; -} - - -Value & -Path::make( Value &root ) const -{ - Value *node = &root; - for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) - { - const PathArgument &arg = *it; - if ( arg.kind_ == PathArgument::kindIndex ) - { - if ( !node->isArray() ) - { - // Error: node is not an array at position ... - } - node = &((*node)[arg.index_]); - } - else if ( arg.kind_ == PathArgument::kindKey ) - { - if ( !node->isObject() ) - { - // Error: node is not an object at position... - } - node = &((*node)[arg.key_]); - } - } - return *node; +const Value& Path::resolve(const Value& root) const +{ + const Value* node = &root; + for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) + { + const PathArgument& arg = *it; + if (arg.kind_ == PathArgument::kindIndex) + { + if (!node->isArray() || node->isValidIndex(arg.index_)) + { + // Error: unable to resolve path (array value expected at position... + } + node = &((*node)[arg.index_]); + } + else if (arg.kind_ == PathArgument::kindKey) + { + if (!node->isObject()) + { + // Error: unable to resolve path (object value expected at position...) + } + node = &((*node)[arg.key_]); + if (node == &Value::null) + { + // Error: unable to resolve path (object has no member named '' at position...) + } + } + } + return *node; +} + +Value Path::resolve(const Value& root, const Value& defaultValue) const +{ + const Value* node = &root; + for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) + { + const PathArgument& arg = *it; + if (arg.kind_ == PathArgument::kindIndex) + { + if (!node->isArray() || node->isValidIndex(arg.index_)) + return defaultValue; + node = &((*node)[arg.index_]); + } + else if (arg.kind_ == PathArgument::kindKey) + { + if (!node->isObject()) + return defaultValue; + node = &((*node)[arg.key_]); + if (node == &Value::null) + return defaultValue; + } + } + return *node; +} + +Value& Path::make(Value& root) const +{ + Value* node = &root; + for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) + { + const PathArgument& arg = *it; + if (arg.kind_ == PathArgument::kindIndex) + { + if (!node->isArray()) + { + // Error: node is not an array at position ... + } + node = &((*node)[arg.index_]); + } + else if (arg.kind_ == PathArgument::kindKey) + { + if (!node->isObject()) + { + // Error: node is not an object at position... + } + node = &((*node)[arg.key_]); + } + } + return *node; } - } // namespace Json diff --git a/ext_libs/json/json_writer.cpp b/ext_libs/json/json_writer.cpp index 4c36c5bd..a74afaf5 100644 --- a/ext_libs/json/json_writer.cpp +++ b/ext_libs/json/json_writer.cpp @@ -3,7 +3,6 @@ // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - #include #include #include @@ -13,145 +12,145 @@ #include #include -#if _MSC_VER >= 1400 // VC++ 8.0 -#pragma warning( disable : 4996 ) // disable warning about strdup being deprecated. +#if _MSC_VER >= 1400 // VC++ 8.0 +#pragma warning(disable : 4996) // disable warning about strdup being deprecated. #endif -namespace Json { - +namespace Json +{ static bool isControlCharacter(char ch) { - return ch > 0 && ch <= 0x1F; + return ch > 0 && ch <= 0x1F; } -static bool containsControlCharacter( const char* str ) +static bool containsControlCharacter(const char* str) { - while ( *str ) - { - if ( isControlCharacter( *(str++) ) ) - return true; - } - return false; + while (*str) + { + if (isControlCharacter(*(str++))) + return true; + } + return false; } -static void uintToString( unsigned int value, - char *¤t ) +static void uintToString(unsigned int value, char*& current) { - *--current = 0; - do - { - *--current = (value % 10) + '0'; - value /= 10; - } - while ( value != 0 ); + *--current = 0; + do + { + *--current = (value % 10) + '0'; + value /= 10; + } while (value != 0); } -std::string valueToString( Int value ) +std::string valueToString(Int value) { - char buffer[32]; - char *current = buffer + sizeof(buffer); - bool isNegative = value < 0; - if ( isNegative ) - value = -value; - uintToString( UInt(value), current ); - if ( isNegative ) - *--current = '-'; - assert( current >= buffer ); - return current; + char buffer[32]; + char* current = buffer + sizeof(buffer); + bool isNegative = value < 0; + if (isNegative) + value = -value; + uintToString(UInt(value), current); + if (isNegative) + *--current = '-'; + assert(current >= buffer); + return current; } - -std::string valueToString( UInt value ) +std::string valueToString(UInt value) { - char buffer[32]; - char *current = buffer + sizeof(buffer); - uintToString( value, current ); - assert( current >= buffer ); - return current; + char buffer[32]; + char* current = buffer + sizeof(buffer); + uintToString(value, current); + assert(current >= buffer); + return current; } -std::string valueToString( double value ) +std::string valueToString(double value) { - char buffer[32]; + char buffer[32]; #if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning. - sprintf_s(buffer, sizeof(buffer), "%#.16g", value); + sprintf_s(buffer, sizeof(buffer), "%#.16g", value); #else - sprintf(buffer, "%#.16g", value); + sprintf(buffer, "%#.16g", value); #endif - char* ch = buffer + strlen(buffer) - 1; - if (*ch != '0') return buffer; // nothing to truncate, so save time - while(ch > buffer && *ch == '0'){ - --ch; - } - char* last_nonzero = ch; - while(ch >= buffer){ - switch(*ch){ - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - --ch; - continue; - case '.': - // Truncate zeroes to save bytes in output, but keep one. - *(last_nonzero+2) = '\0'; - return buffer; - default: - return buffer; - } - } - return buffer; -} - - -std::string valueToString( bool value ) -{ - return value ? "true" : "false"; -} - -std::string valueToQuotedString( const char *value ) -{ - // Not sure how to handle unicode... - if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter( value )) - return std::string("\"") + value + "\""; - // We have to walk value and escape any special characters. - // Appending to std::string is not efficient, but this should be rare. - // (Note: forward slashes are *not* rare, but I am not escaping them.) - unsigned maxsize = strlen(value)*2 + 3; // allescaped+quotes+NULL - std::string result; - result.reserve(maxsize); // to avoid lots of mallocs - result += "\""; - for (const char* c=value; *c != 0; ++c) - { - switch(*c) - { - case '\"': - result += "\\\""; - break; - case '\\': - result += "\\\\"; - break; - case '\b': - result += "\\b"; - break; - case '\f': - result += "\\f"; - break; - case '\n': - result += "\\n"; - break; - case '\r': - result += "\\r"; - break; - case '\t': - result += "\\t"; - break; - //case '/': + char* ch = buffer + strlen(buffer) - 1; + if (*ch != '0') + return buffer; // nothing to truncate, so save time + while (ch > buffer && *ch == '0') + { + --ch; + } + char* last_nonzero = ch; + while (ch >= buffer) + { + switch (*ch) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + --ch; + continue; + case '.': + // Truncate zeroes to save bytes in output, but keep one. + *(last_nonzero + 2) = '\0'; + return buffer; + default: + return buffer; + } + } + return buffer; +} + +std::string valueToString(bool value) +{ + return value ? "true" : "false"; +} + +std::string valueToQuotedString(const char* value) +{ + // Not sure how to handle unicode... + if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter(value)) + return std::string("\"") + value + "\""; + // We have to walk value and escape any special characters. + // Appending to std::string is not efficient, but this should be rare. + // (Note: forward slashes are *not* rare, but I am not escaping them.) + unsigned maxsize = strlen(value) * 2 + 3; // allescaped+quotes+NULL + std::string result; + result.reserve(maxsize); // to avoid lots of mallocs + result += "\""; + for (const char* c = value; *c != 0; ++c) + { + switch (*c) + { + case '\"': + result += "\\\""; + break; + case '\\': + result += "\\\\"; + break; + case '\b': + result += "\\b"; + break; + case '\f': + result += "\\f"; + break; + case '\n': + result += "\\n"; + break; + case '\r': + result += "\\r"; + break; + case '\t': + result += "\\t"; + break; + // case '/': // Even though \/ is considered a legal escape in JSON, a bare // slash is also legal, so I see no reason to escape it. // (I hope I am not misunderstanding something. @@ -159,683 +158,604 @@ std::string valueToQuotedString( const char *value ) // sequence. // Should add a flag to allow this compatibility mode and prevent this // sequence from occurring. - default: - if ( isControlCharacter( *c ) ) - { - std::ostringstream oss; - oss << "\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << static_cast(*c); - result += oss.str(); - } - else - { - result += *c; - } - break; - } - } - result += "\""; - return result; + default: + if (isControlCharacter(*c)) + { + std::ostringstream oss; + oss << "\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) + << static_cast(*c); + result += oss.str(); + } + else + { + result += *c; + } + break; + } + } + result += "\""; + return result; } // Class Writer // ////////////////////////////////////////////////////////////////// -Writer::~Writer() -{ -} - +Writer::~Writer() {} // Class FastWriter // ////////////////////////////////////////////////////////////////// -FastWriter::FastWriter() - : yamlCompatiblityEnabled_( false ) -{ -} - +FastWriter::FastWriter() : yamlCompatiblityEnabled_(false) {} -void -FastWriter::enableYAMLCompatibility() +void FastWriter::enableYAMLCompatibility() { - yamlCompatiblityEnabled_ = true; + yamlCompatiblityEnabled_ = true; } - -std::string -FastWriter::write( const Value &root, bool noNewLine ) +std::string FastWriter::write(const Value& root, bool noNewLine) { - document_ = ""; - writeValue( root ); - if(!noNewLine) { + document_ = ""; + writeValue(root); + if (!noNewLine) + { document_ += "\n"; - } - return document_; -} - - -void -FastWriter::writeValue( const Value &value ) -{ - switch ( value.type() ) - { - case nullValue: - document_ += "null"; - break; - case intValue: - document_ += valueToString( value.asInt() ); - break; - case uintValue: - document_ += valueToString( value.asUInt() ); - break; - case realValue: - document_ += valueToString( value.asDouble() ); - break; - case stringValue: - document_ += valueToQuotedString( value.asCString() ); - break; - case booleanValue: - document_ += valueToString( value.asBool() ); - break; - case arrayValue: - { - document_ += "["; - int size = value.size(); - for ( int index =0; index < size; ++index ) - { - if ( index > 0 ) - document_ += ","; - writeValue( value[index] ); - } - document_ += "]"; - } - break; - case objectValue: - { - Value::Members members( value.getMemberNames() ); - document_ += "{"; - for ( Value::Members::iterator it = members.begin(); - it != members.end(); - ++it ) - { - const std::string &name = *it; - if ( it != members.begin() ) - document_ += ","; - document_ += valueToQuotedString( name.c_str() ); - document_ += yamlCompatiblityEnabled_ ? ": " - : ":"; - writeValue( value[name] ); - } - document_ += "}"; - } - break; - } + } + return document_; } +void FastWriter::writeValue(const Value& value) +{ + switch (value.type()) + { + case nullValue: + document_ += "null"; + break; + case intValue: + document_ += valueToString(value.asInt()); + break; + case uintValue: + document_ += valueToString(value.asUInt()); + break; + case realValue: + document_ += valueToString(value.asDouble()); + break; + case stringValue: + document_ += valueToQuotedString(value.asCString()); + break; + case booleanValue: + document_ += valueToString(value.asBool()); + break; + case arrayValue: + { + document_ += "["; + int size = value.size(); + for (int index = 0; index < size; ++index) + { + if (index > 0) + document_ += ","; + writeValue(value[index]); + } + document_ += "]"; + } + break; + case objectValue: + { + Value::Members members(value.getMemberNames()); + document_ += "{"; + for (Value::Members::iterator it = members.begin(); it != members.end(); ++it) + { + const std::string& name = *it; + if (it != members.begin()) + document_ += ","; + document_ += valueToQuotedString(name.c_str()); + document_ += yamlCompatiblityEnabled_ ? ": " : ":"; + writeValue(value[name]); + } + document_ += "}"; + } + break; + } +} // Class StyledWriter // ////////////////////////////////////////////////////////////////// -StyledWriter::StyledWriter() - : rightMargin_( 74 ) - , indentSize_( 3 ) +StyledWriter::StyledWriter() : rightMargin_(74), indentSize_(3) {} + +std::string StyledWriter::write(const Value& root, bool noNewLine) { + document_ = ""; + addChildValues_ = false; + indentString_ = ""; + writeCommentBeforeValue(root); + writeValue(root); + writeCommentAfterValueOnSameLine(root); + if (!noNewLine) + { + document_ += "\n"; + } + return document_; } - -std::string -StyledWriter::write( const Value &root, bool noNewLine) +void StyledWriter::writeValue(const Value& value) { - document_ = ""; - addChildValues_ = false; - indentString_ = ""; - writeCommentBeforeValue( root ); - writeValue( root ); - writeCommentAfterValueOnSameLine( root ); - if(!noNewLine) { - document_ += "\n"; - } - return document_; -} - - -void -StyledWriter::writeValue( const Value &value ) -{ - switch ( value.type() ) - { - case nullValue: - pushValue( "null" ); - break; - case intValue: - pushValue( valueToString( value.asInt() ) ); - break; - case uintValue: - pushValue( valueToString( value.asUInt() ) ); - break; - case realValue: - pushValue( valueToString( value.asDouble() ) ); - break; - case stringValue: - pushValue( valueToQuotedString( value.asCString() ) ); - break; - case booleanValue: - pushValue( valueToString( value.asBool() ) ); - break; - case arrayValue: - writeArrayValue( value); - break; - case objectValue: - { - Value::Members members( value.getMemberNames() ); - if ( members.empty() ) - pushValue( "{}" ); - else - { - writeWithIndent( "{" ); - indent(); - Value::Members::iterator it = members.begin(); - while ( true ) + switch (value.type()) + { + case nullValue: + pushValue("null"); + break; + case intValue: + pushValue(valueToString(value.asInt())); + break; + case uintValue: + pushValue(valueToString(value.asUInt())); + break; + case realValue: + pushValue(valueToString(value.asDouble())); + break; + case stringValue: + pushValue(valueToQuotedString(value.asCString())); + break; + case booleanValue: + pushValue(valueToString(value.asBool())); + break; + case arrayValue: + writeArrayValue(value); + break; + case objectValue: + { + Value::Members members(value.getMemberNames()); + if (members.empty()) + pushValue("{}"); + else { - const std::string &name = *it; - const Value &childValue = value[name]; - writeCommentBeforeValue( childValue ); - writeWithIndent( valueToQuotedString( name.c_str() ) ); - document_ += " : "; - writeValue( childValue ); - if ( ++it == members.end() ) - { - writeCommentAfterValueOnSameLine( childValue ); - break; - } - document_ += ","; - writeCommentAfterValueOnSameLine( childValue ); + writeWithIndent("{"); + indent(); + Value::Members::iterator it = members.begin(); + while (true) + { + const std::string& name = *it; + const Value& childValue = value[name]; + writeCommentBeforeValue(childValue); + writeWithIndent(valueToQuotedString(name.c_str())); + document_ += " : "; + writeValue(childValue); + if (++it == members.end()) + { + writeCommentAfterValueOnSameLine(childValue); + break; + } + document_ += ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("}"); } - unindent(); - writeWithIndent( "}" ); - } - } - break; - } -} - - -void -StyledWriter::writeArrayValue( const Value &value ) -{ - unsigned size = value.size(); - if ( size == 0 ) - pushValue( "[]" ); - else - { - bool isArrayMultiLine = isMultineArray( value ); - if ( isArrayMultiLine ) - { - writeWithIndent( "[" ); - indent(); - bool hasChildValue = !childValues_.empty(); - unsigned index =0; - while ( true ) - { - const Value &childValue = value[index]; - writeCommentBeforeValue( childValue ); - if ( hasChildValue ) - writeWithIndent( childValues_[index] ); - else + } + break; + } +} + +void StyledWriter::writeArrayValue(const Value& value) +{ + unsigned size = value.size(); + if (size == 0) + pushValue("[]"); + else + { + bool isArrayMultiLine = isMultineArray(value); + if (isArrayMultiLine) + { + writeWithIndent("["); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index = 0; + while (true) { - writeIndent(); - writeValue( childValue ); + const Value& childValue = value[index]; + writeCommentBeforeValue(childValue); + if (hasChildValue) + writeWithIndent(childValues_[index]); + else + { + writeIndent(); + writeValue(childValue); + } + if (++index == size) + { + writeCommentAfterValueOnSameLine(childValue); + break; + } + document_ += ","; + writeCommentAfterValueOnSameLine(childValue); } - if ( ++index == size ) + unindent(); + writeWithIndent("]"); + } + else // output on a single line + { + assert(childValues_.size() == size); + document_ += "[ "; + for (unsigned index = 0; index < size; ++index) { - writeCommentAfterValueOnSameLine( childValue ); - break; + if (index > 0) + document_ += ", "; + document_ += childValues_[index]; } - document_ += ","; - writeCommentAfterValueOnSameLine( childValue ); - } - unindent(); - writeWithIndent( "]" ); - } - else // output on a single line - { - assert( childValues_.size() == size ); - document_ += "[ "; - for ( unsigned index =0; index < size; ++index ) - { - if ( index > 0 ) - document_ += ", "; - document_ += childValues_[index]; - } - document_ += " ]"; - } - } + document_ += " ]"; + } + } } - -bool -StyledWriter::isMultineArray( const Value &value ) +bool StyledWriter::isMultineArray(const Value& value) { - int size = value.size(); - bool isMultiLine = size*3 >= rightMargin_ ; - childValues_.clear(); - for ( int index =0; index < size && !isMultiLine; ++index ) - { - const Value &childValue = value[index]; - isMultiLine = isMultiLine || - ( (childValue.isArray() || childValue.isObject()) && - childValue.size() > 0 ); - } - if ( !isMultiLine ) // check if line length > max line length - { - childValues_.reserve( size ); - addChildValues_ = true; - int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]' - for ( int index =0; index < size && !isMultiLine; ++index ) - { - writeValue( value[index] ); - lineLength += int( childValues_[index].length() ); - isMultiLine = isMultiLine && hasCommentForValue( value[index] ); - } - addChildValues_ = false; - isMultiLine = isMultiLine || lineLength >= rightMargin_; - } - return isMultiLine; + int size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (int index = 0; index < size && !isMultiLine; ++index) + { + const Value& childValue = value[index]; + isMultiLine = isMultiLine || ((childValue.isArray() || childValue.isObject()) && childValue.size() > 0); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (int index = 0; index < size && !isMultiLine; ++index) + { + writeValue(value[index]); + lineLength += int(childValues_[index].length()); + isMultiLine = isMultiLine && hasCommentForValue(value[index]); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; } - -void -StyledWriter::pushValue( const std::string &value ) +void StyledWriter::pushValue(const std::string& value) { - if ( addChildValues_ ) - childValues_.push_back( value ); - else - document_ += value; + if (addChildValues_) + childValues_.push_back(value); + else + document_ += value; } - -void -StyledWriter::writeIndent() +void StyledWriter::writeIndent() { - if ( !document_.empty() ) - { - char last = document_[document_.length()-1]; - if ( last == ' ' ) // already indented - return; - if ( last != '\n' ) // Comments may add new-line - document_ += '\n'; - } - document_ += indentString_; + if (!document_.empty()) + { + char last = document_[document_.length() - 1]; + if (last == ' ') // already indented + return; + if (last != '\n') // Comments may add new-line + document_ += '\n'; + } + document_ += indentString_; } - -void -StyledWriter::writeWithIndent( const std::string &value ) +void StyledWriter::writeWithIndent(const std::string& value) { - writeIndent(); - document_ += value; + writeIndent(); + document_ += value; } - -void -StyledWriter::indent() +void StyledWriter::indent() { - indentString_ += std::string( indentSize_, ' ' ); + indentString_ += std::string(indentSize_, ' '); } - -void -StyledWriter::unindent() +void StyledWriter::unindent() { - assert( int(indentString_.size()) >= indentSize_ ); - indentString_.resize( indentString_.size() - indentSize_ ); + assert(int(indentString_.size()) >= indentSize_); + indentString_.resize(indentString_.size() - indentSize_); } - -void -StyledWriter::writeCommentBeforeValue( const Value &root ) +void StyledWriter::writeCommentBeforeValue(const Value& root) { - if ( !root.hasComment( commentBefore ) ) - return; - document_ += normalizeEOL( root.getComment( commentBefore ) ); - document_ += "\n"; + if (!root.hasComment(commentBefore)) + return; + document_ += normalizeEOL(root.getComment(commentBefore)); + document_ += "\n"; } - -void -StyledWriter::writeCommentAfterValueOnSameLine( const Value &root ) +void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) { - if ( root.hasComment( commentAfterOnSameLine ) ) - document_ += " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) ); + if (root.hasComment(commentAfterOnSameLine)) + document_ += " " + normalizeEOL(root.getComment(commentAfterOnSameLine)); - if ( root.hasComment( commentAfter ) ) - { - document_ += "\n"; - document_ += normalizeEOL( root.getComment( commentAfter ) ); - document_ += "\n"; - } + if (root.hasComment(commentAfter)) + { + document_ += "\n"; + document_ += normalizeEOL(root.getComment(commentAfter)); + document_ += "\n"; + } } - -bool -StyledWriter::hasCommentForValue( const Value &value ) +bool StyledWriter::hasCommentForValue(const Value& value) { - return value.hasComment( commentBefore ) - || value.hasComment( commentAfterOnSameLine ) - || value.hasComment( commentAfter ); + return value.hasComment(commentBefore) || value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); } - -std::string -StyledWriter::normalizeEOL( const std::string &text ) +std::string StyledWriter::normalizeEOL(const std::string& text) { - std::string normalized; - normalized.reserve( text.length() ); - const char *begin = text.c_str(); - const char *end = begin + text.length(); - const char *current = begin; - while ( current != end ) - { - char c = *current++; - if ( c == '\r' ) // mac or dos EOL - { - if ( *current == '\n' ) // convert dos EOL - ++current; - normalized += '\n'; - } - else // handle unix EOL & other char - normalized += c; - } - return normalized; + std::string normalized; + normalized.reserve(text.length()); + const char* begin = text.c_str(); + const char* end = begin + text.length(); + const char* current = begin; + while (current != end) + { + char c = *current++; + if (c == '\r') // mac or dos EOL + { + if (*current == '\n') // convert dos EOL + ++current; + normalized += '\n'; + } + else // handle unix EOL & other char + normalized += c; + } + return normalized; } - // Class StyledStreamWriter // ////////////////////////////////////////////////////////////////// -StyledStreamWriter::StyledStreamWriter( std::string indentation ) - : document_(NULL) - , rightMargin_( 74 ) - , indentation_( indentation ) -{ -} - - -void -StyledStreamWriter::write( std::ostream &out, const Value &root, bool noNewLine) -{ - document_ = &out; - addChildValues_ = false; - indentString_ = ""; - writeCommentBeforeValue( root ); - writeValue( root ); - writeCommentAfterValueOnSameLine( root ); - if(!noNewLine) { - *document_ << "\n"; - } - document_ = NULL; // Forget the stream, for safety. -} - - -void -StyledStreamWriter::writeValue( const Value &value ) -{ - switch ( value.type() ) - { - case nullValue: - pushValue( "null" ); - break; - case intValue: - pushValue( valueToString( value.asInt() ) ); - break; - case uintValue: - pushValue( valueToString( value.asUInt() ) ); - break; - case realValue: - pushValue( valueToString( value.asDouble() ) ); - break; - case stringValue: - pushValue( valueToQuotedString( value.asCString() ) ); - break; - case booleanValue: - pushValue( valueToString( value.asBool() ) ); - break; - case arrayValue: - writeArrayValue( value); - break; - case objectValue: - { - Value::Members members( value.getMemberNames() ); - if ( members.empty() ) - pushValue( "{}" ); - else - { - writeWithIndent( "{" ); - indent(); - Value::Members::iterator it = members.begin(); - while ( true ) - { - const std::string &name = *it; - const Value &childValue = value[name]; - writeCommentBeforeValue( childValue ); - writeWithIndent( valueToQuotedString( name.c_str() ) ); - *document_ << " : "; - writeValue( childValue ); - if ( ++it == members.end() ) - { - writeCommentAfterValueOnSameLine( childValue ); - break; - } - *document_ << ","; - writeCommentAfterValueOnSameLine( childValue ); - } - unindent(); - writeWithIndent( "}" ); - } - } - break; - } -} - - -void -StyledStreamWriter::writeArrayValue( const Value &value ) -{ - unsigned size = value.size(); - if ( size == 0 ) - pushValue( "[]" ); - else - { - bool isArrayMultiLine = isMultineArray( value ); - if ( isArrayMultiLine ) - { - writeWithIndent( "[" ); - indent(); - bool hasChildValue = !childValues_.empty(); - unsigned index =0; - while ( true ) - { - const Value &childValue = value[index]; - writeCommentBeforeValue( childValue ); - if ( hasChildValue ) - writeWithIndent( childValues_[index] ); - else - { - writeIndent(); - writeValue( childValue ); - } - if ( ++index == size ) - { - writeCommentAfterValueOnSameLine( childValue ); - break; - } - *document_ << ","; - writeCommentAfterValueOnSameLine( childValue ); - } - unindent(); - writeWithIndent( "]" ); - } - else // output on a single line - { - assert( childValues_.size() == size ); - *document_ << "[ "; - for ( unsigned index =0; index < size; ++index ) - { - if ( index > 0 ) - *document_ << ", "; - *document_ << childValues_[index]; - } - *document_ << " ]"; - } - } -} - - -bool -StyledStreamWriter::isMultineArray( const Value &value ) +StyledStreamWriter::StyledStreamWriter(std::string indentation) : + document_(NULL), rightMargin_(74), indentation_(indentation) { - int size = value.size(); - bool isMultiLine = size*3 >= rightMargin_ ; - childValues_.clear(); - for ( int index =0; index < size && !isMultiLine; ++index ) - { - const Value &childValue = value[index]; - isMultiLine = isMultiLine || - ( (childValue.isArray() || childValue.isObject()) && - childValue.size() > 0 ); - } - if ( !isMultiLine ) // check if line length > max line length - { - childValues_.reserve( size ); - addChildValues_ = true; - int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]' - for ( int index =0; index < size && !isMultiLine; ++index ) - { - writeValue( value[index] ); - lineLength += int( childValues_[index].length() ); - isMultiLine = isMultiLine && hasCommentForValue( value[index] ); - } - addChildValues_ = false; - isMultiLine = isMultiLine || lineLength >= rightMargin_; - } - return isMultiLine; } - -void -StyledStreamWriter::pushValue( const std::string &value ) +void StyledStreamWriter::write(std::ostream& out, const Value& root, bool noNewLine) { - if ( addChildValues_ ) - childValues_.push_back( value ); - else - *document_ << value; + document_ = &out; + addChildValues_ = false; + indentString_ = ""; + writeCommentBeforeValue(root); + writeValue(root); + writeCommentAfterValueOnSameLine(root); + if (!noNewLine) + { + *document_ << "\n"; + } + document_ = NULL; // Forget the stream, for safety. } - -void -StyledStreamWriter::writeIndent() +void StyledStreamWriter::writeValue(const Value& value) { - /* - Some comments in this method would have been nice. ;-) - - if ( !document_.empty() ) - { - char last = document_[document_.length()-1]; - if ( last == ' ' ) // already indented - return; - if ( last != '\n' ) // Comments may add new-line - *document_ << '\n'; - } - */ - *document_ << '\n' << indentString_; + switch (value.type()) + { + case nullValue: + pushValue("null"); + break; + case intValue: + pushValue(valueToString(value.asInt())); + break; + case uintValue: + pushValue(valueToString(value.asUInt())); + break; + case realValue: + pushValue(valueToString(value.asDouble())); + break; + case stringValue: + pushValue(valueToQuotedString(value.asCString())); + break; + case booleanValue: + pushValue(valueToString(value.asBool())); + break; + case arrayValue: + writeArrayValue(value); + break; + case objectValue: + { + Value::Members members(value.getMemberNames()); + if (members.empty()) + pushValue("{}"); + else + { + writeWithIndent("{"); + indent(); + Value::Members::iterator it = members.begin(); + while (true) + { + const std::string& name = *it; + const Value& childValue = value[name]; + writeCommentBeforeValue(childValue); + writeWithIndent(valueToQuotedString(name.c_str())); + *document_ << " : "; + writeValue(childValue); + if (++it == members.end()) + { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *document_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("}"); + } + } + break; + } +} + +void StyledStreamWriter::writeArrayValue(const Value& value) +{ + unsigned size = value.size(); + if (size == 0) + pushValue("[]"); + else + { + bool isArrayMultiLine = isMultineArray(value); + if (isArrayMultiLine) + { + writeWithIndent("["); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index = 0; + while (true) + { + const Value& childValue = value[index]; + writeCommentBeforeValue(childValue); + if (hasChildValue) + writeWithIndent(childValues_[index]); + else + { + writeIndent(); + writeValue(childValue); + } + if (++index == size) + { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *document_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("]"); + } + else // output on a single line + { + assert(childValues_.size() == size); + *document_ << "[ "; + for (unsigned index = 0; index < size; ++index) + { + if (index > 0) + *document_ << ", "; + *document_ << childValues_[index]; + } + *document_ << " ]"; + } + } +} + +bool StyledStreamWriter::isMultineArray(const Value& value) +{ + int size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (int index = 0; index < size && !isMultiLine; ++index) + { + const Value& childValue = value[index]; + isMultiLine = isMultiLine || ((childValue.isArray() || childValue.isObject()) && childValue.size() > 0); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (int index = 0; index < size && !isMultiLine; ++index) + { + writeValue(value[index]); + lineLength += int(childValues_[index].length()); + isMultiLine = isMultiLine && hasCommentForValue(value[index]); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void StyledStreamWriter::pushValue(const std::string& value) +{ + if (addChildValues_) + childValues_.push_back(value); + else + *document_ << value; +} + +void StyledStreamWriter::writeIndent() +{ + /* + Some comments in this method would have been nice. ;-) + + if ( !document_.empty() ) + { + char last = document_[document_.length()-1]; + if ( last == ' ' ) // already indented + return; + if ( last != '\n' ) // Comments may add new-line + *document_ << '\n'; + } + */ + *document_ << '\n' << indentString_; } - -void -StyledStreamWriter::writeWithIndent( const std::string &value ) +void StyledStreamWriter::writeWithIndent(const std::string& value) { - writeIndent(); - *document_ << value; + writeIndent(); + *document_ << value; } - -void -StyledStreamWriter::indent() +void StyledStreamWriter::indent() { - indentString_ += indentation_; + indentString_ += indentation_; } - -void -StyledStreamWriter::unindent() +void StyledStreamWriter::unindent() { - assert( indentString_.size() >= indentation_.size() ); - indentString_.resize( indentString_.size() - indentation_.size() ); + assert(indentString_.size() >= indentation_.size()); + indentString_.resize(indentString_.size() - indentation_.size()); } - -void -StyledStreamWriter::writeCommentBeforeValue( const Value &root ) +void StyledStreamWriter::writeCommentBeforeValue(const Value& root) { - if ( !root.hasComment( commentBefore ) ) - return; - *document_ << normalizeEOL( root.getComment( commentBefore ) ); - *document_ << "\n"; + if (!root.hasComment(commentBefore)) + return; + *document_ << normalizeEOL(root.getComment(commentBefore)); + *document_ << "\n"; } - -void -StyledStreamWriter::writeCommentAfterValueOnSameLine( const Value &root ) +void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) { - if ( root.hasComment( commentAfterOnSameLine ) ) - *document_ << " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) ); + if (root.hasComment(commentAfterOnSameLine)) + *document_ << " " + normalizeEOL(root.getComment(commentAfterOnSameLine)); - if ( root.hasComment( commentAfter ) ) - { - *document_ << "\n"; - *document_ << normalizeEOL( root.getComment( commentAfter ) ); - *document_ << "\n"; - } + if (root.hasComment(commentAfter)) + { + *document_ << "\n"; + *document_ << normalizeEOL(root.getComment(commentAfter)); + *document_ << "\n"; + } } - -bool -StyledStreamWriter::hasCommentForValue( const Value &value ) +bool StyledStreamWriter::hasCommentForValue(const Value& value) { - return value.hasComment( commentBefore ) - || value.hasComment( commentAfterOnSameLine ) - || value.hasComment( commentAfter ); + return value.hasComment(commentBefore) || value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); } - -std::string -StyledStreamWriter::normalizeEOL( const std::string &text ) +std::string StyledStreamWriter::normalizeEOL(const std::string& text) { - std::string normalized; - normalized.reserve( text.length() ); - const char *begin = text.c_str(); - const char *end = begin + text.length(); - const char *current = begin; - while ( current != end ) - { - char c = *current++; - if ( c == '\r' ) // mac or dos EOL - { - if ( *current == '\n' ) // convert dos EOL - ++current; - normalized += '\n'; - } - else // handle unix EOL & other char - normalized += c; - } - return normalized; + std::string normalized; + normalized.reserve(text.length()); + const char* begin = text.c_str(); + const char* end = begin + text.length(); + const char* current = begin; + while (current != end) + { + char c = *current++; + if (c == '\r') // mac or dos EOL + { + if (*current == '\n') // convert dos EOL + ++current; + normalized += '\n'; + } + else // handle unix EOL & other char + normalized += c; + } + return normalized; } - -std::ostream& operator<<( std::ostream &sout, const Value &root ) +std::ostream& operator<<(std::ostream& sout, const Value& root) { - Json::StyledStreamWriter writer; - writer.write(sout, root); - return sout; + Json::StyledStreamWriter writer; + writer.write(sout, root); + return sout; } - } // namespace Json diff --git a/ext_libs/minixz/xz.h b/ext_libs/minixz/xz.h index 578a1c7f..413ed569 100644 --- a/ext_libs/minixz/xz.h +++ b/ext_libs/minixz/xz.h @@ -42,230 +42,234 @@ #define XZ_H #ifdef __KERNEL__ -# include -# include +#include +#include #else -# include -# include +#include +#include #endif #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif /* In Linux, this is used to make extern functions static when needed. */ #ifndef XZ_EXTERN -# define XZ_EXTERN extern +#define XZ_EXTERN extern #endif -/** - * enum xz_mode - Operation mode - * - * @XZ_SINGLE: Single-call mode. This uses less RAM than - * than multi-call modes, because the LZMA2 - * dictionary doesn't need to be allocated as - * part of the decoder state. All required data - * structures are allocated at initialization, - * so xz_dec_run() cannot return XZ_MEM_ERROR. - * @XZ_PREALLOC: Multi-call mode with preallocated LZMA2 - * dictionary buffer. All data structures are - * allocated at initialization, so xz_dec_run() - * cannot return XZ_MEM_ERROR. - * @XZ_DYNALLOC: Multi-call mode. The LZMA2 dictionary is - * allocated once the required size has been - * parsed from the stream headers. If the - * allocation fails, xz_dec_run() will return - * XZ_MEM_ERROR. - * - * It is possible to enable support only for a subset of the above - * modes at compile time by defining XZ_DEC_SINGLE, XZ_DEC_PREALLOC, - * or XZ_DEC_DYNALLOC. The xz_dec kernel module is always compiled - * with support for all operation modes, but the preboot code may - * be built with fewer features to minimize code size. - */ -enum xz_mode { - XZ_SINGLE, - XZ_PREALLOC, - XZ_DYNALLOC -}; + /** + * enum xz_mode - Operation mode + * + * @XZ_SINGLE: Single-call mode. This uses less RAM than + * than multi-call modes, because the LZMA2 + * dictionary doesn't need to be allocated as + * part of the decoder state. All required data + * structures are allocated at initialization, + * so xz_dec_run() cannot return XZ_MEM_ERROR. + * @XZ_PREALLOC: Multi-call mode with preallocated LZMA2 + * dictionary buffer. All data structures are + * allocated at initialization, so xz_dec_run() + * cannot return XZ_MEM_ERROR. + * @XZ_DYNALLOC: Multi-call mode. The LZMA2 dictionary is + * allocated once the required size has been + * parsed from the stream headers. If the + * allocation fails, xz_dec_run() will return + * XZ_MEM_ERROR. + * + * It is possible to enable support only for a subset of the above + * modes at compile time by defining XZ_DEC_SINGLE, XZ_DEC_PREALLOC, + * or XZ_DEC_DYNALLOC. The xz_dec kernel module is always compiled + * with support for all operation modes, but the preboot code may + * be built with fewer features to minimize code size. + */ + enum xz_mode + { + XZ_SINGLE, + XZ_PREALLOC, + XZ_DYNALLOC + }; -/** - * enum xz_ret - Return codes - * @XZ_OK: Everything is OK so far. More input or more - * output space is required to continue. This - * return code is possible only in multi-call mode - * (XZ_PREALLOC or XZ_DYNALLOC). - * @XZ_STREAM_END: Operation finished successfully. - * @XZ_UNSUPPORTED_CHECK: Integrity check type is not supported. Decoding - * is still possible in multi-call mode by simply - * calling xz_dec_run() again. - * Note that this return value is used only if - * XZ_DEC_ANY_CHECK was defined at build time, - * which is not used in the kernel. Unsupported - * check types return XZ_OPTIONS_ERROR if - * XZ_DEC_ANY_CHECK was not defined at build time. - * @XZ_MEM_ERROR: Allocating memory failed. This return code is - * possible only if the decoder was initialized - * with XZ_DYNALLOC. The amount of memory that was - * tried to be allocated was no more than the - * dict_max argument given to xz_dec_init(). - * @XZ_MEMLIMIT_ERROR: A bigger LZMA2 dictionary would be needed than - * allowed by the dict_max argument given to - * xz_dec_init(). This return value is possible - * only in multi-call mode (XZ_PREALLOC or - * XZ_DYNALLOC); the single-call mode (XZ_SINGLE) - * ignores the dict_max argument. - * @XZ_FORMAT_ERROR: File format was not recognized (wrong magic - * bytes). - * @XZ_OPTIONS_ERROR: This implementation doesn't support the requested - * compression options. In the decoder this means - * that the header CRC32 matches, but the header - * itself specifies something that we don't support. - * @XZ_DATA_ERROR: Compressed data is corrupt. - * @XZ_BUF_ERROR: Cannot make any progress. Details are slightly - * different between multi-call and single-call - * mode; more information below. - * - * In multi-call mode, XZ_BUF_ERROR is returned when two consecutive calls - * to XZ code cannot consume any input and cannot produce any new output. - * This happens when there is no new input available, or the output buffer - * is full while at least one output byte is still pending. Assuming your - * code is not buggy, you can get this error only when decoding a compressed - * stream that is truncated or otherwise corrupt. - * - * In single-call mode, XZ_BUF_ERROR is returned only when the output buffer - * is too small or the compressed input is corrupt in a way that makes the - * decoder produce more output than the caller expected. When it is - * (relatively) clear that the compressed input is truncated, XZ_DATA_ERROR - * is used instead of XZ_BUF_ERROR. - */ -enum xz_ret { - XZ_OK, - XZ_STREAM_END, - XZ_UNSUPPORTED_CHECK, - XZ_MEM_ERROR, - XZ_MEMLIMIT_ERROR, - XZ_FORMAT_ERROR, - XZ_OPTIONS_ERROR, - XZ_DATA_ERROR, - XZ_BUF_ERROR -}; + /** + * enum xz_ret - Return codes + * @XZ_OK: Everything is OK so far. More input or more + * output space is required to continue. This + * return code is possible only in multi-call mode + * (XZ_PREALLOC or XZ_DYNALLOC). + * @XZ_STREAM_END: Operation finished successfully. + * @XZ_UNSUPPORTED_CHECK: Integrity check type is not supported. Decoding + * is still possible in multi-call mode by simply + * calling xz_dec_run() again. + * Note that this return value is used only if + * XZ_DEC_ANY_CHECK was defined at build time, + * which is not used in the kernel. Unsupported + * check types return XZ_OPTIONS_ERROR if + * XZ_DEC_ANY_CHECK was not defined at build time. + * @XZ_MEM_ERROR: Allocating memory failed. This return code is + * possible only if the decoder was initialized + * with XZ_DYNALLOC. The amount of memory that was + * tried to be allocated was no more than the + * dict_max argument given to xz_dec_init(). + * @XZ_MEMLIMIT_ERROR: A bigger LZMA2 dictionary would be needed than + * allowed by the dict_max argument given to + * xz_dec_init(). This return value is possible + * only in multi-call mode (XZ_PREALLOC or + * XZ_DYNALLOC); the single-call mode (XZ_SINGLE) + * ignores the dict_max argument. + * @XZ_FORMAT_ERROR: File format was not recognized (wrong magic + * bytes). + * @XZ_OPTIONS_ERROR: This implementation doesn't support the requested + * compression options. In the decoder this means + * that the header CRC32 matches, but the header + * itself specifies something that we don't support. + * @XZ_DATA_ERROR: Compressed data is corrupt. + * @XZ_BUF_ERROR: Cannot make any progress. Details are slightly + * different between multi-call and single-call + * mode; more information below. + * + * In multi-call mode, XZ_BUF_ERROR is returned when two consecutive calls + * to XZ code cannot consume any input and cannot produce any new output. + * This happens when there is no new input available, or the output buffer + * is full while at least one output byte is still pending. Assuming your + * code is not buggy, you can get this error only when decoding a compressed + * stream that is truncated or otherwise corrupt. + * + * In single-call mode, XZ_BUF_ERROR is returned only when the output buffer + * is too small or the compressed input is corrupt in a way that makes the + * decoder produce more output than the caller expected. When it is + * (relatively) clear that the compressed input is truncated, XZ_DATA_ERROR + * is used instead of XZ_BUF_ERROR. + */ + enum xz_ret + { + XZ_OK, + XZ_STREAM_END, + XZ_UNSUPPORTED_CHECK, + XZ_MEM_ERROR, + XZ_MEMLIMIT_ERROR, + XZ_FORMAT_ERROR, + XZ_OPTIONS_ERROR, + XZ_DATA_ERROR, + XZ_BUF_ERROR + }; -/** - * struct xz_buf - Passing input and output buffers to XZ code - * @in: Beginning of the input buffer. This may be NULL if and only - * if in_pos is equal to in_size. - * @in_pos: Current position in the input buffer. This must not exceed - * in_size. - * @in_size: Size of the input buffer - * @out: Beginning of the output buffer. This may be NULL if and only - * if out_pos is equal to out_size. - * @out_pos: Current position in the output buffer. This must not exceed - * out_size. - * @out_size: Size of the output buffer - * - * Only the contents of the output buffer from out[out_pos] onward, and - * the variables in_pos and out_pos are modified by the XZ code. - */ -struct xz_buf { - const uint8_t *in; - size_t in_pos; - size_t in_size; + /** + * struct xz_buf - Passing input and output buffers to XZ code + * @in: Beginning of the input buffer. This may be NULL if and only + * if in_pos is equal to in_size. + * @in_pos: Current position in the input buffer. This must not exceed + * in_size. + * @in_size: Size of the input buffer + * @out: Beginning of the output buffer. This may be NULL if and only + * if out_pos is equal to out_size. + * @out_pos: Current position in the output buffer. This must not exceed + * out_size. + * @out_size: Size of the output buffer + * + * Only the contents of the output buffer from out[out_pos] onward, and + * the variables in_pos and out_pos are modified by the XZ code. + */ + struct xz_buf + { + const uint8_t* in; + size_t in_pos; + size_t in_size; - uint8_t *out; - size_t out_pos; - size_t out_size; -}; + uint8_t* out; + size_t out_pos; + size_t out_size; + }; -/** - * struct xz_dec - Opaque type to hold the XZ decoder state - */ -struct xz_dec; + /** + * struct xz_dec - Opaque type to hold the XZ decoder state + */ + struct xz_dec; -/** - * xz_dec_init() - Allocate and initialize a XZ decoder state - * @mode: Operation mode - * @dict_max: Maximum size of the LZMA2 dictionary (history buffer) for - * multi-call decoding. This is ignored in single-call mode - * (mode == XZ_SINGLE). LZMA2 dictionary is always 2^n bytes - * or 2^n + 2^(n-1) bytes (the latter sizes are less common - * in practice), so other values for dict_max don't make sense. - * In the kernel, dictionary sizes of 64 KiB, 128 KiB, 256 KiB, - * 512 KiB, and 1 MiB are probably the only reasonable values, - * except for kernel and initramfs images where a bigger - * dictionary can be fine and useful. - * - * Single-call mode (XZ_SINGLE): xz_dec_run() decodes the whole stream at - * once. The caller must provide enough output space or the decoding will - * fail. The output space is used as the dictionary buffer, which is why - * there is no need to allocate the dictionary as part of the decoder's - * internal state. - * - * Because the output buffer is used as the workspace, streams encoded using - * a big dictionary are not a problem in single-call mode. It is enough that - * the output buffer is big enough to hold the actual uncompressed data; it - * can be smaller than the dictionary size stored in the stream headers. - * - * Multi-call mode with preallocated dictionary (XZ_PREALLOC): dict_max bytes - * of memory is preallocated for the LZMA2 dictionary. This way there is no - * risk that xz_dec_run() could run out of memory, since xz_dec_run() will - * never allocate any memory. Instead, if the preallocated dictionary is too - * small for decoding the given input stream, xz_dec_run() will return - * XZ_MEMLIMIT_ERROR. Thus, it is important to know what kind of data will be - * decoded to avoid allocating excessive amount of memory for the dictionary. - * - * Multi-call mode with dynamically allocated dictionary (XZ_DYNALLOC): - * dict_max specifies the maximum allowed dictionary size that xz_dec_run() - * may allocate once it has parsed the dictionary size from the stream - * headers. This way excessive allocations can be avoided while still - * limiting the maximum memory usage to a sane value to prevent running the - * system out of memory when decompressing streams from untrusted sources. - * - * On success, xz_dec_init() returns a pointer to struct xz_dec, which is - * ready to be used with xz_dec_run(). If memory allocation fails, - * xz_dec_init() returns NULL. - */ -XZ_EXTERN struct xz_dec *xz_dec_init(enum xz_mode mode, uint32_t dict_max); + /** + * xz_dec_init() - Allocate and initialize a XZ decoder state + * @mode: Operation mode + * @dict_max: Maximum size of the LZMA2 dictionary (history buffer) for + * multi-call decoding. This is ignored in single-call mode + * (mode == XZ_SINGLE). LZMA2 dictionary is always 2^n bytes + * or 2^n + 2^(n-1) bytes (the latter sizes are less common + * in practice), so other values for dict_max don't make sense. + * In the kernel, dictionary sizes of 64 KiB, 128 KiB, 256 KiB, + * 512 KiB, and 1 MiB are probably the only reasonable values, + * except for kernel and initramfs images where a bigger + * dictionary can be fine and useful. + * + * Single-call mode (XZ_SINGLE): xz_dec_run() decodes the whole stream at + * once. The caller must provide enough output space or the decoding will + * fail. The output space is used as the dictionary buffer, which is why + * there is no need to allocate the dictionary as part of the decoder's + * internal state. + * + * Because the output buffer is used as the workspace, streams encoded using + * a big dictionary are not a problem in single-call mode. It is enough that + * the output buffer is big enough to hold the actual uncompressed data; it + * can be smaller than the dictionary size stored in the stream headers. + * + * Multi-call mode with preallocated dictionary (XZ_PREALLOC): dict_max bytes + * of memory is preallocated for the LZMA2 dictionary. This way there is no + * risk that xz_dec_run() could run out of memory, since xz_dec_run() will + * never allocate any memory. Instead, if the preallocated dictionary is too + * small for decoding the given input stream, xz_dec_run() will return + * XZ_MEMLIMIT_ERROR. Thus, it is important to know what kind of data will be + * decoded to avoid allocating excessive amount of memory for the dictionary. + * + * Multi-call mode with dynamically allocated dictionary (XZ_DYNALLOC): + * dict_max specifies the maximum allowed dictionary size that xz_dec_run() + * may allocate once it has parsed the dictionary size from the stream + * headers. This way excessive allocations can be avoided while still + * limiting the maximum memory usage to a sane value to prevent running the + * system out of memory when decompressing streams from untrusted sources. + * + * On success, xz_dec_init() returns a pointer to struct xz_dec, which is + * ready to be used with xz_dec_run(). If memory allocation fails, + * xz_dec_init() returns NULL. + */ + XZ_EXTERN struct xz_dec* xz_dec_init(enum xz_mode mode, uint32_t dict_max); -/** - * xz_dec_run() - Run the XZ decoder - * @s: Decoder state allocated using xz_dec_init() - * @b: Input and output buffers - * - * The possible return values depend on build options and operation mode. - * See enum xz_ret for details. - * - * Note that if an error occurs in single-call mode (return value is not - * XZ_STREAM_END), b->in_pos and b->out_pos are not modified and the - * contents of the output buffer from b->out[b->out_pos] onward are - * undefined. This is true even after XZ_BUF_ERROR, because with some filter - * chains, there may be a second pass over the output buffer, and this pass - * cannot be properly done if the output buffer is truncated. Thus, you - * cannot give the single-call decoder a too small buffer and then expect to - * get that amount valid data from the beginning of the stream. You must use - * the multi-call decoder if you don't want to uncompress the whole stream. - */ -XZ_EXTERN enum xz_ret xz_dec_run(struct xz_dec *s, struct xz_buf *b); + /** + * xz_dec_run() - Run the XZ decoder + * @s: Decoder state allocated using xz_dec_init() + * @b: Input and output buffers + * + * The possible return values depend on build options and operation mode. + * See enum xz_ret for details. + * + * Note that if an error occurs in single-call mode (return value is not + * XZ_STREAM_END), b->in_pos and b->out_pos are not modified and the + * contents of the output buffer from b->out[b->out_pos] onward are + * undefined. This is true even after XZ_BUF_ERROR, because with some filter + * chains, there may be a second pass over the output buffer, and this pass + * cannot be properly done if the output buffer is truncated. Thus, you + * cannot give the single-call decoder a too small buffer and then expect to + * get that amount valid data from the beginning of the stream. You must use + * the multi-call decoder if you don't want to uncompress the whole stream. + */ + XZ_EXTERN enum xz_ret xz_dec_run(struct xz_dec* s, struct xz_buf* b); -/** - * xz_dec_reset() - Reset an already allocated decoder state - * @s: Decoder state allocated using xz_dec_init() - * - * This function can be used to reset the multi-call decoder state without - * freeing and reallocating memory with xz_dec_end() and xz_dec_init(). - * - * In single-call mode, xz_dec_reset() is always called in the beginning of - * xz_dec_run(). Thus, explicit call to xz_dec_reset() is useful only in - * multi-call mode. - */ -XZ_EXTERN void xz_dec_reset(struct xz_dec *s); + /** + * xz_dec_reset() - Reset an already allocated decoder state + * @s: Decoder state allocated using xz_dec_init() + * + * This function can be used to reset the multi-call decoder state without + * freeing and reallocating memory with xz_dec_end() and xz_dec_init(). + * + * In single-call mode, xz_dec_reset() is always called in the beginning of + * xz_dec_run(). Thus, explicit call to xz_dec_reset() is useful only in + * multi-call mode. + */ + XZ_EXTERN void xz_dec_reset(struct xz_dec* s); -/** - * xz_dec_end() - Free the memory allocated for the decoder state - * @s: Decoder state allocated using xz_dec_init(). If s is NULL, - * this function does nothing. - */ -XZ_EXTERN void xz_dec_end(struct xz_dec *s); + /** + * xz_dec_end() - Free the memory allocated for the decoder state + * @s: Decoder state allocated using xz_dec_init(). If s is NULL, + * this function does nothing. + */ + XZ_EXTERN void xz_dec_end(struct xz_dec* s); /* * Standalone build (userspace build or in-kernel build for boot time use) @@ -274,26 +278,26 @@ XZ_EXTERN void xz_dec_end(struct xz_dec *s); * care about the functions below. */ #ifndef XZ_INTERNAL_CRC32 -# ifdef __KERNEL__ -# define XZ_INTERNAL_CRC32 0 -# else -# define XZ_INTERNAL_CRC32 1 -# endif +#ifdef __KERNEL__ +#define XZ_INTERNAL_CRC32 0 +#else +#define XZ_INTERNAL_CRC32 1 +#endif #endif #if XZ_INTERNAL_CRC32 -/* - * This must be called before any other xz_* function to initialize - * the CRC32 lookup table. - */ -XZ_EXTERN void xz_crc32_init(void); + /* + * This must be called before any other xz_* function to initialize + * the CRC32 lookup table. + */ + XZ_EXTERN void xz_crc32_init(void); -/* - * Update CRC32 value using the polynomial from IEEE-802.3. To start a new - * calculation, the third argument must be zero. To continue the calculation, - * the previously returned value is passed as the third argument. - */ -XZ_EXTERN uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc); + /* + * Update CRC32 value using the polynomial from IEEE-802.3. To start a new + * calculation, the third argument must be zero. To continue the calculation, + * the previously returned value is passed as the third argument. + */ + XZ_EXTERN uint32_t xz_crc32(const uint8_t* buf, size_t size, uint32_t crc); #endif #ifdef __cplusplus diff --git a/ext_libs/minixz/xz_config.h b/ext_libs/minixz/xz_config.h index 87af0a2f..aa96a752 100644 --- a/ext_libs/minixz/xz_config.h +++ b/ext_libs/minixz/xz_config.h @@ -65,7 +65,7 @@ #define memzero(buf, size) memset(buf, 0, size) #ifndef min -# define min(x, y) ((x) < (y) ? (x) : (y)) +#define min(x, y) ((x) < (y) ? (x) : (y)) #endif #define min_t(type, x, y) min(x, y) @@ -80,52 +80,45 @@ * so if you want to change it, you need to #undef it first. */ #ifndef __always_inline -# ifdef __GNUC__ -# define __always_inline \ - inline __attribute__((__always_inline__)) -# else -# define __always_inline inline -# endif +#ifdef __GNUC__ +#define __always_inline inline __attribute__((__always_inline__)) +#else +#define __always_inline inline +#endif #endif /* Inline functions to access unaligned unsigned 32-bit integers */ #ifndef get_unaligned_le32 -static inline uint32_t get_unaligned_le32(const uint8_t *buf) +static inline uint32_t get_unaligned_le32(const uint8_t* buf) { - return (uint32_t)buf[0] - | ((uint32_t)buf[1] << 8) - | ((uint32_t)buf[2] << 16) - | ((uint32_t)buf[3] << 24); + return (uint32_t)buf[0] | ((uint32_t)buf[1] << 8) | ((uint32_t)buf[2] << 16) | ((uint32_t)buf[3] << 24); } #endif #ifndef get_unaligned_be32 -static inline uint32_t get_unaligned_be32(const uint8_t *buf) +static inline uint32_t get_unaligned_be32(const uint8_t* buf) { - return (uint32_t)(buf[0] << 24) - | ((uint32_t)buf[1] << 16) - | ((uint32_t)buf[2] << 8) - | (uint32_t)buf[3]; + return (uint32_t)(buf[0] << 24) | ((uint32_t)buf[1] << 16) | ((uint32_t)buf[2] << 8) | (uint32_t)buf[3]; } #endif #ifndef put_unaligned_le32 -static inline void put_unaligned_le32(uint32_t val, uint8_t *buf) +static inline void put_unaligned_le32(uint32_t val, uint8_t* buf) { - buf[0] = (uint8_t)val; - buf[1] = (uint8_t)(val >> 8); - buf[2] = (uint8_t)(val >> 16); - buf[3] = (uint8_t)(val >> 24); + buf[0] = (uint8_t)val; + buf[1] = (uint8_t)(val >> 8); + buf[2] = (uint8_t)(val >> 16); + buf[3] = (uint8_t)(val >> 24); } #endif #ifndef put_unaligned_be32 -static inline void put_unaligned_be32(uint32_t val, uint8_t *buf) +static inline void put_unaligned_be32(uint32_t val, uint8_t* buf) { - buf[0] = (uint8_t)(val >> 24); - buf[1] = (uint8_t)(val >> 16); - buf[2] = (uint8_t)(val >> 8); - buf[3] = (uint8_t)val; + buf[0] = (uint8_t)(val >> 24); + buf[1] = (uint8_t)(val >> 16); + buf[2] = (uint8_t)(val >> 8); + buf[3] = (uint8_t)val; } #endif @@ -135,7 +128,7 @@ static inline void put_unaligned_be32(uint32_t val, uint8_t *buf) * could save a few bytes in code size. */ #ifndef get_le32 -# define get_le32 get_unaligned_le32 +#define get_le32 get_unaligned_le32 #endif #endif diff --git a/ext_libs/minixz/xz_crc32.c b/ext_libs/minixz/xz_crc32.c index b89bfc23..06861d7d 100644 --- a/ext_libs/minixz/xz_crc32.c +++ b/ext_libs/minixz/xz_crc32.c @@ -54,38 +54,40 @@ * See for details. */ #ifndef STATIC_RW_DATA -# define STATIC_RW_DATA static +#define STATIC_RW_DATA static #endif STATIC_RW_DATA uint32_t xz_crc32_table[256]; XZ_EXTERN void xz_crc32_init(void) { - const uint32_t poly = 0xEDB88320; + const uint32_t poly = 0xEDB88320; - uint32_t i; - uint32_t j; - uint32_t r; + uint32_t i; + uint32_t j; + uint32_t r; - for (i = 0; i < 256; ++i) { - r = i; - for (j = 0; j < 8; ++j) - r = (r >> 1) ^ (poly & ~((r & 1) - 1)); + for (i = 0; i < 256; ++i) + { + r = i; + for (j = 0; j < 8; ++j) + r = (r >> 1) ^ (poly & ~((r & 1) - 1)); - xz_crc32_table[i] = r; - } + xz_crc32_table[i] = r; + } - return; + return; } -XZ_EXTERN uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc) +XZ_EXTERN uint32_t xz_crc32(const uint8_t* buf, size_t size, uint32_t crc) { - crc = ~crc; + crc = ~crc; - while (size != 0) { - crc = xz_crc32_table[*buf++ ^ (crc & 0xFF)] ^ (crc >> 8); - --size; - } + while (size != 0) + { + crc = xz_crc32_table[*buf++ ^ (crc & 0xFF)] ^ (crc >> 8); + --size; + } - return ~crc; + return ~crc; } diff --git a/ext_libs/minixz/xz_dec_bcj.c b/ext_libs/minixz/xz_dec_bcj.c index 37640f9f..5afd2964 100644 --- a/ext_libs/minixz/xz_dec_bcj.c +++ b/ext_libs/minixz/xz_dec_bcj.c @@ -49,63 +49,66 @@ */ #ifdef XZ_DEC_BCJ -struct xz_dec_bcj { - /* Type of the BCJ filter being used */ - enum { - BCJ_X86 = 4, /* x86 or x86-64 */ - BCJ_POWERPC = 5, /* Big endian only */ - BCJ_IA64 = 6, /* Big or little endian */ - BCJ_ARM = 7, /* Little endian only */ - BCJ_ARMTHUMB = 8, /* Little endian only */ - BCJ_SPARC = 9 /* Big or little endian */ - } type; - - /* - * Return value of the next filter in the chain. We need to preserve - * this information across calls, because we must not call the next - * filter anymore once it has returned XZ_STREAM_END. - */ - enum xz_ret ret; - - /* True if we are operating in single-call mode. */ - bool single_call; - - /* - * Absolute position relative to the beginning of the uncompressed - * data (in a single .xz Block). We care only about the lowest 32 - * bits so this doesn't need to be uint64_t even with big files. - */ - uint32_t pos; - - /* x86 filter state */ - uint32_t x86_prev_mask; - - /* Temporary space to hold the variables from struct xz_buf */ - uint8_t *out; - size_t out_pos; - size_t out_size; - - struct { - /* Amount of already filtered data in the beginning of buf */ - size_t filtered; - - /* Total amount of data currently stored in buf */ - size_t size; - - /* - * Buffer to hold a mix of filtered and unfiltered data. This - * needs to be big enough to hold Alignment + 2 * Look-ahead: - * - * Type Alignment Look-ahead - * x86 1 4 - * PowerPC 4 0 - * IA-64 16 0 - * ARM 4 0 - * ARM-Thumb 2 2 - * SPARC 4 0 - */ - uint8_t buf[16]; - } temp; +struct xz_dec_bcj +{ + /* Type of the BCJ filter being used */ + enum + { + BCJ_X86 = 4, /* x86 or x86-64 */ + BCJ_POWERPC = 5, /* Big endian only */ + BCJ_IA64 = 6, /* Big or little endian */ + BCJ_ARM = 7, /* Little endian only */ + BCJ_ARMTHUMB = 8, /* Little endian only */ + BCJ_SPARC = 9 /* Big or little endian */ + } type; + + /* + * Return value of the next filter in the chain. We need to preserve + * this information across calls, because we must not call the next + * filter anymore once it has returned XZ_STREAM_END. + */ + enum xz_ret ret; + + /* True if we are operating in single-call mode. */ + bool single_call; + + /* + * Absolute position relative to the beginning of the uncompressed + * data (in a single .xz Block). We care only about the lowest 32 + * bits so this doesn't need to be uint64_t even with big files. + */ + uint32_t pos; + + /* x86 filter state */ + uint32_t x86_prev_mask; + + /* Temporary space to hold the variables from struct xz_buf */ + uint8_t* out; + size_t out_pos; + size_t out_size; + + struct + { + /* Amount of already filtered data in the beginning of buf */ + size_t filtered; + + /* Total amount of data currently stored in buf */ + size_t size; + + /* + * Buffer to hold a mix of filtered and unfiltered data. This + * needs to be big enough to hold Alignment + 2 * Look-ahead: + * + * Type Alignment Look-ahead + * x86 1 4 + * PowerPC 4 0 + * IA-64 16 0 + * ARM 4 0 + * ARM-Thumb 2 2 + * SPARC 4 0 + */ + uint8_t buf[16]; + } temp; }; #ifdef XZ_DEC_X86 @@ -115,255 +118,261 @@ struct xz_dec_bcj { */ static inline int bcj_x86_test_msbyte(uint8_t b) { - return b == 0x00 || b == 0xFF; + return b == 0x00 || b == 0xFF; } -static size_t bcj_x86(struct xz_dec_bcj *s, uint8_t *buf, size_t size) +static size_t bcj_x86(struct xz_dec_bcj* s, uint8_t* buf, size_t size) { - static const bool mask_to_allowed_status[8] - = { true, true, true, false, true, false, false, false }; - - static const uint8_t mask_to_bit_num[8] = { 0, 1, 2, 2, 3, 3, 3, 3 }; - - size_t i; - size_t prev_pos = (size_t)-1; - uint32_t prev_mask = s->x86_prev_mask; - uint32_t src; - uint32_t dest; - uint32_t j; - uint8_t b; - - if (size <= 4) - return 0; - - size -= 4; - for (i = 0; i < size; ++i) { - if ((buf[i] & 0xFE) != 0xE8) - continue; - - prev_pos = i - prev_pos; - if (prev_pos > 3) { - prev_mask = 0; - } else { - prev_mask = (prev_mask << (prev_pos - 1)) & 7; - if (prev_mask != 0) { - b = buf[i + 4 - mask_to_bit_num[prev_mask]]; - if (!mask_to_allowed_status[prev_mask] - || bcj_x86_test_msbyte(b)) { - prev_pos = i; - prev_mask = (prev_mask << 1) | 1; - continue; - } - } - } - - prev_pos = i; - - if (bcj_x86_test_msbyte(buf[i + 4])) { - src = get_unaligned_le32(buf + i + 1); - while (true) { - dest = src - (s->pos + (uint32_t)i + 5); - if (prev_mask == 0) - break; - - j = mask_to_bit_num[prev_mask] * 8; - b = (uint8_t)(dest >> (24 - j)); - if (!bcj_x86_test_msbyte(b)) - break; - - src = dest ^ (((uint32_t)1 << (32 - j)) - 1); - } - - dest &= 0x01FFFFFF; - dest |= (uint32_t)0 - (dest & 0x01000000); - put_unaligned_le32(dest, buf + i + 1); - i += 4; - } else { - prev_mask = (prev_mask << 1) | 1; - } - } - - prev_pos = i - prev_pos; - s->x86_prev_mask = prev_pos > 3 ? 0 : prev_mask << (prev_pos - 1); - return i; + static const bool mask_to_allowed_status[8] = {true, true, true, false, true, false, false, false}; + + static const uint8_t mask_to_bit_num[8] = {0, 1, 2, 2, 3, 3, 3, 3}; + + size_t i; + size_t prev_pos = (size_t)-1; + uint32_t prev_mask = s->x86_prev_mask; + uint32_t src; + uint32_t dest; + uint32_t j; + uint8_t b; + + if (size <= 4) + return 0; + + size -= 4; + for (i = 0; i < size; ++i) + { + if ((buf[i] & 0xFE) != 0xE8) + continue; + + prev_pos = i - prev_pos; + if (prev_pos > 3) + { + prev_mask = 0; + } + else + { + prev_mask = (prev_mask << (prev_pos - 1)) & 7; + if (prev_mask != 0) + { + b = buf[i + 4 - mask_to_bit_num[prev_mask]]; + if (!mask_to_allowed_status[prev_mask] || bcj_x86_test_msbyte(b)) + { + prev_pos = i; + prev_mask = (prev_mask << 1) | 1; + continue; + } + } + } + + prev_pos = i; + + if (bcj_x86_test_msbyte(buf[i + 4])) + { + src = get_unaligned_le32(buf + i + 1); + while (true) + { + dest = src - (s->pos + (uint32_t)i + 5); + if (prev_mask == 0) + break; + + j = mask_to_bit_num[prev_mask] * 8; + b = (uint8_t)(dest >> (24 - j)); + if (!bcj_x86_test_msbyte(b)) + break; + + src = dest ^ (((uint32_t)1 << (32 - j)) - 1); + } + + dest &= 0x01FFFFFF; + dest |= (uint32_t)0 - (dest & 0x01000000); + put_unaligned_le32(dest, buf + i + 1); + i += 4; + } + else + { + prev_mask = (prev_mask << 1) | 1; + } + } + + prev_pos = i - prev_pos; + s->x86_prev_mask = prev_pos > 3 ? 0 : prev_mask << (prev_pos - 1); + return i; } #endif #ifdef XZ_DEC_POWERPC -static size_t bcj_powerpc(struct xz_dec_bcj *s, uint8_t *buf, size_t size) +static size_t bcj_powerpc(struct xz_dec_bcj* s, uint8_t* buf, size_t size) { - size_t i; - uint32_t instr; - - for (i = 0; i + 4 <= size; i += 4) { - instr = get_unaligned_be32(buf + i); - if ((instr & 0xFC000003) == 0x48000001) { - instr &= 0x03FFFFFC; - instr -= s->pos + (uint32_t)i; - instr &= 0x03FFFFFC; - instr |= 0x48000001; - put_unaligned_be32(instr, buf + i); - } - } - - return i; + size_t i; + uint32_t instr; + + for (i = 0; i + 4 <= size; i += 4) + { + instr = get_unaligned_be32(buf + i); + if ((instr & 0xFC000003) == 0x48000001) + { + instr &= 0x03FFFFFC; + instr -= s->pos + (uint32_t)i; + instr &= 0x03FFFFFC; + instr |= 0x48000001; + put_unaligned_be32(instr, buf + i); + } + } + + return i; } #endif #ifdef XZ_DEC_IA64 -static size_t bcj_ia64(struct xz_dec_bcj *s, uint8_t *buf, size_t size) +static size_t bcj_ia64(struct xz_dec_bcj* s, uint8_t* buf, size_t size) { - static const uint8_t branch_table[32] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 4, 4, 6, 6, 0, 0, 7, 7, - 4, 4, 0, 0, 4, 4, 0, 0 - }; - - /* - * The local variables take a little bit stack space, but it's less - * than what LZMA2 decoder takes, so it doesn't make sense to reduce - * stack usage here without doing that for the LZMA2 decoder too. - */ - - /* Loop counters */ - size_t i; - size_t j; - - /* Instruction slot (0, 1, or 2) in the 128-bit instruction word */ - uint32_t slot; - - /* Bitwise offset of the instruction indicated by slot */ - uint32_t bit_pos; - - /* bit_pos split into byte and bit parts */ - uint32_t byte_pos; - uint32_t bit_res; - - /* Address part of an instruction */ - uint32_t addr; - - /* Mask used to detect which instructions to convert */ - uint32_t mask; - - /* 41-bit instruction stored somewhere in the lowest 48 bits */ - uint64_t instr; - - /* Instruction normalized with bit_res for easier manipulation */ - uint64_t norm; - - for (i = 0; i + 16 <= size; i += 16) { - mask = branch_table[buf[i] & 0x1F]; - for (slot = 0, bit_pos = 5; slot < 3; ++slot, bit_pos += 41) { - if (((mask >> slot) & 1) == 0) - continue; - - byte_pos = bit_pos >> 3; - bit_res = bit_pos & 7; - instr = 0; - for (j = 0; j < 6; ++j) - instr |= (uint64_t)(buf[i + j + byte_pos]) - << (8 * j); - - norm = instr >> bit_res; - - if (((norm >> 37) & 0x0F) == 0x05 - && ((norm >> 9) & 0x07) == 0) { - addr = (norm >> 13) & 0x0FFFFF; - addr |= ((uint32_t)(norm >> 36) & 1) << 20; - addr <<= 4; - addr -= s->pos + (uint32_t)i; - addr >>= 4; - - norm &= ~((uint64_t)0x8FFFFF << 13); - norm |= (uint64_t)(addr & 0x0FFFFF) << 13; - norm |= (uint64_t)(addr & 0x100000) - << (36 - 20); - - instr &= (1 << bit_res) - 1; - instr |= norm << bit_res; - - for (j = 0; j < 6; j++) - buf[i + j + byte_pos] - = (uint8_t)(instr >> (8 * j)); - } - } - } - - return i; + static const uint8_t branch_table[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 4, 6, 6, 0, 0, 7, 7, 4, 4, 0, 0, 4, 4, 0, 0}; + + /* + * The local variables take a little bit stack space, but it's less + * than what LZMA2 decoder takes, so it doesn't make sense to reduce + * stack usage here without doing that for the LZMA2 decoder too. + */ + + /* Loop counters */ + size_t i; + size_t j; + + /* Instruction slot (0, 1, or 2) in the 128-bit instruction word */ + uint32_t slot; + + /* Bitwise offset of the instruction indicated by slot */ + uint32_t bit_pos; + + /* bit_pos split into byte and bit parts */ + uint32_t byte_pos; + uint32_t bit_res; + + /* Address part of an instruction */ + uint32_t addr; + + /* Mask used to detect which instructions to convert */ + uint32_t mask; + + /* 41-bit instruction stored somewhere in the lowest 48 bits */ + uint64_t instr; + + /* Instruction normalized with bit_res for easier manipulation */ + uint64_t norm; + + for (i = 0; i + 16 <= size; i += 16) + { + mask = branch_table[buf[i] & 0x1F]; + for (slot = 0, bit_pos = 5; slot < 3; ++slot, bit_pos += 41) + { + if (((mask >> slot) & 1) == 0) + continue; + + byte_pos = bit_pos >> 3; + bit_res = bit_pos & 7; + instr = 0; + for (j = 0; j < 6; ++j) + instr |= (uint64_t)(buf[i + j + byte_pos]) << (8 * j); + + norm = instr >> bit_res; + + if (((norm >> 37) & 0x0F) == 0x05 && ((norm >> 9) & 0x07) == 0) + { + addr = (norm >> 13) & 0x0FFFFF; + addr |= ((uint32_t)(norm >> 36) & 1) << 20; + addr <<= 4; + addr -= s->pos + (uint32_t)i; + addr >>= 4; + + norm &= ~((uint64_t)0x8FFFFF << 13); + norm |= (uint64_t)(addr & 0x0FFFFF) << 13; + norm |= (uint64_t)(addr & 0x100000) << (36 - 20); + + instr &= (1 << bit_res) - 1; + instr |= norm << bit_res; + + for (j = 0; j < 6; j++) + buf[i + j + byte_pos] = (uint8_t)(instr >> (8 * j)); + } + } + } + + return i; } #endif #ifdef XZ_DEC_ARM -static size_t bcj_arm(struct xz_dec_bcj *s, uint8_t *buf, size_t size) +static size_t bcj_arm(struct xz_dec_bcj* s, uint8_t* buf, size_t size) { - size_t i; - uint32_t addr; - - for (i = 0; i + 4 <= size; i += 4) { - if (buf[i + 3] == 0xEB) { - addr = (uint32_t)buf[i] | ((uint32_t)buf[i + 1] << 8) - | ((uint32_t)buf[i + 2] << 16); - addr <<= 2; - addr -= s->pos + (uint32_t)i + 8; - addr >>= 2; - buf[i] = (uint8_t)addr; - buf[i + 1] = (uint8_t)(addr >> 8); - buf[i + 2] = (uint8_t)(addr >> 16); - } - } - - return i; + size_t i; + uint32_t addr; + + for (i = 0; i + 4 <= size; i += 4) + { + if (buf[i + 3] == 0xEB) + { + addr = (uint32_t)buf[i] | ((uint32_t)buf[i + 1] << 8) | ((uint32_t)buf[i + 2] << 16); + addr <<= 2; + addr -= s->pos + (uint32_t)i + 8; + addr >>= 2; + buf[i] = (uint8_t)addr; + buf[i + 1] = (uint8_t)(addr >> 8); + buf[i + 2] = (uint8_t)(addr >> 16); + } + } + + return i; } #endif #ifdef XZ_DEC_ARMTHUMB -static size_t bcj_armthumb(struct xz_dec_bcj *s, uint8_t *buf, size_t size) +static size_t bcj_armthumb(struct xz_dec_bcj* s, uint8_t* buf, size_t size) { - size_t i; - uint32_t addr; - - for (i = 0; i + 4 <= size; i += 2) { - if ((buf[i + 1] & 0xF8) == 0xF0 - && (buf[i + 3] & 0xF8) == 0xF8) { - addr = (((uint32_t)buf[i + 1] & 0x07) << 19) - | ((uint32_t)buf[i] << 11) - | (((uint32_t)buf[i + 3] & 0x07) << 8) - | (uint32_t)buf[i + 2]; - addr <<= 1; - addr -= s->pos + (uint32_t)i + 4; - addr >>= 1; - buf[i + 1] = (uint8_t)(0xF0 | ((addr >> 19) & 0x07)); - buf[i] = (uint8_t)(addr >> 11); - buf[i + 3] = (uint8_t)(0xF8 | ((addr >> 8) & 0x07)); - buf[i + 2] = (uint8_t)addr; - i += 2; - } - } - - return i; + size_t i; + uint32_t addr; + + for (i = 0; i + 4 <= size; i += 2) + { + if ((buf[i + 1] & 0xF8) == 0xF0 && (buf[i + 3] & 0xF8) == 0xF8) + { + addr = (((uint32_t)buf[i + 1] & 0x07) << 19) | ((uint32_t)buf[i] << 11) | + (((uint32_t)buf[i + 3] & 0x07) << 8) | (uint32_t)buf[i + 2]; + addr <<= 1; + addr -= s->pos + (uint32_t)i + 4; + addr >>= 1; + buf[i + 1] = (uint8_t)(0xF0 | ((addr >> 19) & 0x07)); + buf[i] = (uint8_t)(addr >> 11); + buf[i + 3] = (uint8_t)(0xF8 | ((addr >> 8) & 0x07)); + buf[i + 2] = (uint8_t)addr; + i += 2; + } + } + + return i; } #endif #ifdef XZ_DEC_SPARC -static size_t bcj_sparc(struct xz_dec_bcj *s, uint8_t *buf, size_t size) +static size_t bcj_sparc(struct xz_dec_bcj* s, uint8_t* buf, size_t size) { - size_t i; - uint32_t instr; - - for (i = 0; i + 4 <= size; i += 4) { - instr = get_unaligned_be32(buf + i); - if ((instr >> 22) == 0x100 || (instr >> 22) == 0x1FF) { - instr <<= 2; - instr -= s->pos + (uint32_t)i; - instr >>= 2; - instr = ((uint32_t)0x40000000 - (instr & 0x400000)) - | 0x40000000 | (instr & 0x3FFFFF); - put_unaligned_be32(instr, buf + i); - } - } - - return i; + size_t i; + uint32_t instr; + + for (i = 0; i + 4 <= size; i += 4) + { + instr = get_unaligned_be32(buf + i); + if ((instr >> 22) == 0x100 || (instr >> 22) == 0x1FF) + { + instr <<= 2; + instr -= s->pos + (uint32_t)i; + instr >>= 2; + instr = ((uint32_t)0x40000000 - (instr & 0x400000)) | 0x40000000 | (instr & 0x3FFFFF); + put_unaligned_be32(instr, buf + i); + } + } + + return i; } #endif @@ -375,53 +384,53 @@ static size_t bcj_sparc(struct xz_dec_bcj *s, uint8_t *buf, size_t size) * pointers, which could be problematic in the kernel boot code, which must * avoid pointers to static data (at least on x86). */ -static void bcj_apply(struct xz_dec_bcj *s, - uint8_t *buf, size_t *pos, size_t size) +static void bcj_apply(struct xz_dec_bcj* s, uint8_t* buf, size_t* pos, size_t size) { - size_t filtered; + size_t filtered; - buf += *pos; - size -= *pos; + buf += *pos; + size -= *pos; - switch (s->type) { + switch (s->type) + { #ifdef XZ_DEC_X86 - case BCJ_X86: - filtered = bcj_x86(s, buf, size); - break; + case BCJ_X86: + filtered = bcj_x86(s, buf, size); + break; #endif #ifdef XZ_DEC_POWERPC - case BCJ_POWERPC: - filtered = bcj_powerpc(s, buf, size); - break; + case BCJ_POWERPC: + filtered = bcj_powerpc(s, buf, size); + break; #endif #ifdef XZ_DEC_IA64 - case BCJ_IA64: - filtered = bcj_ia64(s, buf, size); - break; + case BCJ_IA64: + filtered = bcj_ia64(s, buf, size); + break; #endif #ifdef XZ_DEC_ARM - case BCJ_ARM: - filtered = bcj_arm(s, buf, size); - break; + case BCJ_ARM: + filtered = bcj_arm(s, buf, size); + break; #endif #ifdef XZ_DEC_ARMTHUMB - case BCJ_ARMTHUMB: - filtered = bcj_armthumb(s, buf, size); - break; + case BCJ_ARMTHUMB: + filtered = bcj_armthumb(s, buf, size); + break; #endif #ifdef XZ_DEC_SPARC - case BCJ_SPARC: - filtered = bcj_sparc(s, buf, size); - break; + case BCJ_SPARC: + filtered = bcj_sparc(s, buf, size); + break; #endif - default: - /* Never reached but silence compiler warnings. */ - filtered = 0; - break; - } - - *pos += filtered; - s->pos += filtered; + default: + /* Never reached but silence compiler warnings. */ + filtered = 0; + break; + } + + *pos += filtered; + s->pos += filtered; } /* @@ -429,17 +438,17 @@ static void bcj_apply(struct xz_dec_bcj *s, * Move the remaining mixture of possibly filtered and unfiltered * data to the beginning of temp. */ -static void bcj_flush(struct xz_dec_bcj *s, struct xz_buf *b) +static void bcj_flush(struct xz_dec_bcj* s, struct xz_buf* b) { - size_t copy_size; + size_t copy_size; - copy_size = min_t(size_t, s->temp.filtered, b->out_size - b->out_pos); - memcpy(b->out + b->out_pos, s->temp.buf, copy_size); - b->out_pos += copy_size; + copy_size = min_t(size_t, s->temp.filtered, b->out_size - b->out_pos); + memcpy(b->out + b->out_pos, s->temp.buf, copy_size); + b->out_pos += copy_size; - s->temp.filtered -= copy_size; - s->temp.size -= copy_size; - memmove(s->temp.buf, s->temp.buf + copy_size, s->temp.size); + s->temp.filtered -= copy_size; + s->temp.size -= copy_size; + memmove(s->temp.buf, s->temp.buf + copy_size, s->temp.size); } /* @@ -447,161 +456,162 @@ static void bcj_flush(struct xz_dec_bcj *s, struct xz_buf *b) * data in chunks of 1-16 bytes. To hide this issue, this function does * some buffering. */ -XZ_EXTERN enum xz_ret xz_dec_bcj_run(struct xz_dec_bcj *s, - struct xz_dec_lzma2 *lzma2, - struct xz_buf *b) +XZ_EXTERN enum xz_ret xz_dec_bcj_run(struct xz_dec_bcj* s, struct xz_dec_lzma2* lzma2, struct xz_buf* b) { - size_t out_start; - - /* - * Flush pending already filtered data to the output buffer. Return - * immediatelly if we couldn't flush everything, or if the next - * filter in the chain had already returned XZ_STREAM_END. - */ - if (s->temp.filtered > 0) { - bcj_flush(s, b); - if (s->temp.filtered > 0) - return XZ_OK; - - if (s->ret == XZ_STREAM_END) - return XZ_STREAM_END; - } - - /* - * If we have more output space than what is currently pending in - * temp, copy the unfiltered data from temp to the output buffer - * and try to fill the output buffer by decoding more data from the - * next filter in the chain. Apply the BCJ filter on the new data - * in the output buffer. If everything cannot be filtered, copy it - * to temp and rewind the output buffer position accordingly. - * - * This needs to be always run when temp.size == 0 to handle a special - * case where the output buffer is full and the next filter has no - * more output coming but hasn't returned XZ_STREAM_END yet. - */ - if (s->temp.size < b->out_size - b->out_pos || s->temp.size == 0) { - out_start = b->out_pos; - memcpy(b->out + b->out_pos, s->temp.buf, s->temp.size); - b->out_pos += s->temp.size; - - s->ret = xz_dec_lzma2_run(lzma2, b); - if (s->ret != XZ_STREAM_END - && (s->ret != XZ_OK || s->single_call)) - return s->ret; - - bcj_apply(s, b->out, &out_start, b->out_pos); - - /* - * As an exception, if the next filter returned XZ_STREAM_END, - * we can do that too, since the last few bytes that remain - * unfiltered are meant to remain unfiltered. - */ - if (s->ret == XZ_STREAM_END) - return XZ_STREAM_END; - - s->temp.size = b->out_pos - out_start; - b->out_pos -= s->temp.size; - memcpy(s->temp.buf, b->out + b->out_pos, s->temp.size); - - /* - * If there wasn't enough input to the next filter to fill - * the output buffer with unfiltered data, there's no point - * to try decoding more data to temp. - */ - if (b->out_pos + s->temp.size < b->out_size) - return XZ_OK; - } - - /* - * We have unfiltered data in temp. If the output buffer isn't full - * yet, try to fill the temp buffer by decoding more data from the - * next filter. Apply the BCJ filter on temp. Then we hopefully can - * fill the actual output buffer by copying filtered data from temp. - * A mix of filtered and unfiltered data may be left in temp; it will - * be taken care on the next call to this function. - */ - if (b->out_pos < b->out_size) { - /* Make b->out{,_pos,_size} temporarily point to s->temp. */ - s->out = b->out; - s->out_pos = b->out_pos; - s->out_size = b->out_size; - b->out = s->temp.buf; - b->out_pos = s->temp.size; - b->out_size = sizeof(s->temp.buf); - - s->ret = xz_dec_lzma2_run(lzma2, b); - - s->temp.size = b->out_pos; - b->out = s->out; - b->out_pos = s->out_pos; - b->out_size = s->out_size; - - if (s->ret != XZ_OK && s->ret != XZ_STREAM_END) - return s->ret; - - bcj_apply(s, s->temp.buf, &s->temp.filtered, s->temp.size); - - /* - * If the next filter returned XZ_STREAM_END, we mark that - * everything is filtered, since the last unfiltered bytes - * of the stream are meant to be left as is. - */ - if (s->ret == XZ_STREAM_END) - s->temp.filtered = s->temp.size; - - bcj_flush(s, b); - if (s->temp.filtered > 0) - return XZ_OK; - } - - return s->ret; + size_t out_start; + + /* + * Flush pending already filtered data to the output buffer. Return + * immediatelly if we couldn't flush everything, or if the next + * filter in the chain had already returned XZ_STREAM_END. + */ + if (s->temp.filtered > 0) + { + bcj_flush(s, b); + if (s->temp.filtered > 0) + return XZ_OK; + + if (s->ret == XZ_STREAM_END) + return XZ_STREAM_END; + } + + /* + * If we have more output space than what is currently pending in + * temp, copy the unfiltered data from temp to the output buffer + * and try to fill the output buffer by decoding more data from the + * next filter in the chain. Apply the BCJ filter on the new data + * in the output buffer. If everything cannot be filtered, copy it + * to temp and rewind the output buffer position accordingly. + * + * This needs to be always run when temp.size == 0 to handle a special + * case where the output buffer is full and the next filter has no + * more output coming but hasn't returned XZ_STREAM_END yet. + */ + if (s->temp.size < b->out_size - b->out_pos || s->temp.size == 0) + { + out_start = b->out_pos; + memcpy(b->out + b->out_pos, s->temp.buf, s->temp.size); + b->out_pos += s->temp.size; + + s->ret = xz_dec_lzma2_run(lzma2, b); + if (s->ret != XZ_STREAM_END && (s->ret != XZ_OK || s->single_call)) + return s->ret; + + bcj_apply(s, b->out, &out_start, b->out_pos); + + /* + * As an exception, if the next filter returned XZ_STREAM_END, + * we can do that too, since the last few bytes that remain + * unfiltered are meant to remain unfiltered. + */ + if (s->ret == XZ_STREAM_END) + return XZ_STREAM_END; + + s->temp.size = b->out_pos - out_start; + b->out_pos -= s->temp.size; + memcpy(s->temp.buf, b->out + b->out_pos, s->temp.size); + + /* + * If there wasn't enough input to the next filter to fill + * the output buffer with unfiltered data, there's no point + * to try decoding more data to temp. + */ + if (b->out_pos + s->temp.size < b->out_size) + return XZ_OK; + } + + /* + * We have unfiltered data in temp. If the output buffer isn't full + * yet, try to fill the temp buffer by decoding more data from the + * next filter. Apply the BCJ filter on temp. Then we hopefully can + * fill the actual output buffer by copying filtered data from temp. + * A mix of filtered and unfiltered data may be left in temp; it will + * be taken care on the next call to this function. + */ + if (b->out_pos < b->out_size) + { + /* Make b->out{,_pos,_size} temporarily point to s->temp. */ + s->out = b->out; + s->out_pos = b->out_pos; + s->out_size = b->out_size; + b->out = s->temp.buf; + b->out_pos = s->temp.size; + b->out_size = sizeof(s->temp.buf); + + s->ret = xz_dec_lzma2_run(lzma2, b); + + s->temp.size = b->out_pos; + b->out = s->out; + b->out_pos = s->out_pos; + b->out_size = s->out_size; + + if (s->ret != XZ_OK && s->ret != XZ_STREAM_END) + return s->ret; + + bcj_apply(s, s->temp.buf, &s->temp.filtered, s->temp.size); + + /* + * If the next filter returned XZ_STREAM_END, we mark that + * everything is filtered, since the last unfiltered bytes + * of the stream are meant to be left as is. + */ + if (s->ret == XZ_STREAM_END) + s->temp.filtered = s->temp.size; + + bcj_flush(s, b); + if (s->temp.filtered > 0) + return XZ_OK; + } + + return s->ret; } -XZ_EXTERN struct xz_dec_bcj *xz_dec_bcj_create(bool single_call) +XZ_EXTERN struct xz_dec_bcj* xz_dec_bcj_create(bool single_call) { - struct xz_dec_bcj *s = kmalloc(sizeof(*s), GFP_KERNEL); - if (s != NULL) - s->single_call = single_call; + struct xz_dec_bcj* s = kmalloc(sizeof(*s), GFP_KERNEL); + if (s != NULL) + s->single_call = single_call; - return s; + return s; } -XZ_EXTERN enum xz_ret xz_dec_bcj_reset(struct xz_dec_bcj *s, uint8_t id) +XZ_EXTERN enum xz_ret xz_dec_bcj_reset(struct xz_dec_bcj* s, uint8_t id) { - switch (id) { + switch (id) + { #ifdef XZ_DEC_X86 - case BCJ_X86: + case BCJ_X86: #endif #ifdef XZ_DEC_POWERPC - case BCJ_POWERPC: + case BCJ_POWERPC: #endif #ifdef XZ_DEC_IA64 - case BCJ_IA64: + case BCJ_IA64: #endif #ifdef XZ_DEC_ARM - case BCJ_ARM: + case BCJ_ARM: #endif #ifdef XZ_DEC_ARMTHUMB - case BCJ_ARMTHUMB: + case BCJ_ARMTHUMB: #endif #ifdef XZ_DEC_SPARC - case BCJ_SPARC: + case BCJ_SPARC: #endif - break; + break; - default: - /* Unsupported Filter ID */ - return XZ_OPTIONS_ERROR; - } + default: + /* Unsupported Filter ID */ + return XZ_OPTIONS_ERROR; + } - s->type = id; - s->ret = XZ_OK; - s->pos = 0; - s->x86_prev_mask = 0; - s->temp.filtered = 0; - s->temp.size = 0; + s->type = id; + s->ret = XZ_OK; + s->pos = 0; + s->x86_prev_mask = 0; + s->temp.filtered = 0; + s->temp.size = 0; - return XZ_OK; + return XZ_OK; } #endif diff --git a/ext_libs/minixz/xz_dec_lzma2.c b/ext_libs/minixz/xz_dec_lzma2.c index a61a04fd..58a28a2b 100644 --- a/ext_libs/minixz/xz_dec_lzma2.c +++ b/ext_libs/minixz/xz_dec_lzma2.c @@ -75,238 +75,246 @@ * in which the dictionary variables address the actual output * buffer directly. */ -struct dictionary { - /* Beginning of the history buffer */ - uint8_t *buf; - - /* Old position in buf (before decoding more data) */ - size_t start; - - /* Position in buf */ - size_t pos; - - /* - * How full dictionary is. This is used to detect corrupt input that - * would read beyond the beginning of the uncompressed stream. - */ - size_t full; - - /* Write limit; we don't write to buf[limit] or later bytes. */ - size_t limit; - - /* - * End of the dictionary buffer. In multi-call mode, this is - * the same as the dictionary size. In single-call mode, this - * indicates the size of the output buffer. - */ - size_t end; - - /* - * Size of the dictionary as specified in Block Header. This is used - * together with "full" to detect corrupt input that would make us - * read beyond the beginning of the uncompressed stream. - */ - uint32_t size; - - /* - * Maximum allowed dictionary size in multi-call mode. - * This is ignored in single-call mode. - */ - uint32_t size_max; - - /* - * Amount of memory currently allocated for the dictionary. - * This is used only with XZ_DYNALLOC. (With XZ_PREALLOC, - * size_max is always the same as the allocated size.) - */ - uint32_t allocated; - - /* Operation mode */ - enum xz_mode mode; +struct dictionary +{ + /* Beginning of the history buffer */ + uint8_t* buf; + + /* Old position in buf (before decoding more data) */ + size_t start; + + /* Position in buf */ + size_t pos; + + /* + * How full dictionary is. This is used to detect corrupt input that + * would read beyond the beginning of the uncompressed stream. + */ + size_t full; + + /* Write limit; we don't write to buf[limit] or later bytes. */ + size_t limit; + + /* + * End of the dictionary buffer. In multi-call mode, this is + * the same as the dictionary size. In single-call mode, this + * indicates the size of the output buffer. + */ + size_t end; + + /* + * Size of the dictionary as specified in Block Header. This is used + * together with "full" to detect corrupt input that would make us + * read beyond the beginning of the uncompressed stream. + */ + uint32_t size; + + /* + * Maximum allowed dictionary size in multi-call mode. + * This is ignored in single-call mode. + */ + uint32_t size_max; + + /* + * Amount of memory currently allocated for the dictionary. + * This is used only with XZ_DYNALLOC. (With XZ_PREALLOC, + * size_max is always the same as the allocated size.) + */ + uint32_t allocated; + + /* Operation mode */ + enum xz_mode mode; }; /* Range decoder */ -struct rc_dec { - uint32_t range; - uint32_t code; - - /* - * Number of initializing bytes remaining to be read - * by rc_read_init(). - */ - uint32_t init_bytes_left; - - /* - * Buffer from which we read our input. It can be either - * temp.buf or the caller-provided input buffer. - */ - const uint8_t *in; - size_t in_pos; - size_t in_limit; +struct rc_dec +{ + uint32_t range; + uint32_t code; + + /* + * Number of initializing bytes remaining to be read + * by rc_read_init(). + */ + uint32_t init_bytes_left; + + /* + * Buffer from which we read our input. It can be either + * temp.buf or the caller-provided input buffer. + */ + const uint8_t* in; + size_t in_pos; + size_t in_limit; }; /* Probabilities for a length decoder. */ -struct lzma_len_dec { - /* Probability of match length being at least 10 */ - uint16_t choice; +struct lzma_len_dec +{ + /* Probability of match length being at least 10 */ + uint16_t choice; - /* Probability of match length being at least 18 */ - uint16_t choice2; + /* Probability of match length being at least 18 */ + uint16_t choice2; - /* Probabilities for match lengths 2-9 */ - uint16_t low[POS_STATES_MAX][LEN_LOW_SYMBOLS]; + /* Probabilities for match lengths 2-9 */ + uint16_t low[POS_STATES_MAX][LEN_LOW_SYMBOLS]; - /* Probabilities for match lengths 10-17 */ - uint16_t mid[POS_STATES_MAX][LEN_MID_SYMBOLS]; + /* Probabilities for match lengths 10-17 */ + uint16_t mid[POS_STATES_MAX][LEN_MID_SYMBOLS]; - /* Probabilities for match lengths 18-273 */ - uint16_t high[LEN_HIGH_SYMBOLS]; + /* Probabilities for match lengths 18-273 */ + uint16_t high[LEN_HIGH_SYMBOLS]; }; -struct lzma_dec { - /* Distances of latest four matches */ - uint32_t rep0; - uint32_t rep1; - uint32_t rep2; - uint32_t rep3; - - /* Types of the most recently seen LZMA symbols */ - enum lzma_state state; - - /* - * Length of a match. This is updated so that dict_repeat can - * be called again to finish repeating the whole match. - */ - uint32_t len; - - /* - * LZMA properties or related bit masks (number of literal - * context bits, a mask dervied from the number of literal - * position bits, and a mask dervied from the number - * position bits) - */ - uint32_t lc; - uint32_t literal_pos_mask; /* (1 << lp) - 1 */ - uint32_t pos_mask; /* (1 << pb) - 1 */ - - /* If 1, it's a match. Otherwise it's a single 8-bit literal. */ - uint16_t is_match[STATES][POS_STATES_MAX]; - - /* If 1, it's a repeated match. The distance is one of rep0 .. rep3. */ - uint16_t is_rep[STATES]; - - /* - * If 0, distance of a repeated match is rep0. - * Otherwise check is_rep1. - */ - uint16_t is_rep0[STATES]; - - /* - * If 0, distance of a repeated match is rep1. - * Otherwise check is_rep2. - */ - uint16_t is_rep1[STATES]; - - /* If 0, distance of a repeated match is rep2. Otherwise it is rep3. */ - uint16_t is_rep2[STATES]; - - /* - * If 1, the repeated match has length of one byte. Otherwise - * the length is decoded from rep_len_decoder. - */ - uint16_t is_rep0_long[STATES][POS_STATES_MAX]; - - /* - * Probability tree for the highest two bits of the match - * distance. There is a separate probability tree for match - * lengths of 2 (i.e. MATCH_LEN_MIN), 3, 4, and [5, 273]. - */ - uint16_t dist_slot[DIST_STATES][DIST_SLOTS]; - - /* - * Probility trees for additional bits for match distance - * when the distance is in the range [4, 127]. - */ - uint16_t dist_special[FULL_DISTANCES - DIST_MODEL_END]; - - /* - * Probability tree for the lowest four bits of a match - * distance that is equal to or greater than 128. - */ - uint16_t dist_align[ALIGN_SIZE]; - - /* Length of a normal match */ - struct lzma_len_dec match_len_dec; - - /* Length of a repeated match */ - struct lzma_len_dec rep_len_dec; - - /* Probabilities of literals */ - uint16_t literal[LITERAL_CODERS_MAX][LITERAL_CODER_SIZE]; +struct lzma_dec +{ + /* Distances of latest four matches */ + uint32_t rep0; + uint32_t rep1; + uint32_t rep2; + uint32_t rep3; + + /* Types of the most recently seen LZMA symbols */ + enum lzma_state state; + + /* + * Length of a match. This is updated so that dict_repeat can + * be called again to finish repeating the whole match. + */ + uint32_t len; + + /* + * LZMA properties or related bit masks (number of literal + * context bits, a mask dervied from the number of literal + * position bits, and a mask dervied from the number + * position bits) + */ + uint32_t lc; + uint32_t literal_pos_mask; /* (1 << lp) - 1 */ + uint32_t pos_mask; /* (1 << pb) - 1 */ + + /* If 1, it's a match. Otherwise it's a single 8-bit literal. */ + uint16_t is_match[STATES][POS_STATES_MAX]; + + /* If 1, it's a repeated match. The distance is one of rep0 .. rep3. */ + uint16_t is_rep[STATES]; + + /* + * If 0, distance of a repeated match is rep0. + * Otherwise check is_rep1. + */ + uint16_t is_rep0[STATES]; + + /* + * If 0, distance of a repeated match is rep1. + * Otherwise check is_rep2. + */ + uint16_t is_rep1[STATES]; + + /* If 0, distance of a repeated match is rep2. Otherwise it is rep3. */ + uint16_t is_rep2[STATES]; + + /* + * If 1, the repeated match has length of one byte. Otherwise + * the length is decoded from rep_len_decoder. + */ + uint16_t is_rep0_long[STATES][POS_STATES_MAX]; + + /* + * Probability tree for the highest two bits of the match + * distance. There is a separate probability tree for match + * lengths of 2 (i.e. MATCH_LEN_MIN), 3, 4, and [5, 273]. + */ + uint16_t dist_slot[DIST_STATES][DIST_SLOTS]; + + /* + * Probility trees for additional bits for match distance + * when the distance is in the range [4, 127]. + */ + uint16_t dist_special[FULL_DISTANCES - DIST_MODEL_END]; + + /* + * Probability tree for the lowest four bits of a match + * distance that is equal to or greater than 128. + */ + uint16_t dist_align[ALIGN_SIZE]; + + /* Length of a normal match */ + struct lzma_len_dec match_len_dec; + + /* Length of a repeated match */ + struct lzma_len_dec rep_len_dec; + + /* Probabilities of literals */ + uint16_t literal[LITERAL_CODERS_MAX][LITERAL_CODER_SIZE]; }; -struct lzma2_dec { - /* Position in xz_dec_lzma2_run(). */ - enum lzma2_seq { - SEQ_CONTROL, - SEQ_UNCOMPRESSED_1, - SEQ_UNCOMPRESSED_2, - SEQ_COMPRESSED_0, - SEQ_COMPRESSED_1, - SEQ_PROPERTIES, - SEQ_LZMA_PREPARE, - SEQ_LZMA_RUN, - SEQ_COPY - } sequence; - - /* Next position after decoding the compressed size of the chunk. */ - enum lzma2_seq next_sequence; - - /* Uncompressed size of LZMA chunk (2 MiB at maximum) */ - uint32_t uncompressed; - - /* - * Compressed size of LZMA chunk or compressed/uncompressed - * size of uncompressed chunk (64 KiB at maximum) - */ - uint32_t compressed; - - /* - * True if dictionary reset is needed. This is false before - * the first chunk (LZMA or uncompressed). - */ - bool need_dict_reset; - - /* - * True if new LZMA properties are needed. This is false - * before the first LZMA chunk. - */ - bool need_props; +struct lzma2_dec +{ + /* Position in xz_dec_lzma2_run(). */ + enum lzma2_seq + { + SEQ_CONTROL, + SEQ_UNCOMPRESSED_1, + SEQ_UNCOMPRESSED_2, + SEQ_COMPRESSED_0, + SEQ_COMPRESSED_1, + SEQ_PROPERTIES, + SEQ_LZMA_PREPARE, + SEQ_LZMA_RUN, + SEQ_COPY + } sequence; + + /* Next position after decoding the compressed size of the chunk. */ + enum lzma2_seq next_sequence; + + /* Uncompressed size of LZMA chunk (2 MiB at maximum) */ + uint32_t uncompressed; + + /* + * Compressed size of LZMA chunk or compressed/uncompressed + * size of uncompressed chunk (64 KiB at maximum) + */ + uint32_t compressed; + + /* + * True if dictionary reset is needed. This is false before + * the first chunk (LZMA or uncompressed). + */ + bool need_dict_reset; + + /* + * True if new LZMA properties are needed. This is false + * before the first LZMA chunk. + */ + bool need_props; }; -struct xz_dec_lzma2 { - /* - * The order below is important on x86 to reduce code size and - * it shouldn't hurt on other platforms. Everything up to and - * including lzma.pos_mask are in the first 128 bytes on x86-32, - * which allows using smaller instructions to access those - * variables. On x86-64, fewer variables fit into the first 128 - * bytes, but this is still the best order without sacrificing - * the readability by splitting the structures. - */ - struct rc_dec rc; - struct dictionary dict; - struct lzma2_dec lzma2; - struct lzma_dec lzma; - - /* - * Temporary buffer which holds small number of input bytes between - * decoder calls. See lzma2_lzma() for details. - */ - struct { - uint32_t size; - uint8_t buf[3 * LZMA_IN_REQUIRED]; - } temp; +struct xz_dec_lzma2 +{ + /* + * The order below is important on x86 to reduce code size and + * it shouldn't hurt on other platforms. Everything up to and + * including lzma.pos_mask are in the first 128 bytes on x86-32, + * which allows using smaller instructions to access those + * variables. On x86-64, fewer variables fit into the first 128 + * bytes, but this is still the best order without sacrificing + * the readability by splitting the structures. + */ + struct rc_dec rc; + struct dictionary dict; + struct lzma2_dec lzma2; + struct lzma_dec lzma; + + /* + * Temporary buffer which holds small number of input bytes between + * decoder calls. See lzma2_lzma() for details. + */ + struct + { + uint32_t size; + uint8_t buf[3 * LZMA_IN_REQUIRED]; + } temp; }; /************** @@ -317,32 +325,33 @@ struct xz_dec_lzma2 { * Reset the dictionary state. When in single-call mode, set up the beginning * of the dictionary to point to the actual output buffer. */ -static void dict_reset(struct dictionary *dict, struct xz_buf *b) +static void dict_reset(struct dictionary* dict, struct xz_buf* b) { - if (DEC_IS_SINGLE(dict->mode)) { - dict->buf = b->out + b->out_pos; - dict->end = b->out_size - b->out_pos; - } - - dict->start = 0; - dict->pos = 0; - dict->limit = 0; - dict->full = 0; + if (DEC_IS_SINGLE(dict->mode)) + { + dict->buf = b->out + b->out_pos; + dict->end = b->out_size - b->out_pos; + } + + dict->start = 0; + dict->pos = 0; + dict->limit = 0; + dict->full = 0; } /* Set dictionary write limit */ -static void dict_limit(struct dictionary *dict, size_t out_max) +static void dict_limit(struct dictionary* dict, size_t out_max) { - if (dict->end - dict->pos <= out_max) - dict->limit = dict->end; - else - dict->limit = dict->pos + out_max; + if (dict->end - dict->pos <= out_max) + dict->limit = dict->end; + else + dict->limit = dict->pos + out_max; } /* Return true if at least one byte can be written into the dictionary. */ -static inline bool dict_has_space(const struct dictionary *dict) +static inline bool dict_has_space(const struct dictionary* dict) { - return dict->pos < dict->limit; + return dict->pos < dict->limit; } /* @@ -351,25 +360,25 @@ static inline bool dict_has_space(const struct dictionary *dict) * still empty. This special case is needed for single-call decoding to * avoid writing a '\0' to the end of the destination buffer. */ -static inline uint32_t dict_get(const struct dictionary *dict, uint32_t dist) +static inline uint32_t dict_get(const struct dictionary* dict, uint32_t dist) { - size_t offset = dict->pos - dist - 1; + size_t offset = dict->pos - dist - 1; - if (dist >= dict->pos) - offset += dict->end; + if (dist >= dict->pos) + offset += dict->end; - return dict->full > 0 ? dict->buf[offset] : 0; + return dict->full > 0 ? dict->buf[offset] : 0; } /* * Put one byte into the dictionary. It is assumed that there is space for it. */ -static inline void dict_put(struct dictionary *dict, uint8_t byte) +static inline void dict_put(struct dictionary* dict, uint8_t byte) { - dict->buf[dict->pos++] = byte; + dict->buf[dict->pos++] = byte; - if (dict->full < dict->pos) - dict->full = dict->pos; + if (dict->full < dict->pos) + dict->full = dict->pos; } /* @@ -377,69 +386,68 @@ static inline void dict_put(struct dictionary *dict, uint8_t byte) * invalid, false is returned. On success, true is returned and *len is * updated to indicate how many bytes were left to be repeated. */ -static bool dict_repeat(struct dictionary *dict, uint32_t *len, uint32_t dist) +static bool dict_repeat(struct dictionary* dict, uint32_t* len, uint32_t dist) { - size_t back; - uint32_t left; + size_t back; + uint32_t left; - if (dist >= dict->full || dist >= dict->size) - return false; + if (dist >= dict->full || dist >= dict->size) + return false; - left = min_t(size_t, dict->limit - dict->pos, *len); - *len -= left; + left = min_t(size_t, dict->limit - dict->pos, *len); + *len -= left; - back = dict->pos - dist - 1; - if (dist >= dict->pos) - back += dict->end; + back = dict->pos - dist - 1; + if (dist >= dict->pos) + back += dict->end; - do { - dict->buf[dict->pos++] = dict->buf[back++]; - if (back == dict->end) - back = 0; - } while (--left > 0); + do + { + dict->buf[dict->pos++] = dict->buf[back++]; + if (back == dict->end) + back = 0; + } while (--left > 0); - if (dict->full < dict->pos) - dict->full = dict->pos; + if (dict->full < dict->pos) + dict->full = dict->pos; - return true; + return true; } /* Copy uncompressed data as is from input to dictionary and output buffers. */ -static void dict_uncompressed(struct dictionary *dict, struct xz_buf *b, - uint32_t *left) +static void dict_uncompressed(struct dictionary* dict, struct xz_buf* b, uint32_t* left) { - size_t copy_size; + size_t copy_size; - while (*left > 0 && b->in_pos < b->in_size - && b->out_pos < b->out_size) { - copy_size = min(b->in_size - b->in_pos, - b->out_size - b->out_pos); - if (copy_size > dict->end - dict->pos) - copy_size = dict->end - dict->pos; - if (copy_size > *left) - copy_size = *left; + while (*left > 0 && b->in_pos < b->in_size && b->out_pos < b->out_size) + { + copy_size = min(b->in_size - b->in_pos, b->out_size - b->out_pos); + if (copy_size > dict->end - dict->pos) + copy_size = dict->end - dict->pos; + if (copy_size > *left) + copy_size = *left; - *left -= copy_size; + *left -= copy_size; - memcpy(dict->buf + dict->pos, b->in + b->in_pos, copy_size); - dict->pos += copy_size; + memcpy(dict->buf + dict->pos, b->in + b->in_pos, copy_size); + dict->pos += copy_size; - if (dict->full < dict->pos) - dict->full = dict->pos; + if (dict->full < dict->pos) + dict->full = dict->pos; - if (DEC_IS_MULTI(dict->mode)) { - if (dict->pos == dict->end) - dict->pos = 0; + if (DEC_IS_MULTI(dict->mode)) + { + if (dict->pos == dict->end) + dict->pos = 0; - memcpy(b->out + b->out_pos, b->in + b->in_pos, - copy_size); - } + memcpy(b->out + b->out_pos, b->in + b->in_pos, copy_size); + } - dict->start = dict->pos; + dict->start = dict->pos; - b->out_pos += copy_size; - b->in_pos += copy_size; - } + b->out_pos += copy_size; + b->in_pos += copy_size; + } } /* @@ -447,21 +455,21 @@ static void dict_uncompressed(struct dictionary *dict, struct xz_buf *b, * enough space in b->out. This is guaranteed because caller uses dict_limit() * before decoding data into the dictionary. */ -static uint32_t dict_flush(struct dictionary *dict, struct xz_buf *b) +static uint32_t dict_flush(struct dictionary* dict, struct xz_buf* b) { - size_t copy_size = dict->pos - dict->start; + size_t copy_size = dict->pos - dict->start; - if (DEC_IS_MULTI(dict->mode)) { - if (dict->pos == dict->end) - dict->pos = 0; + if (DEC_IS_MULTI(dict->mode)) + { + if (dict->pos == dict->end) + dict->pos = 0; - memcpy(b->out + b->out_pos, dict->buf + dict->start, - copy_size); - } + memcpy(b->out + b->out_pos, dict->buf + dict->start, copy_size); + } - dict->start = dict->pos; - b->out_pos += copy_size; - return copy_size; + dict->start = dict->pos; + b->out_pos += copy_size; + return copy_size; } /***************** @@ -469,52 +477,54 @@ static uint32_t dict_flush(struct dictionary *dict, struct xz_buf *b) *****************/ /* Reset the range decoder. */ -static void rc_reset(struct rc_dec *rc) +static void rc_reset(struct rc_dec* rc) { - rc->range = (uint32_t)-1; - rc->code = 0; - rc->init_bytes_left = RC_INIT_BYTES; + rc->range = (uint32_t)-1; + rc->code = 0; + rc->init_bytes_left = RC_INIT_BYTES; } /* * Read the first five initial bytes into rc->code if they haven't been * read already. (Yes, the first byte gets completely ignored.) */ -static bool rc_read_init(struct rc_dec *rc, struct xz_buf *b) +static bool rc_read_init(struct rc_dec* rc, struct xz_buf* b) { - while (rc->init_bytes_left > 0) { - if (b->in_pos == b->in_size) - return false; + while (rc->init_bytes_left > 0) + { + if (b->in_pos == b->in_size) + return false; - rc->code = (rc->code << 8) + b->in[b->in_pos++]; - --rc->init_bytes_left; - } + rc->code = (rc->code << 8) + b->in[b->in_pos++]; + --rc->init_bytes_left; + } - return true; + return true; } /* Return true if there may not be enough input for the next decoding loop. */ -static inline bool rc_limit_exceeded(const struct rc_dec *rc) +static inline bool rc_limit_exceeded(const struct rc_dec* rc) { - return rc->in_pos > rc->in_limit; + return rc->in_pos > rc->in_limit; } /* * Return true if it is possible (from point of view of range decoder) that * we have reached the end of the LZMA chunk. */ -static inline bool rc_is_finished(const struct rc_dec *rc) +static inline bool rc_is_finished(const struct rc_dec* rc) { - return rc->code == 0; + return rc->code == 0; } /* Read the next input byte if needed. */ -static __always_inline void rc_normalize(struct rc_dec *rc) +static __always_inline void rc_normalize(struct rc_dec* rc) { - if (rc->range < RC_TOP_VALUE) { - rc->range <<= RC_SHIFT_BITS; - rc->code = (rc->code << RC_SHIFT_BITS) + rc->in[rc->in_pos++]; - } + if (rc->range < RC_TOP_VALUE) + { + rc->range <<= RC_SHIFT_BITS; + rc->code = (rc->code << RC_SHIFT_BITS) + rc->in[rc->in_pos++]; + } } /* @@ -528,74 +538,80 @@ static __always_inline void rc_normalize(struct rc_dec *rc) * of the code generated by GCC 3.x decreases 10-15 %. (GCC 4.3 doesn't care, * and it generates 10-20 % faster code than GCC 3.x from this file anyway.) */ -static __always_inline int rc_bit(struct rc_dec *rc, uint16_t *prob) +static __always_inline int rc_bit(struct rc_dec* rc, uint16_t* prob) { - uint32_t bound; - int bit; - - rc_normalize(rc); - bound = (rc->range >> RC_BIT_MODEL_TOTAL_BITS) * *prob; - if (rc->code < bound) { - rc->range = bound; - *prob += (RC_BIT_MODEL_TOTAL - *prob) >> RC_MOVE_BITS; - bit = 0; - } else { - rc->range -= bound; - rc->code -= bound; - *prob -= *prob >> RC_MOVE_BITS; - bit = 1; - } - - return bit; + uint32_t bound; + int bit; + + rc_normalize(rc); + bound = (rc->range >> RC_BIT_MODEL_TOTAL_BITS) * *prob; + if (rc->code < bound) + { + rc->range = bound; + *prob += (RC_BIT_MODEL_TOTAL - *prob) >> RC_MOVE_BITS; + bit = 0; + } + else + { + rc->range -= bound; + rc->code -= bound; + *prob -= *prob >> RC_MOVE_BITS; + bit = 1; + } + + return bit; } /* Decode a bittree starting from the most significant bit. */ -static __always_inline uint32_t rc_bittree(struct rc_dec *rc, - uint16_t *probs, uint32_t limit) +static __always_inline uint32_t rc_bittree(struct rc_dec* rc, uint16_t* probs, uint32_t limit) { - uint32_t symbol = 1; + uint32_t symbol = 1; - do { - if (rc_bit(rc, &probs[symbol])) - symbol = (symbol << 1) + 1; - else - symbol <<= 1; - } while (symbol < limit); + do + { + if (rc_bit(rc, &probs[symbol])) + symbol = (symbol << 1) + 1; + else + symbol <<= 1; + } while (symbol < limit); - return symbol; + return symbol; } /* Decode a bittree starting from the least significant bit. */ -static __always_inline void rc_bittree_reverse(struct rc_dec *rc, - uint16_t *probs, - uint32_t *dest, uint32_t limit) +static __always_inline void rc_bittree_reverse(struct rc_dec* rc, uint16_t* probs, uint32_t* dest, uint32_t limit) { - uint32_t symbol = 1; - uint32_t i = 0; - - do { - if (rc_bit(rc, &probs[symbol])) { - symbol = (symbol << 1) + 1; - *dest += 1 << i; - } else { - symbol <<= 1; - } - } while (++i < limit); + uint32_t symbol = 1; + uint32_t i = 0; + + do + { + if (rc_bit(rc, &probs[symbol])) + { + symbol = (symbol << 1) + 1; + *dest += 1 << i; + } + else + { + symbol <<= 1; + } + } while (++i < limit); } /* Decode direct bits (fixed fifty-fifty probability) */ -static inline void rc_direct(struct rc_dec *rc, uint32_t *dest, uint32_t limit) +static inline void rc_direct(struct rc_dec* rc, uint32_t* dest, uint32_t limit) { - uint32_t mask; - - do { - rc_normalize(rc); - rc->range >>= 1; - rc->code -= rc->range; - mask = (uint32_t)0 - (rc->code >> 31); - rc->code += rc->range & mask; - *dest = (*dest << 1) + (mask + 1); - } while (--limit > 0); + uint32_t mask; + + do + { + rc_normalize(rc); + rc->range >>= 1; + rc->code -= rc->range; + mask = (uint32_t)0 - (rc->code >> 31); + rc->code += rc->range & mask; + *dest = (*dest << 1) + (mask + 1); + } while (--limit > 0); } /******** @@ -603,226 +619,252 @@ static inline void rc_direct(struct rc_dec *rc, uint32_t *dest, uint32_t limit) ********/ /* Get pointer to literal coder probability array. */ -static uint16_t *lzma_literal_probs(struct xz_dec_lzma2 *s) +static uint16_t* lzma_literal_probs(struct xz_dec_lzma2* s) { - uint32_t prev_byte = dict_get(&s->dict, 0); - uint32_t low = prev_byte >> (8 - s->lzma.lc); - uint32_t high = (s->dict.pos & s->lzma.literal_pos_mask) << s->lzma.lc; - return s->lzma.literal[low + high]; + uint32_t prev_byte = dict_get(&s->dict, 0); + uint32_t low = prev_byte >> (8 - s->lzma.lc); + uint32_t high = (s->dict.pos & s->lzma.literal_pos_mask) << s->lzma.lc; + return s->lzma.literal[low + high]; } /* Decode a literal (one 8-bit byte) */ -static void lzma_literal(struct xz_dec_lzma2 *s) +static void lzma_literal(struct xz_dec_lzma2* s) { - uint16_t *probs; - uint32_t symbol; - uint32_t match_byte; - uint32_t match_bit; - uint32_t offset; - uint32_t i; - - probs = lzma_literal_probs(s); - - if (lzma_state_is_literal(s->lzma.state)) { - symbol = rc_bittree(&s->rc, probs, 0x100); - } else { - symbol = 1; - match_byte = dict_get(&s->dict, s->lzma.rep0) << 1; - offset = 0x100; - - do { - match_bit = match_byte & offset; - match_byte <<= 1; - i = offset + match_bit + symbol; - - if (rc_bit(&s->rc, &probs[i])) { - symbol = (symbol << 1) + 1; - offset &= match_bit; - } else { - symbol <<= 1; - offset &= ~match_bit; - } - } while (symbol < 0x100); - } - - dict_put(&s->dict, (uint8_t)symbol); - lzma_state_literal(&s->lzma.state); + uint16_t* probs; + uint32_t symbol; + uint32_t match_byte; + uint32_t match_bit; + uint32_t offset; + uint32_t i; + + probs = lzma_literal_probs(s); + + if (lzma_state_is_literal(s->lzma.state)) + { + symbol = rc_bittree(&s->rc, probs, 0x100); + } + else + { + symbol = 1; + match_byte = dict_get(&s->dict, s->lzma.rep0) << 1; + offset = 0x100; + + do + { + match_bit = match_byte & offset; + match_byte <<= 1; + i = offset + match_bit + symbol; + + if (rc_bit(&s->rc, &probs[i])) + { + symbol = (symbol << 1) + 1; + offset &= match_bit; + } + else + { + symbol <<= 1; + offset &= ~match_bit; + } + } while (symbol < 0x100); + } + + dict_put(&s->dict, (uint8_t)symbol); + lzma_state_literal(&s->lzma.state); } /* Decode the length of the match into s->lzma.len. */ -static void lzma_len(struct xz_dec_lzma2 *s, struct lzma_len_dec *l, - uint32_t pos_state) +static void lzma_len(struct xz_dec_lzma2* s, struct lzma_len_dec* l, uint32_t pos_state) { - uint16_t *probs; - uint32_t limit; - - if (!rc_bit(&s->rc, &l->choice)) { - probs = l->low[pos_state]; - limit = LEN_LOW_SYMBOLS; - s->lzma.len = MATCH_LEN_MIN; - } else { - if (!rc_bit(&s->rc, &l->choice2)) { - probs = l->mid[pos_state]; - limit = LEN_MID_SYMBOLS; - s->lzma.len = MATCH_LEN_MIN + LEN_LOW_SYMBOLS; - } else { - probs = l->high; - limit = LEN_HIGH_SYMBOLS; - s->lzma.len = MATCH_LEN_MIN + LEN_LOW_SYMBOLS - + LEN_MID_SYMBOLS; - } - } - - s->lzma.len += rc_bittree(&s->rc, probs, limit) - limit; + uint16_t* probs; + uint32_t limit; + + if (!rc_bit(&s->rc, &l->choice)) + { + probs = l->low[pos_state]; + limit = LEN_LOW_SYMBOLS; + s->lzma.len = MATCH_LEN_MIN; + } + else + { + if (!rc_bit(&s->rc, &l->choice2)) + { + probs = l->mid[pos_state]; + limit = LEN_MID_SYMBOLS; + s->lzma.len = MATCH_LEN_MIN + LEN_LOW_SYMBOLS; + } + else + { + probs = l->high; + limit = LEN_HIGH_SYMBOLS; + s->lzma.len = MATCH_LEN_MIN + LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS; + } + } + + s->lzma.len += rc_bittree(&s->rc, probs, limit) - limit; } /* Decode a match. The distance will be stored in s->lzma.rep0. */ -static void lzma_match(struct xz_dec_lzma2 *s, uint32_t pos_state) +static void lzma_match(struct xz_dec_lzma2* s, uint32_t pos_state) { - uint16_t *probs; - uint32_t dist_slot; - uint32_t limit; - - lzma_state_match(&s->lzma.state); - - s->lzma.rep3 = s->lzma.rep2; - s->lzma.rep2 = s->lzma.rep1; - s->lzma.rep1 = s->lzma.rep0; - - lzma_len(s, &s->lzma.match_len_dec, pos_state); - - probs = s->lzma.dist_slot[lzma_get_dist_state(s->lzma.len)]; - dist_slot = rc_bittree(&s->rc, probs, DIST_SLOTS) - DIST_SLOTS; - - if (dist_slot < DIST_MODEL_START) { - s->lzma.rep0 = dist_slot; - } else { - limit = (dist_slot >> 1) - 1; - s->lzma.rep0 = 2 + (dist_slot & 1); - - if (dist_slot < DIST_MODEL_END) { - s->lzma.rep0 <<= limit; - probs = s->lzma.dist_special + s->lzma.rep0 - - dist_slot - 1; - rc_bittree_reverse(&s->rc, probs, - &s->lzma.rep0, limit); - } else { - rc_direct(&s->rc, &s->lzma.rep0, limit - ALIGN_BITS); - s->lzma.rep0 <<= ALIGN_BITS; - rc_bittree_reverse(&s->rc, s->lzma.dist_align, - &s->lzma.rep0, ALIGN_BITS); - } - } + uint16_t* probs; + uint32_t dist_slot; + uint32_t limit; + + lzma_state_match(&s->lzma.state); + + s->lzma.rep3 = s->lzma.rep2; + s->lzma.rep2 = s->lzma.rep1; + s->lzma.rep1 = s->lzma.rep0; + + lzma_len(s, &s->lzma.match_len_dec, pos_state); + + probs = s->lzma.dist_slot[lzma_get_dist_state(s->lzma.len)]; + dist_slot = rc_bittree(&s->rc, probs, DIST_SLOTS) - DIST_SLOTS; + + if (dist_slot < DIST_MODEL_START) + { + s->lzma.rep0 = dist_slot; + } + else + { + limit = (dist_slot >> 1) - 1; + s->lzma.rep0 = 2 + (dist_slot & 1); + + if (dist_slot < DIST_MODEL_END) + { + s->lzma.rep0 <<= limit; + probs = s->lzma.dist_special + s->lzma.rep0 - dist_slot - 1; + rc_bittree_reverse(&s->rc, probs, &s->lzma.rep0, limit); + } + else + { + rc_direct(&s->rc, &s->lzma.rep0, limit - ALIGN_BITS); + s->lzma.rep0 <<= ALIGN_BITS; + rc_bittree_reverse(&s->rc, s->lzma.dist_align, &s->lzma.rep0, ALIGN_BITS); + } + } } /* * Decode a repeated match. The distance is one of the four most recently * seen matches. The distance will be stored in s->lzma.rep0. */ -static void lzma_rep_match(struct xz_dec_lzma2 *s, uint32_t pos_state) +static void lzma_rep_match(struct xz_dec_lzma2* s, uint32_t pos_state) { - uint32_t tmp; - - if (!rc_bit(&s->rc, &s->lzma.is_rep0[s->lzma.state])) { - if (!rc_bit(&s->rc, &s->lzma.is_rep0_long[ - s->lzma.state][pos_state])) { - lzma_state_short_rep(&s->lzma.state); - s->lzma.len = 1; - return; - } - } else { - if (!rc_bit(&s->rc, &s->lzma.is_rep1[s->lzma.state])) { - tmp = s->lzma.rep1; - } else { - if (!rc_bit(&s->rc, &s->lzma.is_rep2[s->lzma.state])) { - tmp = s->lzma.rep2; - } else { - tmp = s->lzma.rep3; - s->lzma.rep3 = s->lzma.rep2; - } - - s->lzma.rep2 = s->lzma.rep1; - } - - s->lzma.rep1 = s->lzma.rep0; - s->lzma.rep0 = tmp; - } - - lzma_state_long_rep(&s->lzma.state); - lzma_len(s, &s->lzma.rep_len_dec, pos_state); + uint32_t tmp; + + if (!rc_bit(&s->rc, &s->lzma.is_rep0[s->lzma.state])) + { + if (!rc_bit(&s->rc, &s->lzma.is_rep0_long[s->lzma.state][pos_state])) + { + lzma_state_short_rep(&s->lzma.state); + s->lzma.len = 1; + return; + } + } + else + { + if (!rc_bit(&s->rc, &s->lzma.is_rep1[s->lzma.state])) + { + tmp = s->lzma.rep1; + } + else + { + if (!rc_bit(&s->rc, &s->lzma.is_rep2[s->lzma.state])) + { + tmp = s->lzma.rep2; + } + else + { + tmp = s->lzma.rep3; + s->lzma.rep3 = s->lzma.rep2; + } + + s->lzma.rep2 = s->lzma.rep1; + } + + s->lzma.rep1 = s->lzma.rep0; + s->lzma.rep0 = tmp; + } + + lzma_state_long_rep(&s->lzma.state); + lzma_len(s, &s->lzma.rep_len_dec, pos_state); } /* LZMA decoder core */ -static bool lzma_main(struct xz_dec_lzma2 *s) +static bool lzma_main(struct xz_dec_lzma2* s) { - uint32_t pos_state; - - /* - * If the dictionary was reached during the previous call, try to - * finish the possibly pending repeat in the dictionary. - */ - if (dict_has_space(&s->dict) && s->lzma.len > 0) - dict_repeat(&s->dict, &s->lzma.len, s->lzma.rep0); - - /* - * Decode more LZMA symbols. One iteration may consume up to - * LZMA_IN_REQUIRED - 1 bytes. - */ - while (dict_has_space(&s->dict) && !rc_limit_exceeded(&s->rc)) { - pos_state = s->dict.pos & s->lzma.pos_mask; - - if (!rc_bit(&s->rc, &s->lzma.is_match[ - s->lzma.state][pos_state])) { - lzma_literal(s); - } else { - if (rc_bit(&s->rc, &s->lzma.is_rep[s->lzma.state])) - lzma_rep_match(s, pos_state); - else - lzma_match(s, pos_state); - - if (!dict_repeat(&s->dict, &s->lzma.len, s->lzma.rep0)) - return false; - } - } - - /* - * Having the range decoder always normalized when we are outside - * this function makes it easier to correctly handle end of the chunk. - */ - rc_normalize(&s->rc); - - return true; + uint32_t pos_state; + + /* + * If the dictionary was reached during the previous call, try to + * finish the possibly pending repeat in the dictionary. + */ + if (dict_has_space(&s->dict) && s->lzma.len > 0) + dict_repeat(&s->dict, &s->lzma.len, s->lzma.rep0); + + /* + * Decode more LZMA symbols. One iteration may consume up to + * LZMA_IN_REQUIRED - 1 bytes. + */ + while (dict_has_space(&s->dict) && !rc_limit_exceeded(&s->rc)) + { + pos_state = s->dict.pos & s->lzma.pos_mask; + + if (!rc_bit(&s->rc, &s->lzma.is_match[s->lzma.state][pos_state])) + { + lzma_literal(s); + } + else + { + if (rc_bit(&s->rc, &s->lzma.is_rep[s->lzma.state])) + lzma_rep_match(s, pos_state); + else + lzma_match(s, pos_state); + + if (!dict_repeat(&s->dict, &s->lzma.len, s->lzma.rep0)) + return false; + } + } + + /* + * Having the range decoder always normalized when we are outside + * this function makes it easier to correctly handle end of the chunk. + */ + rc_normalize(&s->rc); + + return true; } /* * Reset the LZMA decoder and range decoder state. Dictionary is nore reset * here, because LZMA state may be reset without resetting the dictionary. */ -static void lzma_reset(struct xz_dec_lzma2 *s) +static void lzma_reset(struct xz_dec_lzma2* s) { - uint16_t *probs; - size_t i; - - s->lzma.state = STATE_LIT_LIT; - s->lzma.rep0 = 0; - s->lzma.rep1 = 0; - s->lzma.rep2 = 0; - s->lzma.rep3 = 0; - - /* - * All probabilities are initialized to the same value. This hack - * makes the code smaller by avoiding a separate loop for each - * probability array. - * - * This could be optimized so that only that part of literal - * probabilities that are actually required. In the common case - * we would write 12 KiB less. - */ - probs = s->lzma.is_match[0]; - for (i = 0; i < PROBS_TOTAL; ++i) - probs[i] = RC_BIT_MODEL_TOTAL / 2; - - rc_reset(&s->rc); + uint16_t* probs; + size_t i; + + s->lzma.state = STATE_LIT_LIT; + s->lzma.rep0 = 0; + s->lzma.rep1 = 0; + s->lzma.rep2 = 0; + s->lzma.rep3 = 0; + + /* + * All probabilities are initialized to the same value. This hack + * makes the code smaller by avoiding a separate loop for each + * probability array. + * + * This could be optimized so that only that part of literal + * probabilities that are actually required. In the common case + * we would write 12 KiB less. + */ + probs = s->lzma.is_match[0]; + for (i = 0; i < PROBS_TOTAL; ++i) + probs[i] = RC_BIT_MODEL_TOTAL / 2; + + rc_reset(&s->rc); } /* @@ -830,35 +872,37 @@ static void lzma_reset(struct xz_dec_lzma2 *s) * from the decoded lp and pb values. On success, the LZMA decoder state is * reset and true is returned. */ -static bool lzma_props(struct xz_dec_lzma2 *s, uint8_t props) +static bool lzma_props(struct xz_dec_lzma2* s, uint8_t props) { - if (props > (4 * 5 + 4) * 9 + 8) - return false; + if (props > (4 * 5 + 4) * 9 + 8) + return false; - s->lzma.pos_mask = 0; - while (props >= 9 * 5) { - props -= 9 * 5; - ++s->lzma.pos_mask; - } + s->lzma.pos_mask = 0; + while (props >= 9 * 5) + { + props -= 9 * 5; + ++s->lzma.pos_mask; + } - s->lzma.pos_mask = (1 << s->lzma.pos_mask) - 1; + s->lzma.pos_mask = (1 << s->lzma.pos_mask) - 1; - s->lzma.literal_pos_mask = 0; - while (props >= 9) { - props -= 9; - ++s->lzma.literal_pos_mask; - } + s->lzma.literal_pos_mask = 0; + while (props >= 9) + { + props -= 9; + ++s->lzma.literal_pos_mask; + } - s->lzma.lc = props; + s->lzma.lc = props; - if (s->lzma.lc + s->lzma.literal_pos_mask > 4) - return false; + if (s->lzma.lc + s->lzma.literal_pos_mask > 4) + return false; - s->lzma.literal_pos_mask = (1 << s->lzma.literal_pos_mask) - 1; + s->lzma.literal_pos_mask = (1 << s->lzma.literal_pos_mask) - 1; - lzma_reset(s); + lzma_reset(s); - return true; + return true; } /********* @@ -877,329 +921,342 @@ static bool lzma_props(struct xz_dec_lzma2 *s, uint8_t props) * function. We decode a few bytes from the temporary buffer so that we can * continue decoding from the caller-supplied input buffer again. */ -static bool lzma2_lzma(struct xz_dec_lzma2 *s, struct xz_buf *b) +static bool lzma2_lzma(struct xz_dec_lzma2* s, struct xz_buf* b) { - size_t in_avail; - uint32_t tmp; - - in_avail = b->in_size - b->in_pos; - if (s->temp.size > 0 || s->lzma2.compressed == 0) { - tmp = 2 * LZMA_IN_REQUIRED - s->temp.size; - if (tmp > s->lzma2.compressed - s->temp.size) - tmp = s->lzma2.compressed - s->temp.size; - if (tmp > in_avail) - tmp = in_avail; - - memcpy(s->temp.buf + s->temp.size, b->in + b->in_pos, tmp); - - if (s->temp.size + tmp == s->lzma2.compressed) { - memzero(s->temp.buf + s->temp.size + tmp, - sizeof(s->temp.buf) - - s->temp.size - tmp); - s->rc.in_limit = s->temp.size + tmp; - } else if (s->temp.size + tmp < LZMA_IN_REQUIRED) { - s->temp.size += tmp; - b->in_pos += tmp; - return true; - } else { - s->rc.in_limit = s->temp.size + tmp - LZMA_IN_REQUIRED; - } - - s->rc.in = s->temp.buf; - s->rc.in_pos = 0; - - if (!lzma_main(s) || s->rc.in_pos > s->temp.size + tmp) - return false; - - s->lzma2.compressed -= s->rc.in_pos; - - if (s->rc.in_pos < s->temp.size) { - s->temp.size -= s->rc.in_pos; - memmove(s->temp.buf, s->temp.buf + s->rc.in_pos, - s->temp.size); - return true; - } - - b->in_pos += s->rc.in_pos - s->temp.size; - s->temp.size = 0; - } - - in_avail = b->in_size - b->in_pos; - if (in_avail >= LZMA_IN_REQUIRED) { - s->rc.in = b->in; - s->rc.in_pos = b->in_pos; - - if (in_avail >= s->lzma2.compressed + LZMA_IN_REQUIRED) - s->rc.in_limit = b->in_pos + s->lzma2.compressed; - else - s->rc.in_limit = b->in_size - LZMA_IN_REQUIRED; - - if (!lzma_main(s)) - return false; - - in_avail = s->rc.in_pos - b->in_pos; - if (in_avail > s->lzma2.compressed) - return false; - - s->lzma2.compressed -= in_avail; - b->in_pos = s->rc.in_pos; - } - - in_avail = b->in_size - b->in_pos; - if (in_avail < LZMA_IN_REQUIRED) { - if (in_avail > s->lzma2.compressed) - in_avail = s->lzma2.compressed; - - memcpy(s->temp.buf, b->in + b->in_pos, in_avail); - s->temp.size = in_avail; - b->in_pos += in_avail; - } - - return true; + size_t in_avail; + uint32_t tmp; + + in_avail = b->in_size - b->in_pos; + if (s->temp.size > 0 || s->lzma2.compressed == 0) + { + tmp = 2 * LZMA_IN_REQUIRED - s->temp.size; + if (tmp > s->lzma2.compressed - s->temp.size) + tmp = s->lzma2.compressed - s->temp.size; + if (tmp > in_avail) + tmp = in_avail; + + memcpy(s->temp.buf + s->temp.size, b->in + b->in_pos, tmp); + + if (s->temp.size + tmp == s->lzma2.compressed) + { + memzero(s->temp.buf + s->temp.size + tmp, sizeof(s->temp.buf) - s->temp.size - tmp); + s->rc.in_limit = s->temp.size + tmp; + } + else if (s->temp.size + tmp < LZMA_IN_REQUIRED) + { + s->temp.size += tmp; + b->in_pos += tmp; + return true; + } + else + { + s->rc.in_limit = s->temp.size + tmp - LZMA_IN_REQUIRED; + } + + s->rc.in = s->temp.buf; + s->rc.in_pos = 0; + + if (!lzma_main(s) || s->rc.in_pos > s->temp.size + tmp) + return false; + + s->lzma2.compressed -= s->rc.in_pos; + + if (s->rc.in_pos < s->temp.size) + { + s->temp.size -= s->rc.in_pos; + memmove(s->temp.buf, s->temp.buf + s->rc.in_pos, s->temp.size); + return true; + } + + b->in_pos += s->rc.in_pos - s->temp.size; + s->temp.size = 0; + } + + in_avail = b->in_size - b->in_pos; + if (in_avail >= LZMA_IN_REQUIRED) + { + s->rc.in = b->in; + s->rc.in_pos = b->in_pos; + + if (in_avail >= s->lzma2.compressed + LZMA_IN_REQUIRED) + s->rc.in_limit = b->in_pos + s->lzma2.compressed; + else + s->rc.in_limit = b->in_size - LZMA_IN_REQUIRED; + + if (!lzma_main(s)) + return false; + + in_avail = s->rc.in_pos - b->in_pos; + if (in_avail > s->lzma2.compressed) + return false; + + s->lzma2.compressed -= in_avail; + b->in_pos = s->rc.in_pos; + } + + in_avail = b->in_size - b->in_pos; + if (in_avail < LZMA_IN_REQUIRED) + { + if (in_avail > s->lzma2.compressed) + in_avail = s->lzma2.compressed; + + memcpy(s->temp.buf, b->in + b->in_pos, in_avail); + s->temp.size = in_avail; + b->in_pos += in_avail; + } + + return true; } /* * Take care of the LZMA2 control layer, and forward the job of actual LZMA * decoding or copying of uncompressed chunks to other functions. */ -XZ_EXTERN enum xz_ret xz_dec_lzma2_run(struct xz_dec_lzma2 *s, - struct xz_buf *b) +XZ_EXTERN enum xz_ret xz_dec_lzma2_run(struct xz_dec_lzma2* s, struct xz_buf* b) { - uint32_t tmp; - - while (b->in_pos < b->in_size || s->lzma2.sequence == SEQ_LZMA_RUN) { - switch (s->lzma2.sequence) { - case SEQ_CONTROL: - /* - * LZMA2 control byte - * - * Exact values: - * 0x00 End marker - * 0x01 Dictionary reset followed by - * an uncompressed chunk - * 0x02 Uncompressed chunk (no dictionary reset) - * - * Highest three bits (s->control & 0xE0): - * 0xE0 Dictionary reset, new properties and state - * reset, followed by LZMA compressed chunk - * 0xC0 New properties and state reset, followed - * by LZMA compressed chunk (no dictionary - * reset) - * 0xA0 State reset using old properties, - * followed by LZMA compressed chunk (no - * dictionary reset) - * 0x80 LZMA chunk (no dictionary or state reset) - * - * For LZMA compressed chunks, the lowest five bits - * (s->control & 1F) are the highest bits of the - * uncompressed size (bits 16-20). - * - * A new LZMA2 stream must begin with a dictionary - * reset. The first LZMA chunk must set new - * properties and reset the LZMA state. - * - * Values that don't match anything described above - * are invalid and we return XZ_DATA_ERROR. - */ - tmp = b->in[b->in_pos++]; - - if (tmp == 0x00) - return XZ_STREAM_END; - - if (tmp >= 0xE0 || tmp == 0x01) { - s->lzma2.need_props = true; - s->lzma2.need_dict_reset = false; - dict_reset(&s->dict, b); - } else if (s->lzma2.need_dict_reset) { - return XZ_DATA_ERROR; - } - - if (tmp >= 0x80) { - s->lzma2.uncompressed = (tmp & 0x1F) << 16; - s->lzma2.sequence = SEQ_UNCOMPRESSED_1; - - if (tmp >= 0xC0) { - /* - * When there are new properties, - * state reset is done at - * SEQ_PROPERTIES. - */ - s->lzma2.need_props = false; - s->lzma2.next_sequence - = SEQ_PROPERTIES; - - } else if (s->lzma2.need_props) { - return XZ_DATA_ERROR; - - } else { - s->lzma2.next_sequence - = SEQ_LZMA_PREPARE; - if (tmp >= 0xA0) - lzma_reset(s); - } - } else { - if (tmp > 0x02) - return XZ_DATA_ERROR; - - s->lzma2.sequence = SEQ_COMPRESSED_0; - s->lzma2.next_sequence = SEQ_COPY; - } - - break; - - case SEQ_UNCOMPRESSED_1: - s->lzma2.uncompressed - += (uint32_t)b->in[b->in_pos++] << 8; - s->lzma2.sequence = SEQ_UNCOMPRESSED_2; - break; - - case SEQ_UNCOMPRESSED_2: - s->lzma2.uncompressed - += (uint32_t)b->in[b->in_pos++] + 1; - s->lzma2.sequence = SEQ_COMPRESSED_0; - break; - - case SEQ_COMPRESSED_0: - s->lzma2.compressed - = (uint32_t)b->in[b->in_pos++] << 8; - s->lzma2.sequence = SEQ_COMPRESSED_1; - break; - - case SEQ_COMPRESSED_1: - s->lzma2.compressed - += (uint32_t)b->in[b->in_pos++] + 1; - s->lzma2.sequence = s->lzma2.next_sequence; - break; - - case SEQ_PROPERTIES: - if (!lzma_props(s, b->in[b->in_pos++])) - return XZ_DATA_ERROR; - - s->lzma2.sequence = SEQ_LZMA_PREPARE; - - case SEQ_LZMA_PREPARE: - if (s->lzma2.compressed < RC_INIT_BYTES) - return XZ_DATA_ERROR; - - if (!rc_read_init(&s->rc, b)) - return XZ_OK; - - s->lzma2.compressed -= RC_INIT_BYTES; - s->lzma2.sequence = SEQ_LZMA_RUN; - - case SEQ_LZMA_RUN: - /* - * Set dictionary limit to indicate how much we want - * to be encoded at maximum. Decode new data into the - * dictionary. Flush the new data from dictionary to - * b->out. Check if we finished decoding this chunk. - * In case the dictionary got full but we didn't fill - * the output buffer yet, we may run this loop - * multiple times without changing s->lzma2.sequence. - */ - dict_limit(&s->dict, min_t(size_t, - b->out_size - b->out_pos, - s->lzma2.uncompressed)); - if (!lzma2_lzma(s, b)) - return XZ_DATA_ERROR; - - s->lzma2.uncompressed -= dict_flush(&s->dict, b); - - if (s->lzma2.uncompressed == 0) { - if (s->lzma2.compressed > 0 || s->lzma.len > 0 - || !rc_is_finished(&s->rc)) - return XZ_DATA_ERROR; - - rc_reset(&s->rc); - s->lzma2.sequence = SEQ_CONTROL; - - } else if (b->out_pos == b->out_size - || (b->in_pos == b->in_size - && s->temp.size - < s->lzma2.compressed)) { - return XZ_OK; - } - - break; - - case SEQ_COPY: - dict_uncompressed(&s->dict, b, &s->lzma2.compressed); - if (s->lzma2.compressed > 0) - return XZ_OK; - - s->lzma2.sequence = SEQ_CONTROL; - break; - } - } - - return XZ_OK; + uint32_t tmp; + + while (b->in_pos < b->in_size || s->lzma2.sequence == SEQ_LZMA_RUN) + { + switch (s->lzma2.sequence) + { + case SEQ_CONTROL: + /* + * LZMA2 control byte + * + * Exact values: + * 0x00 End marker + * 0x01 Dictionary reset followed by + * an uncompressed chunk + * 0x02 Uncompressed chunk (no dictionary reset) + * + * Highest three bits (s->control & 0xE0): + * 0xE0 Dictionary reset, new properties and state + * reset, followed by LZMA compressed chunk + * 0xC0 New properties and state reset, followed + * by LZMA compressed chunk (no dictionary + * reset) + * 0xA0 State reset using old properties, + * followed by LZMA compressed chunk (no + * dictionary reset) + * 0x80 LZMA chunk (no dictionary or state reset) + * + * For LZMA compressed chunks, the lowest five bits + * (s->control & 1F) are the highest bits of the + * uncompressed size (bits 16-20). + * + * A new LZMA2 stream must begin with a dictionary + * reset. The first LZMA chunk must set new + * properties and reset the LZMA state. + * + * Values that don't match anything described above + * are invalid and we return XZ_DATA_ERROR. + */ + tmp = b->in[b->in_pos++]; + + if (tmp == 0x00) + return XZ_STREAM_END; + + if (tmp >= 0xE0 || tmp == 0x01) + { + s->lzma2.need_props = true; + s->lzma2.need_dict_reset = false; + dict_reset(&s->dict, b); + } + else if (s->lzma2.need_dict_reset) + { + return XZ_DATA_ERROR; + } + + if (tmp >= 0x80) + { + s->lzma2.uncompressed = (tmp & 0x1F) << 16; + s->lzma2.sequence = SEQ_UNCOMPRESSED_1; + + if (tmp >= 0xC0) + { + /* + * When there are new properties, + * state reset is done at + * SEQ_PROPERTIES. + */ + s->lzma2.need_props = false; + s->lzma2.next_sequence = SEQ_PROPERTIES; + } + else if (s->lzma2.need_props) + { + return XZ_DATA_ERROR; + } + else + { + s->lzma2.next_sequence = SEQ_LZMA_PREPARE; + if (tmp >= 0xA0) + lzma_reset(s); + } + } + else + { + if (tmp > 0x02) + return XZ_DATA_ERROR; + + s->lzma2.sequence = SEQ_COMPRESSED_0; + s->lzma2.next_sequence = SEQ_COPY; + } + + break; + + case SEQ_UNCOMPRESSED_1: + s->lzma2.uncompressed += (uint32_t)b->in[b->in_pos++] << 8; + s->lzma2.sequence = SEQ_UNCOMPRESSED_2; + break; + + case SEQ_UNCOMPRESSED_2: + s->lzma2.uncompressed += (uint32_t)b->in[b->in_pos++] + 1; + s->lzma2.sequence = SEQ_COMPRESSED_0; + break; + + case SEQ_COMPRESSED_0: + s->lzma2.compressed = (uint32_t)b->in[b->in_pos++] << 8; + s->lzma2.sequence = SEQ_COMPRESSED_1; + break; + + case SEQ_COMPRESSED_1: + s->lzma2.compressed += (uint32_t)b->in[b->in_pos++] + 1; + s->lzma2.sequence = s->lzma2.next_sequence; + break; + + case SEQ_PROPERTIES: + if (!lzma_props(s, b->in[b->in_pos++])) + return XZ_DATA_ERROR; + + s->lzma2.sequence = SEQ_LZMA_PREPARE; + + case SEQ_LZMA_PREPARE: + if (s->lzma2.compressed < RC_INIT_BYTES) + return XZ_DATA_ERROR; + + if (!rc_read_init(&s->rc, b)) + return XZ_OK; + + s->lzma2.compressed -= RC_INIT_BYTES; + s->lzma2.sequence = SEQ_LZMA_RUN; + + case SEQ_LZMA_RUN: + /* + * Set dictionary limit to indicate how much we want + * to be encoded at maximum. Decode new data into the + * dictionary. Flush the new data from dictionary to + * b->out. Check if we finished decoding this chunk. + * In case the dictionary got full but we didn't fill + * the output buffer yet, we may run this loop + * multiple times without changing s->lzma2.sequence. + */ + dict_limit(&s->dict, min_t(size_t, b->out_size - b->out_pos, s->lzma2.uncompressed)); + if (!lzma2_lzma(s, b)) + return XZ_DATA_ERROR; + + s->lzma2.uncompressed -= dict_flush(&s->dict, b); + + if (s->lzma2.uncompressed == 0) + { + if (s->lzma2.compressed > 0 || s->lzma.len > 0 || !rc_is_finished(&s->rc)) + return XZ_DATA_ERROR; + + rc_reset(&s->rc); + s->lzma2.sequence = SEQ_CONTROL; + } + else if (b->out_pos == b->out_size || (b->in_pos == b->in_size && s->temp.size < s->lzma2.compressed)) + { + return XZ_OK; + } + + break; + + case SEQ_COPY: + dict_uncompressed(&s->dict, b, &s->lzma2.compressed); + if (s->lzma2.compressed > 0) + return XZ_OK; + + s->lzma2.sequence = SEQ_CONTROL; + break; + } + } + + return XZ_OK; } -XZ_EXTERN struct xz_dec_lzma2 *xz_dec_lzma2_create(enum xz_mode mode, - uint32_t dict_max) +XZ_EXTERN struct xz_dec_lzma2* xz_dec_lzma2_create(enum xz_mode mode, uint32_t dict_max) { - struct xz_dec_lzma2 *s = kmalloc(sizeof(*s), GFP_KERNEL); - if (s == NULL) - return NULL; - - s->dict.mode = mode; - s->dict.size_max = dict_max; - - if (DEC_IS_PREALLOC(mode)) { - s->dict.buf = vmalloc(dict_max); - if (s->dict.buf == NULL) { - kfree(s); - return NULL; - } - } else if (DEC_IS_DYNALLOC(mode)) { - s->dict.buf = NULL; - s->dict.allocated = 0; - } - - return s; + struct xz_dec_lzma2* s = kmalloc(sizeof(*s), GFP_KERNEL); + if (s == NULL) + return NULL; + + s->dict.mode = mode; + s->dict.size_max = dict_max; + + if (DEC_IS_PREALLOC(mode)) + { + s->dict.buf = vmalloc(dict_max); + if (s->dict.buf == NULL) + { + kfree(s); + return NULL; + } + } + else if (DEC_IS_DYNALLOC(mode)) + { + s->dict.buf = NULL; + s->dict.allocated = 0; + } + + return s; } -XZ_EXTERN enum xz_ret xz_dec_lzma2_reset(struct xz_dec_lzma2 *s, uint8_t props) +XZ_EXTERN enum xz_ret xz_dec_lzma2_reset(struct xz_dec_lzma2* s, uint8_t props) { - /* This limits dictionary size to 3 GiB to keep parsing simpler. */ - if (props > 39) - return XZ_OPTIONS_ERROR; - - s->dict.size = 2 + (props & 1); - s->dict.size <<= (props >> 1) + 11; - - if (DEC_IS_MULTI(s->dict.mode)) { - if (s->dict.size > s->dict.size_max) - return XZ_MEMLIMIT_ERROR; - - s->dict.end = s->dict.size; - - if (DEC_IS_DYNALLOC(s->dict.mode)) { - if (s->dict.allocated < s->dict.size) { - vfree(s->dict.buf); - s->dict.buf = vmalloc(s->dict.size); - if (s->dict.buf == NULL) { - s->dict.allocated = 0; - return XZ_MEM_ERROR; - } - } - } - } - - s->lzma.len = 0; - - s->lzma2.sequence = SEQ_CONTROL; - s->lzma2.need_dict_reset = true; - - s->temp.size = 0; - - return XZ_OK; + /* This limits dictionary size to 3 GiB to keep parsing simpler. */ + if (props > 39) + return XZ_OPTIONS_ERROR; + + s->dict.size = 2 + (props & 1); + s->dict.size <<= (props >> 1) + 11; + + if (DEC_IS_MULTI(s->dict.mode)) + { + if (s->dict.size > s->dict.size_max) + return XZ_MEMLIMIT_ERROR; + + s->dict.end = s->dict.size; + + if (DEC_IS_DYNALLOC(s->dict.mode)) + { + if (s->dict.allocated < s->dict.size) + { + vfree(s->dict.buf); + s->dict.buf = vmalloc(s->dict.size); + if (s->dict.buf == NULL) + { + s->dict.allocated = 0; + return XZ_MEM_ERROR; + } + } + } + } + + s->lzma.len = 0; + + s->lzma2.sequence = SEQ_CONTROL; + s->lzma2.need_dict_reset = true; + + s->temp.size = 0; + + return XZ_OK; } -XZ_EXTERN void xz_dec_lzma2_end(struct xz_dec_lzma2 *s) +XZ_EXTERN void xz_dec_lzma2_end(struct xz_dec_lzma2* s) { - if (DEC_IS_MULTI(s->dict.mode)) - vfree(s->dict.buf); + if (DEC_IS_MULTI(s->dict.mode)) + vfree(s->dict.buf); - kfree(s); + kfree(s); } diff --git a/ext_libs/minixz/xz_dec_stream.c b/ext_libs/minixz/xz_dec_stream.c index 037b52c8..a81a39b5 100644 --- a/ext_libs/minixz/xz_dec_stream.c +++ b/ext_libs/minixz/xz_dec_stream.c @@ -45,141 +45,142 @@ #include "xz_stream.h" /* Hash used to validate the Index field */ -struct xz_dec_hash { - vli_type unpadded; - vli_type uncompressed; - uint32_t crc32; +struct xz_dec_hash +{ + vli_type unpadded; + vli_type uncompressed; + uint32_t crc32; }; -struct xz_dec { - /* Position in dec_main() */ - enum { - SEQ_STREAM_HEADER, - SEQ_BLOCK_START, - SEQ_BLOCK_HEADER, - SEQ_BLOCK_UNCOMPRESS, - SEQ_BLOCK_PADDING, - SEQ_BLOCK_CHECK, - SEQ_INDEX, - SEQ_INDEX_PADDING, - SEQ_INDEX_CRC32, - SEQ_STREAM_FOOTER - } sequence; - - /* Position in variable-length integers and Check fields */ - uint32_t pos; - - /* Variable-length integer decoded by dec_vli() */ - vli_type vli; - - /* Saved in_pos and out_pos */ - size_t in_start; - size_t out_start; - - /* CRC32 value in Block or Index */ - uint32_t crc32; - - /* Type of the integrity check calculated from uncompressed data */ - enum xz_check check_type; - - /* Operation mode */ - enum xz_mode mode; - - /* - * True if the next call to xz_dec_run() is allowed to return - * XZ_BUF_ERROR. - */ - bool allow_buf_error; - - /* Information stored in Block Header */ - struct { - /* - * Value stored in the Compressed Size field, or - * VLI_UNKNOWN if Compressed Size is not present. - */ - vli_type compressed; - - /* - * Value stored in the Uncompressed Size field, or - * VLI_UNKNOWN if Uncompressed Size is not present. - */ - vli_type uncompressed; - - /* Size of the Block Header field */ - uint32_t size; - } block_header; - - /* Information collected when decoding Blocks */ - struct { - /* Observed compressed size of the current Block */ - vli_type compressed; - - /* Observed uncompressed size of the current Block */ - vli_type uncompressed; - - /* Number of Blocks decoded so far */ - vli_type count; - - /* - * Hash calculated from the Block sizes. This is used to - * validate the Index field. - */ - struct xz_dec_hash hash; - } block; - - /* Variables needed when verifying the Index field */ - struct { - /* Position in dec_index() */ - enum { - SEQ_INDEX_COUNT, - SEQ_INDEX_UNPADDED, - SEQ_INDEX_UNCOMPRESSED - } sequence; - - /* Size of the Index in bytes */ - vli_type size; - - /* Number of Records (matches block.count in valid files) */ - vli_type count; - - /* - * Hash calculated from the Records (matches block.hash in - * valid files). - */ - struct xz_dec_hash hash; - } index; - - /* - * Temporary buffer needed to hold Stream Header, Block Header, - * and Stream Footer. The Block Header is the biggest (1 KiB) - * so we reserve space according to that. buf[] has to be aligned - * to a multiple of four bytes; the size_t variables before it - * should guarantee this. - */ - struct { - size_t pos; - size_t size; - uint8_t buf[1024]; - } temp; - - struct xz_dec_lzma2 *lzma2; +struct xz_dec +{ + /* Position in dec_main() */ + enum + { + SEQ_STREAM_HEADER, + SEQ_BLOCK_START, + SEQ_BLOCK_HEADER, + SEQ_BLOCK_UNCOMPRESS, + SEQ_BLOCK_PADDING, + SEQ_BLOCK_CHECK, + SEQ_INDEX, + SEQ_INDEX_PADDING, + SEQ_INDEX_CRC32, + SEQ_STREAM_FOOTER + } sequence; + + /* Position in variable-length integers and Check fields */ + uint32_t pos; + + /* Variable-length integer decoded by dec_vli() */ + vli_type vli; + + /* Saved in_pos and out_pos */ + size_t in_start; + size_t out_start; + + /* CRC32 value in Block or Index */ + uint32_t crc32; + + /* Type of the integrity check calculated from uncompressed data */ + enum xz_check check_type; + + /* Operation mode */ + enum xz_mode mode; + + /* + * True if the next call to xz_dec_run() is allowed to return + * XZ_BUF_ERROR. + */ + bool allow_buf_error; + + /* Information stored in Block Header */ + struct + { + /* + * Value stored in the Compressed Size field, or + * VLI_UNKNOWN if Compressed Size is not present. + */ + vli_type compressed; + + /* + * Value stored in the Uncompressed Size field, or + * VLI_UNKNOWN if Uncompressed Size is not present. + */ + vli_type uncompressed; + + /* Size of the Block Header field */ + uint32_t size; + } block_header; + + /* Information collected when decoding Blocks */ + struct + { + /* Observed compressed size of the current Block */ + vli_type compressed; + + /* Observed uncompressed size of the current Block */ + vli_type uncompressed; + + /* Number of Blocks decoded so far */ + vli_type count; + + /* + * Hash calculated from the Block sizes. This is used to + * validate the Index field. + */ + struct xz_dec_hash hash; + } block; + + /* Variables needed when verifying the Index field */ + struct + { + /* Position in dec_index() */ + enum + { + SEQ_INDEX_COUNT, + SEQ_INDEX_UNPADDED, + SEQ_INDEX_UNCOMPRESSED + } sequence; + + /* Size of the Index in bytes */ + vli_type size; + + /* Number of Records (matches block.count in valid files) */ + vli_type count; + + /* + * Hash calculated from the Records (matches block.hash in + * valid files). + */ + struct xz_dec_hash hash; + } index; + + /* + * Temporary buffer needed to hold Stream Header, Block Header, + * and Stream Footer. The Block Header is the biggest (1 KiB) + * so we reserve space according to that. buf[] has to be aligned + * to a multiple of four bytes; the size_t variables before it + * should guarantee this. + */ + struct + { + size_t pos; + size_t size; + uint8_t buf[1024]; + } temp; + + struct xz_dec_lzma2* lzma2; #ifdef XZ_DEC_BCJ - struct xz_dec_bcj *bcj; - bool bcj_active; + struct xz_dec_bcj* bcj; + bool bcj_active; #endif }; #ifdef XZ_DEC_ANY_CHECK /* Sizes of the Check field with different Check IDs */ -static const uint8_t check_sizes[16] = { - 0, - 4, 4, 4, - 8, 8, 8, - 16, 16, 16, - 32, 32, 32, - 64, 64, 64 -}; +static const uint8_t check_sizes[16] = {0, 4, 4, 4, 8, 8, 8, 16, 16, 16, 32, 32, 32, 64, 64, 64}; #endif /* @@ -188,53 +189,54 @@ static const uint8_t check_sizes[16] = { * to copy into s->temp.buf. Return true once s->temp.pos has reached * s->temp.size. */ -static bool fill_temp(struct xz_dec *s, struct xz_buf *b) +static bool fill_temp(struct xz_dec* s, struct xz_buf* b) { - size_t copy_size = min_t(size_t, - b->in_size - b->in_pos, s->temp.size - s->temp.pos); + size_t copy_size = min_t(size_t, b->in_size - b->in_pos, s->temp.size - s->temp.pos); - memcpy(s->temp.buf + s->temp.pos, b->in + b->in_pos, copy_size); - b->in_pos += copy_size; - s->temp.pos += copy_size; + memcpy(s->temp.buf + s->temp.pos, b->in + b->in_pos, copy_size); + b->in_pos += copy_size; + s->temp.pos += copy_size; - if (s->temp.pos == s->temp.size) { - s->temp.pos = 0; - return true; - } + if (s->temp.pos == s->temp.size) + { + s->temp.pos = 0; + return true; + } - return false; + return false; } /* Decode a variable-length integer (little-endian base-128 encoding) */ -static enum xz_ret dec_vli(struct xz_dec *s, const uint8_t *in, - size_t *in_pos, size_t in_size) +static enum xz_ret dec_vli(struct xz_dec* s, const uint8_t* in, size_t* in_pos, size_t in_size) { - uint8_t byte; + uint8_t byte; - if (s->pos == 0) - s->vli = 0; + if (s->pos == 0) + s->vli = 0; - while (*in_pos < in_size) { - byte = in[*in_pos]; - ++*in_pos; + while (*in_pos < in_size) + { + byte = in[*in_pos]; + ++*in_pos; - s->vli |= (vli_type)(byte & 0x7F) << s->pos; + s->vli |= (vli_type)(byte & 0x7F) << s->pos; - if ((byte & 0x80) == 0) { - /* Don't allow non-minimal encodings. */ - if (byte == 0 && s->pos != 0) - return XZ_DATA_ERROR; + if ((byte & 0x80) == 0) + { + /* Don't allow non-minimal encodings. */ + if (byte == 0 && s->pos != 0) + return XZ_DATA_ERROR; - s->pos = 0; - return XZ_STREAM_END; - } + s->pos = 0; + return XZ_STREAM_END; + } - s->pos += 7; - if (s->pos == 7 * VLI_BYTES_MAX) - return XZ_DATA_ERROR; - } + s->pos += 7; + if (s->pos == 7 * VLI_BYTES_MAX) + return XZ_DATA_ERROR; + } - return XZ_OK; + return XZ_OK; } /* @@ -249,74 +251,65 @@ static enum xz_ret dec_vli(struct xz_dec *s, const uint8_t *in, * the sizes possibly stored in the Block Header. Update the hash and * Block count, which are later used to validate the Index field. */ -static enum xz_ret dec_block(struct xz_dec *s, struct xz_buf *b) +static enum xz_ret dec_block(struct xz_dec* s, struct xz_buf* b) { - enum xz_ret ret; + enum xz_ret ret; - s->in_start = b->in_pos; - s->out_start = b->out_pos; + s->in_start = b->in_pos; + s->out_start = b->out_pos; #ifdef XZ_DEC_BCJ - if (s->bcj_active) - ret = xz_dec_bcj_run(s->bcj, s->lzma2, b); - else + if (s->bcj_active) + ret = xz_dec_bcj_run(s->bcj, s->lzma2, b); + else #endif - ret = xz_dec_lzma2_run(s->lzma2, b); - - s->block.compressed += b->in_pos - s->in_start; - s->block.uncompressed += b->out_pos - s->out_start; - - /* - * There is no need to separately check for VLI_UNKNOWN, since - * the observed sizes are always smaller than VLI_UNKNOWN. - */ - if (s->block.compressed > s->block_header.compressed - || s->block.uncompressed - > s->block_header.uncompressed) - return XZ_DATA_ERROR; - - if (s->check_type == XZ_CHECK_CRC32) - s->crc32 = xz_crc32(b->out + s->out_start, - b->out_pos - s->out_start, s->crc32); - - if (ret == XZ_STREAM_END) { - if (s->block_header.compressed != VLI_UNKNOWN - && s->block_header.compressed - != s->block.compressed) - return XZ_DATA_ERROR; - - if (s->block_header.uncompressed != VLI_UNKNOWN - && s->block_header.uncompressed - != s->block.uncompressed) - return XZ_DATA_ERROR; - - s->block.hash.unpadded += s->block_header.size - + s->block.compressed; + ret = xz_dec_lzma2_run(s->lzma2, b); + + s->block.compressed += b->in_pos - s->in_start; + s->block.uncompressed += b->out_pos - s->out_start; + + /* + * There is no need to separately check for VLI_UNKNOWN, since + * the observed sizes are always smaller than VLI_UNKNOWN. + */ + if (s->block.compressed > s->block_header.compressed || s->block.uncompressed > s->block_header.uncompressed) + return XZ_DATA_ERROR; + + if (s->check_type == XZ_CHECK_CRC32) + s->crc32 = xz_crc32(b->out + s->out_start, b->out_pos - s->out_start, s->crc32); + + if (ret == XZ_STREAM_END) + { + if (s->block_header.compressed != VLI_UNKNOWN && s->block_header.compressed != s->block.compressed) + return XZ_DATA_ERROR; + + if (s->block_header.uncompressed != VLI_UNKNOWN && s->block_header.uncompressed != s->block.uncompressed) + return XZ_DATA_ERROR; + + s->block.hash.unpadded += s->block_header.size + s->block.compressed; #ifdef XZ_DEC_ANY_CHECK - s->block.hash.unpadded += check_sizes[s->check_type]; + s->block.hash.unpadded += check_sizes[s->check_type]; #else - if (s->check_type == XZ_CHECK_CRC32) - s->block.hash.unpadded += 4; + if (s->check_type == XZ_CHECK_CRC32) + s->block.hash.unpadded += 4; #endif - s->block.hash.uncompressed += s->block.uncompressed; - s->block.hash.crc32 = xz_crc32( - (const uint8_t *)&s->block.hash, - sizeof(s->block.hash), s->block.hash.crc32); + s->block.hash.uncompressed += s->block.uncompressed; + s->block.hash.crc32 = xz_crc32((const uint8_t*)&s->block.hash, sizeof(s->block.hash), s->block.hash.crc32); - ++s->block.count; - } + ++s->block.count; + } - return ret; + return ret; } /* Update the Index size and the CRC32 value. */ -static void index_update(struct xz_dec *s, const struct xz_buf *b) +static void index_update(struct xz_dec* s, const struct xz_buf* b) { - size_t in_used = b->in_pos - s->in_start; - s->index.size += in_used; - s->crc32 = xz_crc32(b->in + s->in_start, in_used, s->crc32); + size_t in_used = b->in_pos - s->in_start; + s->index.size += in_used; + s->crc32 = xz_crc32(b->in + s->in_start, in_used, s->crc32); } /* @@ -327,73 +320,75 @@ static void index_update(struct xz_dec *s, const struct xz_buf *b) * This can return XZ_OK (more input needed), XZ_STREAM_END (everything * successfully decoded), or XZ_DATA_ERROR (input is corrupt). */ -static enum xz_ret dec_index(struct xz_dec *s, struct xz_buf *b) +static enum xz_ret dec_index(struct xz_dec* s, struct xz_buf* b) { - enum xz_ret ret; - - do { - ret = dec_vli(s, b->in, &b->in_pos, b->in_size); - if (ret != XZ_STREAM_END) { - index_update(s, b); - return ret; - } - - switch (s->index.sequence) { - case SEQ_INDEX_COUNT: - s->index.count = s->vli; - - /* - * Validate that the Number of Records field - * indicates the same number of Records as - * there were Blocks in the Stream. - */ - if (s->index.count != s->block.count) - return XZ_DATA_ERROR; - - s->index.sequence = SEQ_INDEX_UNPADDED; - break; - - case SEQ_INDEX_UNPADDED: - s->index.hash.unpadded += s->vli; - s->index.sequence = SEQ_INDEX_UNCOMPRESSED; - break; - - case SEQ_INDEX_UNCOMPRESSED: - s->index.hash.uncompressed += s->vli; - s->index.hash.crc32 = xz_crc32( - (const uint8_t *)&s->index.hash, - sizeof(s->index.hash), - s->index.hash.crc32); - --s->index.count; - s->index.sequence = SEQ_INDEX_UNPADDED; - break; - } - } while (s->index.count > 0); - - return XZ_STREAM_END; + enum xz_ret ret; + + do + { + ret = dec_vli(s, b->in, &b->in_pos, b->in_size); + if (ret != XZ_STREAM_END) + { + index_update(s, b); + return ret; + } + + switch (s->index.sequence) + { + case SEQ_INDEX_COUNT: + s->index.count = s->vli; + + /* + * Validate that the Number of Records field + * indicates the same number of Records as + * there were Blocks in the Stream. + */ + if (s->index.count != s->block.count) + return XZ_DATA_ERROR; + + s->index.sequence = SEQ_INDEX_UNPADDED; + break; + + case SEQ_INDEX_UNPADDED: + s->index.hash.unpadded += s->vli; + s->index.sequence = SEQ_INDEX_UNCOMPRESSED; + break; + + case SEQ_INDEX_UNCOMPRESSED: + s->index.hash.uncompressed += s->vli; + s->index.hash.crc32 = + xz_crc32((const uint8_t*)&s->index.hash, sizeof(s->index.hash), s->index.hash.crc32); + --s->index.count; + s->index.sequence = SEQ_INDEX_UNPADDED; + break; + } + } while (s->index.count > 0); + + return XZ_STREAM_END; } /* * Validate that the next four input bytes match the value of s->crc32. * s->pos must be zero when starting to validate the first byte. */ -static enum xz_ret crc32_validate(struct xz_dec *s, struct xz_buf *b) +static enum xz_ret crc32_validate(struct xz_dec* s, struct xz_buf* b) { - do { - if (b->in_pos == b->in_size) - return XZ_OK; + do + { + if (b->in_pos == b->in_size) + return XZ_OK; - if (((s->crc32 >> s->pos) & 0xFF) != b->in[b->in_pos++]) - return XZ_DATA_ERROR; + if (((s->crc32 >> s->pos) & 0xFF) != b->in[b->in_pos++]) + return XZ_DATA_ERROR; - s->pos += 8; + s->pos += 8; - } while (s->pos < 32); + } while (s->pos < 32); - s->crc32 = 0; - s->pos = 0; + s->crc32 = 0; + s->pos = 0; - return XZ_STREAM_END; + return XZ_STREAM_END; } #ifdef XZ_DEC_ANY_CHECK @@ -401,343 +396,352 @@ static enum xz_ret crc32_validate(struct xz_dec *s, struct xz_buf *b) * Skip over the Check field when the Check ID is not supported. * Returns true once the whole Check field has been skipped over. */ -static bool check_skip(struct xz_dec *s, struct xz_buf *b) +static bool check_skip(struct xz_dec* s, struct xz_buf* b) { - while (s->pos < check_sizes[s->check_type]) { - if (b->in_pos == b->in_size) - return false; + while (s->pos < check_sizes[s->check_type]) + { + if (b->in_pos == b->in_size) + return false; - ++b->in_pos; - ++s->pos; - } + ++b->in_pos; + ++s->pos; + } - s->pos = 0; + s->pos = 0; - return true; + return true; } #endif /* Decode the Stream Header field (the first 12 bytes of the .xz Stream). */ -static enum xz_ret dec_stream_header(struct xz_dec *s) +static enum xz_ret dec_stream_header(struct xz_dec* s) { - if (!memeq(s->temp.buf, HEADER_MAGIC, HEADER_MAGIC_SIZE)) - return XZ_FORMAT_ERROR; + if (!memeq(s->temp.buf, HEADER_MAGIC, HEADER_MAGIC_SIZE)) + return XZ_FORMAT_ERROR; - if (xz_crc32(s->temp.buf + HEADER_MAGIC_SIZE, 2, 0) - != get_le32(s->temp.buf + HEADER_MAGIC_SIZE + 2)) - return XZ_DATA_ERROR; + if (xz_crc32(s->temp.buf + HEADER_MAGIC_SIZE, 2, 0) != get_le32(s->temp.buf + HEADER_MAGIC_SIZE + 2)) + return XZ_DATA_ERROR; - if (s->temp.buf[HEADER_MAGIC_SIZE] != 0) - return XZ_OPTIONS_ERROR; + if (s->temp.buf[HEADER_MAGIC_SIZE] != 0) + return XZ_OPTIONS_ERROR; - /* - * Of integrity checks, we support only none (Check ID = 0) and - * CRC32 (Check ID = 1). However, if XZ_DEC_ANY_CHECK is defined, - * we will accept other check types too, but then the check won't - * be verified and a warning (XZ_UNSUPPORTED_CHECK) will be given. - */ - s->check_type = s->temp.buf[HEADER_MAGIC_SIZE + 1]; + /* + * Of integrity checks, we support only none (Check ID = 0) and + * CRC32 (Check ID = 1). However, if XZ_DEC_ANY_CHECK is defined, + * we will accept other check types too, but then the check won't + * be verified and a warning (XZ_UNSUPPORTED_CHECK) will be given. + */ + s->check_type = s->temp.buf[HEADER_MAGIC_SIZE + 1]; #ifdef XZ_DEC_ANY_CHECK - if (s->check_type > XZ_CHECK_MAX) - return XZ_OPTIONS_ERROR; + if (s->check_type > XZ_CHECK_MAX) + return XZ_OPTIONS_ERROR; - if (s->check_type > XZ_CHECK_CRC32) - return XZ_UNSUPPORTED_CHECK; + if (s->check_type > XZ_CHECK_CRC32) + return XZ_UNSUPPORTED_CHECK; #else - if (s->check_type > XZ_CHECK_CRC32) - return XZ_OPTIONS_ERROR; + if (s->check_type > XZ_CHECK_CRC32) + return XZ_OPTIONS_ERROR; #endif - return XZ_OK; + return XZ_OK; } /* Decode the Stream Footer field (the last 12 bytes of the .xz Stream) */ -static enum xz_ret dec_stream_footer(struct xz_dec *s) +static enum xz_ret dec_stream_footer(struct xz_dec* s) { - if (!memeq(s->temp.buf + 10, FOOTER_MAGIC, FOOTER_MAGIC_SIZE)) - return XZ_DATA_ERROR; - - if (xz_crc32(s->temp.buf + 4, 6, 0) != get_le32(s->temp.buf)) - return XZ_DATA_ERROR; - - /* - * Validate Backward Size. Note that we never added the size of the - * Index CRC32 field to s->index.size, thus we use s->index.size / 4 - * instead of s->index.size / 4 - 1. - */ - if ((s->index.size >> 2) != get_le32(s->temp.buf + 4)) - return XZ_DATA_ERROR; - - if (s->temp.buf[8] != 0 || s->temp.buf[9] != s->check_type) - return XZ_DATA_ERROR; - - /* - * Use XZ_STREAM_END instead of XZ_OK to be more convenient - * for the caller. - */ - return XZ_STREAM_END; + if (!memeq(s->temp.buf + 10, FOOTER_MAGIC, FOOTER_MAGIC_SIZE)) + return XZ_DATA_ERROR; + + if (xz_crc32(s->temp.buf + 4, 6, 0) != get_le32(s->temp.buf)) + return XZ_DATA_ERROR; + + /* + * Validate Backward Size. Note that we never added the size of the + * Index CRC32 field to s->index.size, thus we use s->index.size / 4 + * instead of s->index.size / 4 - 1. + */ + if ((s->index.size >> 2) != get_le32(s->temp.buf + 4)) + return XZ_DATA_ERROR; + + if (s->temp.buf[8] != 0 || s->temp.buf[9] != s->check_type) + return XZ_DATA_ERROR; + + /* + * Use XZ_STREAM_END instead of XZ_OK to be more convenient + * for the caller. + */ + return XZ_STREAM_END; } /* Decode the Block Header and initialize the filter chain. */ -static enum xz_ret dec_block_header(struct xz_dec *s) +static enum xz_ret dec_block_header(struct xz_dec* s) { - enum xz_ret ret; - - /* - * Validate the CRC32. We know that the temp buffer is at least - * eight bytes so this is safe. - */ - s->temp.size -= 4; - if (xz_crc32(s->temp.buf, s->temp.size, 0) - != get_le32(s->temp.buf + s->temp.size)) - return XZ_DATA_ERROR; - - s->temp.pos = 2; - - /* - * Catch unsupported Block Flags. We support only one or two filters - * in the chain, so we catch that with the same test. - */ + enum xz_ret ret; + + /* + * Validate the CRC32. We know that the temp buffer is at least + * eight bytes so this is safe. + */ + s->temp.size -= 4; + if (xz_crc32(s->temp.buf, s->temp.size, 0) != get_le32(s->temp.buf + s->temp.size)) + return XZ_DATA_ERROR; + + s->temp.pos = 2; + + /* + * Catch unsupported Block Flags. We support only one or two filters + * in the chain, so we catch that with the same test. + */ #ifdef XZ_DEC_BCJ - if (s->temp.buf[1] & 0x3E) + if (s->temp.buf[1] & 0x3E) #else - if (s->temp.buf[1] & 0x3F) + if (s->temp.buf[1] & 0x3F) #endif - return XZ_OPTIONS_ERROR; - - /* Compressed Size */ - if (s->temp.buf[1] & 0x40) { - if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size) - != XZ_STREAM_END) - return XZ_DATA_ERROR; - - s->block_header.compressed = s->vli; - } else { - s->block_header.compressed = VLI_UNKNOWN; - } - - /* Uncompressed Size */ - if (s->temp.buf[1] & 0x80) { - if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size) - != XZ_STREAM_END) - return XZ_DATA_ERROR; - - s->block_header.uncompressed = s->vli; - } else { - s->block_header.uncompressed = VLI_UNKNOWN; - } + return XZ_OPTIONS_ERROR; + + /* Compressed Size */ + if (s->temp.buf[1] & 0x40) + { + if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size) != XZ_STREAM_END) + return XZ_DATA_ERROR; + + s->block_header.compressed = s->vli; + } + else + { + s->block_header.compressed = VLI_UNKNOWN; + } + + /* Uncompressed Size */ + if (s->temp.buf[1] & 0x80) + { + if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size) != XZ_STREAM_END) + return XZ_DATA_ERROR; + + s->block_header.uncompressed = s->vli; + } + else + { + s->block_header.uncompressed = VLI_UNKNOWN; + } #ifdef XZ_DEC_BCJ - /* If there are two filters, the first one must be a BCJ filter. */ - s->bcj_active = s->temp.buf[1] & 0x01; - if (s->bcj_active) { - if (s->temp.size - s->temp.pos < 2) - return XZ_OPTIONS_ERROR; - - ret = xz_dec_bcj_reset(s->bcj, s->temp.buf[s->temp.pos++]); - if (ret != XZ_OK) - return ret; - - /* - * We don't support custom start offset, - * so Size of Properties must be zero. - */ - if (s->temp.buf[s->temp.pos++] != 0x00) - return XZ_OPTIONS_ERROR; - } + /* If there are two filters, the first one must be a BCJ filter. */ + s->bcj_active = s->temp.buf[1] & 0x01; + if (s->bcj_active) + { + if (s->temp.size - s->temp.pos < 2) + return XZ_OPTIONS_ERROR; + + ret = xz_dec_bcj_reset(s->bcj, s->temp.buf[s->temp.pos++]); + if (ret != XZ_OK) + return ret; + + /* + * We don't support custom start offset, + * so Size of Properties must be zero. + */ + if (s->temp.buf[s->temp.pos++] != 0x00) + return XZ_OPTIONS_ERROR; + } #endif - /* Valid Filter Flags always take at least two bytes. */ - if (s->temp.size - s->temp.pos < 2) - return XZ_DATA_ERROR; + /* Valid Filter Flags always take at least two bytes. */ + if (s->temp.size - s->temp.pos < 2) + return XZ_DATA_ERROR; - /* Filter ID = LZMA2 */ - if (s->temp.buf[s->temp.pos++] != 0x21) - return XZ_OPTIONS_ERROR; + /* Filter ID = LZMA2 */ + if (s->temp.buf[s->temp.pos++] != 0x21) + return XZ_OPTIONS_ERROR; - /* Size of Properties = 1-byte Filter Properties */ - if (s->temp.buf[s->temp.pos++] != 0x01) - return XZ_OPTIONS_ERROR; + /* Size of Properties = 1-byte Filter Properties */ + if (s->temp.buf[s->temp.pos++] != 0x01) + return XZ_OPTIONS_ERROR; - /* Filter Properties contains LZMA2 dictionary size. */ - if (s->temp.size - s->temp.pos < 1) - return XZ_DATA_ERROR; + /* Filter Properties contains LZMA2 dictionary size. */ + if (s->temp.size - s->temp.pos < 1) + return XZ_DATA_ERROR; - ret = xz_dec_lzma2_reset(s->lzma2, s->temp.buf[s->temp.pos++]); - if (ret != XZ_OK) - return ret; + ret = xz_dec_lzma2_reset(s->lzma2, s->temp.buf[s->temp.pos++]); + if (ret != XZ_OK) + return ret; - /* The rest must be Header Padding. */ - while (s->temp.pos < s->temp.size) - if (s->temp.buf[s->temp.pos++] != 0x00) - return XZ_OPTIONS_ERROR; + /* The rest must be Header Padding. */ + while (s->temp.pos < s->temp.size) + if (s->temp.buf[s->temp.pos++] != 0x00) + return XZ_OPTIONS_ERROR; - s->temp.pos = 0; - s->block.compressed = 0; - s->block.uncompressed = 0; + s->temp.pos = 0; + s->block.compressed = 0; + s->block.uncompressed = 0; - return XZ_OK; + return XZ_OK; } -static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b) +static enum xz_ret dec_main(struct xz_dec* s, struct xz_buf* b) { - enum xz_ret ret; - - /* - * Store the start position for the case when we are in the middle - * of the Index field. - */ - s->in_start = b->in_pos; - - while (true) { - switch (s->sequence) { - case SEQ_STREAM_HEADER: - /* - * Stream Header is copied to s->temp, and then - * decoded from there. This way if the caller - * gives us only little input at a time, we can - * still keep the Stream Header decoding code - * simple. Similar approach is used in many places - * in this file. - */ - if (!fill_temp(s, b)) - return XZ_OK; - - /* - * If dec_stream_header() returns - * XZ_UNSUPPORTED_CHECK, it is still possible - * to continue decoding if working in multi-call - * mode. Thus, update s->sequence before calling - * dec_stream_header(). - */ - s->sequence = SEQ_BLOCK_START; - - ret = dec_stream_header(s); - if (ret != XZ_OK) - return ret; - - case SEQ_BLOCK_START: - /* We need one byte of input to continue. */ - if (b->in_pos == b->in_size) - return XZ_OK; - - /* See if this is the beginning of the Index field. */ - if (b->in[b->in_pos] == 0) { - s->in_start = b->in_pos++; - s->sequence = SEQ_INDEX; - break; - } - - /* - * Calculate the size of the Block Header and - * prepare to decode it. - */ - s->block_header.size - = ((uint32_t)b->in[b->in_pos] + 1) * 4; - - s->temp.size = s->block_header.size; - s->temp.pos = 0; - s->sequence = SEQ_BLOCK_HEADER; - - case SEQ_BLOCK_HEADER: - if (!fill_temp(s, b)) - return XZ_OK; - - ret = dec_block_header(s); - if (ret != XZ_OK) - return ret; - - s->sequence = SEQ_BLOCK_UNCOMPRESS; - - case SEQ_BLOCK_UNCOMPRESS: - ret = dec_block(s, b); - if (ret != XZ_STREAM_END) - return ret; - - s->sequence = SEQ_BLOCK_PADDING; - - case SEQ_BLOCK_PADDING: - /* - * Size of Compressed Data + Block Padding - * must be a multiple of four. We don't need - * s->block.compressed for anything else - * anymore, so we use it here to test the size - * of the Block Padding field. - */ - while (s->block.compressed & 3) { - if (b->in_pos == b->in_size) - return XZ_OK; - - if (b->in[b->in_pos++] != 0) - return XZ_DATA_ERROR; - - ++s->block.compressed; - } - - s->sequence = SEQ_BLOCK_CHECK; - - case SEQ_BLOCK_CHECK: - if (s->check_type == XZ_CHECK_CRC32) { - ret = crc32_validate(s, b); - if (ret != XZ_STREAM_END) - return ret; - } + enum xz_ret ret; + + /* + * Store the start position for the case when we are in the middle + * of the Index field. + */ + s->in_start = b->in_pos; + + while (true) + { + switch (s->sequence) + { + case SEQ_STREAM_HEADER: + /* + * Stream Header is copied to s->temp, and then + * decoded from there. This way if the caller + * gives us only little input at a time, we can + * still keep the Stream Header decoding code + * simple. Similar approach is used in many places + * in this file. + */ + if (!fill_temp(s, b)) + return XZ_OK; + + /* + * If dec_stream_header() returns + * XZ_UNSUPPORTED_CHECK, it is still possible + * to continue decoding if working in multi-call + * mode. Thus, update s->sequence before calling + * dec_stream_header(). + */ + s->sequence = SEQ_BLOCK_START; + + ret = dec_stream_header(s); + if (ret != XZ_OK) + return ret; + + case SEQ_BLOCK_START: + /* We need one byte of input to continue. */ + if (b->in_pos == b->in_size) + return XZ_OK; + + /* See if this is the beginning of the Index field. */ + if (b->in[b->in_pos] == 0) + { + s->in_start = b->in_pos++; + s->sequence = SEQ_INDEX; + break; + } + + /* + * Calculate the size of the Block Header and + * prepare to decode it. + */ + s->block_header.size = ((uint32_t)b->in[b->in_pos] + 1) * 4; + + s->temp.size = s->block_header.size; + s->temp.pos = 0; + s->sequence = SEQ_BLOCK_HEADER; + + case SEQ_BLOCK_HEADER: + if (!fill_temp(s, b)) + return XZ_OK; + + ret = dec_block_header(s); + if (ret != XZ_OK) + return ret; + + s->sequence = SEQ_BLOCK_UNCOMPRESS; + + case SEQ_BLOCK_UNCOMPRESS: + ret = dec_block(s, b); + if (ret != XZ_STREAM_END) + return ret; + + s->sequence = SEQ_BLOCK_PADDING; + + case SEQ_BLOCK_PADDING: + /* + * Size of Compressed Data + Block Padding + * must be a multiple of four. We don't need + * s->block.compressed for anything else + * anymore, so we use it here to test the size + * of the Block Padding field. + */ + while (s->block.compressed & 3) + { + if (b->in_pos == b->in_size) + return XZ_OK; + + if (b->in[b->in_pos++] != 0) + return XZ_DATA_ERROR; + + ++s->block.compressed; + } + + s->sequence = SEQ_BLOCK_CHECK; + + case SEQ_BLOCK_CHECK: + if (s->check_type == XZ_CHECK_CRC32) + { + ret = crc32_validate(s, b); + if (ret != XZ_STREAM_END) + return ret; + } #ifdef XZ_DEC_ANY_CHECK - else if (!check_skip(s, b)) { - return XZ_OK; - } + else if (!check_skip(s, b)) + { + return XZ_OK; + } #endif - s->sequence = SEQ_BLOCK_START; - break; + s->sequence = SEQ_BLOCK_START; + break; - case SEQ_INDEX: - ret = dec_index(s, b); - if (ret != XZ_STREAM_END) - return ret; + case SEQ_INDEX: + ret = dec_index(s, b); + if (ret != XZ_STREAM_END) + return ret; - s->sequence = SEQ_INDEX_PADDING; + s->sequence = SEQ_INDEX_PADDING; - case SEQ_INDEX_PADDING: - while ((s->index.size + (b->in_pos - s->in_start)) - & 3) { - if (b->in_pos == b->in_size) { - index_update(s, b); - return XZ_OK; - } + case SEQ_INDEX_PADDING: + while ((s->index.size + (b->in_pos - s->in_start)) & 3) + { + if (b->in_pos == b->in_size) + { + index_update(s, b); + return XZ_OK; + } - if (b->in[b->in_pos++] != 0) - return XZ_DATA_ERROR; - } + if (b->in[b->in_pos++] != 0) + return XZ_DATA_ERROR; + } - /* Finish the CRC32 value and Index size. */ - index_update(s, b); + /* Finish the CRC32 value and Index size. */ + index_update(s, b); - /* Compare the hashes to validate the Index field. */ - if (!memeq(&s->block.hash, &s->index.hash, - sizeof(s->block.hash))) - return XZ_DATA_ERROR; + /* Compare the hashes to validate the Index field. */ + if (!memeq(&s->block.hash, &s->index.hash, sizeof(s->block.hash))) + return XZ_DATA_ERROR; - s->sequence = SEQ_INDEX_CRC32; + s->sequence = SEQ_INDEX_CRC32; - case SEQ_INDEX_CRC32: - ret = crc32_validate(s, b); - if (ret != XZ_STREAM_END) - return ret; + case SEQ_INDEX_CRC32: + ret = crc32_validate(s, b); + if (ret != XZ_STREAM_END) + return ret; - s->temp.size = STREAM_HEADER_SIZE; - s->sequence = SEQ_STREAM_FOOTER; + s->temp.size = STREAM_HEADER_SIZE; + s->sequence = SEQ_STREAM_FOOTER; - case SEQ_STREAM_FOOTER: - if (!fill_temp(s, b)) - return XZ_OK; + case SEQ_STREAM_FOOTER: + if (!fill_temp(s, b)) + return XZ_OK; - return dec_stream_footer(s); - } - } + return dec_stream_footer(s); + } + } - /* Never reached */ + /* Never reached */ } /* @@ -765,91 +769,95 @@ static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b) * actually succeeds (that's the price to pay of using the output buffer as * the workspace). */ -XZ_EXTERN enum xz_ret xz_dec_run(struct xz_dec *s, struct xz_buf *b) +XZ_EXTERN enum xz_ret xz_dec_run(struct xz_dec* s, struct xz_buf* b) { - size_t in_start; - size_t out_start; - enum xz_ret ret; - - if (DEC_IS_SINGLE(s->mode)) - xz_dec_reset(s); - - in_start = b->in_pos; - out_start = b->out_pos; - ret = dec_main(s, b); - - if (DEC_IS_SINGLE(s->mode)) { - if (ret == XZ_OK) - ret = b->in_pos == b->in_size - ? XZ_DATA_ERROR : XZ_BUF_ERROR; - - if (ret != XZ_STREAM_END) { - b->in_pos = in_start; - b->out_pos = out_start; - } - - } else if (ret == XZ_OK && in_start == b->in_pos - && out_start == b->out_pos) { - if (s->allow_buf_error) - ret = XZ_BUF_ERROR; - - s->allow_buf_error = true; - } else { - s->allow_buf_error = false; - } - - return ret; + size_t in_start; + size_t out_start; + enum xz_ret ret; + + if (DEC_IS_SINGLE(s->mode)) + xz_dec_reset(s); + + in_start = b->in_pos; + out_start = b->out_pos; + ret = dec_main(s, b); + + if (DEC_IS_SINGLE(s->mode)) + { + if (ret == XZ_OK) + ret = b->in_pos == b->in_size ? XZ_DATA_ERROR : XZ_BUF_ERROR; + + if (ret != XZ_STREAM_END) + { + b->in_pos = in_start; + b->out_pos = out_start; + } + } + else if (ret == XZ_OK && in_start == b->in_pos && out_start == b->out_pos) + { + if (s->allow_buf_error) + ret = XZ_BUF_ERROR; + + s->allow_buf_error = true; + } + else + { + s->allow_buf_error = false; + } + + return ret; } -XZ_EXTERN struct xz_dec *xz_dec_init(enum xz_mode mode, uint32_t dict_max) +XZ_EXTERN struct xz_dec* xz_dec_init(enum xz_mode mode, uint32_t dict_max) { - struct xz_dec *s = kmalloc(sizeof(*s), GFP_KERNEL); - if (s == NULL) - return NULL; + struct xz_dec* s = kmalloc(sizeof(*s), GFP_KERNEL); + if (s == NULL) + return NULL; - s->mode = mode; + s->mode = mode; #ifdef XZ_DEC_BCJ - s->bcj = xz_dec_bcj_create(DEC_IS_SINGLE(mode)); - if (s->bcj == NULL) - goto error_bcj; + s->bcj = xz_dec_bcj_create(DEC_IS_SINGLE(mode)); + if (s->bcj == NULL) + goto error_bcj; #endif - s->lzma2 = xz_dec_lzma2_create(mode, dict_max); - if (s->lzma2 == NULL) - goto error_lzma2; + s->lzma2 = xz_dec_lzma2_create(mode, dict_max); + if (s->lzma2 == NULL) + goto error_lzma2; - xz_dec_reset(s); - return s; + xz_dec_reset(s); + return s; error_lzma2: #ifdef XZ_DEC_BCJ - xz_dec_bcj_end(s->bcj); + xz_dec_bcj_end(s->bcj); error_bcj: #endif - kfree(s); - return NULL; + kfree(s); + return NULL; } -XZ_EXTERN void xz_dec_reset(struct xz_dec *s) +XZ_EXTERN void xz_dec_reset(struct xz_dec* s) { - s->sequence = SEQ_STREAM_HEADER; - s->allow_buf_error = false; - s->pos = 0; - s->crc32 = 0; - memzero(&s->block, sizeof(s->block)); - memzero(&s->index, sizeof(s->index)); - s->temp.pos = 0; - s->temp.size = STREAM_HEADER_SIZE; + s->sequence = SEQ_STREAM_HEADER; + s->allow_buf_error = false; + s->pos = 0; + s->crc32 = 0; + memzero(&s->block, sizeof(s->block)); + memzero(&s->index, sizeof(s->index)); + s->temp.pos = 0; + s->temp.size = STREAM_HEADER_SIZE; } -XZ_EXTERN void xz_dec_end(struct xz_dec *s) +XZ_EXTERN void xz_dec_end(struct xz_dec* s) { - if (s != NULL) { - xz_dec_lzma2_end(s->lzma2); + if (s != NULL) + { + xz_dec_lzma2_end(s->lzma2); #ifdef XZ_DEC_BCJ - xz_dec_bcj_end(s->bcj); + xz_dec_bcj_end(s->bcj); #endif - kfree(s); - } + kfree(s); + } } diff --git a/ext_libs/minixz/xz_lzma2.h b/ext_libs/minixz/xz_lzma2.h index 40c20cce..0c7632dc 100644 --- a/ext_libs/minixz/xz_lzma2.h +++ b/ext_libs/minixz/xz_lzma2.h @@ -72,19 +72,20 @@ * The symbol names are in from STATE_oldest_older_previous. REP means * either short or long repeated match, and NONLIT means any non-literal. */ -enum lzma_state { - STATE_LIT_LIT, - STATE_MATCH_LIT_LIT, - STATE_REP_LIT_LIT, - STATE_SHORTREP_LIT_LIT, - STATE_MATCH_LIT, - STATE_REP_LIT, - STATE_SHORTREP_LIT, - STATE_LIT_MATCH, - STATE_LIT_LONGREP, - STATE_LIT_SHORTREP, - STATE_NONLIT_MATCH, - STATE_NONLIT_REP +enum lzma_state +{ + STATE_LIT_LIT, + STATE_MATCH_LIT_LIT, + STATE_REP_LIT_LIT, + STATE_SHORTREP_LIT_LIT, + STATE_MATCH_LIT, + STATE_REP_LIT, + STATE_SHORTREP_LIT, + STATE_LIT_MATCH, + STATE_LIT_LONGREP, + STATE_LIT_SHORTREP, + STATE_NONLIT_MATCH, + STATE_NONLIT_REP }; /* Total number of states */ @@ -94,38 +95,38 @@ enum lzma_state { #define LIT_STATES 7 /* Indicate that the latest symbol was a literal. */ -static inline void lzma_state_literal(enum lzma_state *state) +static inline void lzma_state_literal(enum lzma_state* state) { - if (*state <= STATE_SHORTREP_LIT_LIT) - *state = STATE_LIT_LIT; - else if (*state <= STATE_LIT_SHORTREP) - *state -= 3; - else - *state -= 6; + if (*state <= STATE_SHORTREP_LIT_LIT) + *state = STATE_LIT_LIT; + else if (*state <= STATE_LIT_SHORTREP) + *state -= 3; + else + *state -= 6; } /* Indicate that the latest symbol was a match. */ -static inline void lzma_state_match(enum lzma_state *state) +static inline void lzma_state_match(enum lzma_state* state) { - *state = *state < LIT_STATES ? STATE_LIT_MATCH : STATE_NONLIT_MATCH; + *state = *state < LIT_STATES ? STATE_LIT_MATCH : STATE_NONLIT_MATCH; } /* Indicate that the latest state was a long repeated match. */ -static inline void lzma_state_long_rep(enum lzma_state *state) +static inline void lzma_state_long_rep(enum lzma_state* state) { - *state = *state < LIT_STATES ? STATE_LIT_LONGREP : STATE_NONLIT_REP; + *state = *state < LIT_STATES ? STATE_LIT_LONGREP : STATE_NONLIT_REP; } /* Indicate that the latest symbol was a short match. */ -static inline void lzma_state_short_rep(enum lzma_state *state) +static inline void lzma_state_short_rep(enum lzma_state* state) { - *state = *state < LIT_STATES ? STATE_LIT_SHORTREP : STATE_NONLIT_REP; + *state = *state < LIT_STATES ? STATE_LIT_SHORTREP : STATE_NONLIT_REP; } /* Test if the previous symbol was a literal. */ static inline bool lzma_state_is_literal(enum lzma_state state) { - return state < LIT_STATES; + return state < LIT_STATES; } /* Each literal coder is divided in three sections: @@ -179,8 +180,7 @@ static inline bool lzma_state_is_literal(enum lzma_state state) */ static inline uint32_t lzma_get_dist_state(uint32_t len) { - return len < DIST_STATES + MATCH_LEN_MIN - ? len - MATCH_LEN_MIN : DIST_STATES - 1; + return len < DIST_STATES + MATCH_LEN_MIN ? len - MATCH_LEN_MIN : DIST_STATES - 1; } /* diff --git a/ext_libs/minixz/xz_private.h b/ext_libs/minixz/xz_private.h index 396cf32f..a49aa352 100644 --- a/ext_libs/minixz/xz_private.h +++ b/ext_libs/minixz/xz_private.h @@ -43,51 +43,50 @@ #define XZ_PRIVATE_H #ifdef __KERNEL__ -# include -# include -# include - /* XZ_PREBOOT may be defined only via decompress_unxz.c. */ -# ifndef XZ_PREBOOT -# include -# include -# include -# ifdef CONFIG_XZ_DEC_X86 -# define XZ_DEC_X86 -# endif -# ifdef CONFIG_XZ_DEC_POWERPC -# define XZ_DEC_POWERPC -# endif -# ifdef CONFIG_XZ_DEC_IA64 -# define XZ_DEC_IA64 -# endif -# ifdef CONFIG_XZ_DEC_ARM -# define XZ_DEC_ARM -# endif -# ifdef CONFIG_XZ_DEC_ARMTHUMB -# define XZ_DEC_ARMTHUMB -# endif -# ifdef CONFIG_XZ_DEC_SPARC -# define XZ_DEC_SPARC -# endif -# define memeq(a, b, size) (memcmp(a, b, size) == 0) -# define memzero(buf, size) memset(buf, 0, size) -# endif -# define get_le32(p) le32_to_cpup((const uint32_t *)(p)) +#include +#include +#include +/* XZ_PREBOOT may be defined only via decompress_unxz.c. */ +#ifndef XZ_PREBOOT +#include +#include +#include +#ifdef CONFIG_XZ_DEC_X86 +#define XZ_DEC_X86 +#endif +#ifdef CONFIG_XZ_DEC_POWERPC +#define XZ_DEC_POWERPC +#endif +#ifdef CONFIG_XZ_DEC_IA64 +#define XZ_DEC_IA64 +#endif +#ifdef CONFIG_XZ_DEC_ARM +#define XZ_DEC_ARM +#endif +#ifdef CONFIG_XZ_DEC_ARMTHUMB +#define XZ_DEC_ARMTHUMB +#endif +#ifdef CONFIG_XZ_DEC_SPARC +#define XZ_DEC_SPARC +#endif +#define memeq(a, b, size) (memcmp(a, b, size) == 0) +#define memzero(buf, size) memset(buf, 0, size) +#endif +#define get_le32(p) le32_to_cpup((const uint32_t*)(p)) #else - /* - * For userspace builds, use a separate header to define the required - * macros and functions. This makes it easier to adapt the code into - * different environments and avoids clutter in the Linux kernel tree. - */ -# include +/* + * For userspace builds, use a separate header to define the required + * macros and functions. This makes it easier to adapt the code into + * different environments and avoids clutter in the Linux kernel tree. + */ +#include #endif /* If no specific decoding mode is requested, enable support for all modes. */ -#if !defined(XZ_DEC_SINGLE) && !defined(XZ_DEC_PREALLOC) \ - && !defined(XZ_DEC_DYNALLOC) -# define XZ_DEC_SINGLE -# define XZ_DEC_PREALLOC -# define XZ_DEC_DYNALLOC +#if !defined(XZ_DEC_SINGLE) && !defined(XZ_DEC_PREALLOC) && !defined(XZ_DEC_DYNALLOC) +#define XZ_DEC_SINGLE +#define XZ_DEC_PREALLOC +#define XZ_DEC_DYNALLOC #endif /* @@ -96,29 +95,29 @@ * false at compile time and thus allow the compiler to omit unneeded code. */ #ifdef XZ_DEC_SINGLE -# define DEC_IS_SINGLE(mode) ((mode) == XZ_SINGLE) +#define DEC_IS_SINGLE(mode) ((mode) == XZ_SINGLE) #else -# define DEC_IS_SINGLE(mode) (false) +#define DEC_IS_SINGLE(mode) (false) #endif #ifdef XZ_DEC_PREALLOC -# define DEC_IS_PREALLOC(mode) ((mode) == XZ_PREALLOC) +#define DEC_IS_PREALLOC(mode) ((mode) == XZ_PREALLOC) #else -# define DEC_IS_PREALLOC(mode) (false) +#define DEC_IS_PREALLOC(mode) (false) #endif #ifdef XZ_DEC_DYNALLOC -# define DEC_IS_DYNALLOC(mode) ((mode) == XZ_DYNALLOC) +#define DEC_IS_DYNALLOC(mode) ((mode) == XZ_DYNALLOC) #else -# define DEC_IS_DYNALLOC(mode) (false) +#define DEC_IS_DYNALLOC(mode) (false) #endif #if !defined(XZ_DEC_SINGLE) -# define DEC_IS_MULTI(mode) (true) +#define DEC_IS_MULTI(mode) (true) #elif defined(XZ_DEC_PREALLOC) || defined(XZ_DEC_DYNALLOC) -# define DEC_IS_MULTI(mode) ((mode) != XZ_SINGLE) +#define DEC_IS_MULTI(mode) ((mode) != XZ_SINGLE) #else -# define DEC_IS_MULTI(mode) (false) +#define DEC_IS_MULTI(mode) (false) #endif /* @@ -126,20 +125,17 @@ * XZ_DEC_BCJ is used to enable generic support for BCJ decoders. */ #ifndef XZ_DEC_BCJ -# if defined(XZ_DEC_X86) || defined(XZ_DEC_POWERPC) \ - || defined(XZ_DEC_IA64) || defined(XZ_DEC_ARM) \ - || defined(XZ_DEC_ARM) || defined(XZ_DEC_ARMTHUMB) \ - || defined(XZ_DEC_SPARC) -# define XZ_DEC_BCJ -# endif +#if defined(XZ_DEC_X86) || defined(XZ_DEC_POWERPC) || defined(XZ_DEC_IA64) || defined(XZ_DEC_ARM) || \ + defined(XZ_DEC_ARM) || defined(XZ_DEC_ARMTHUMB) || defined(XZ_DEC_SPARC) +#define XZ_DEC_BCJ +#endif #endif /* * Allocate memory for LZMA2 decoder. xz_dec_lzma2_reset() must be used * before calling xz_dec_lzma2_run(). */ -XZ_EXTERN struct xz_dec_lzma2 *xz_dec_lzma2_create(enum xz_mode mode, - uint32_t dict_max); +XZ_EXTERN struct xz_dec_lzma2* xz_dec_lzma2_create(enum xz_mode mode, uint32_t dict_max); /* * Decode the LZMA2 properties (one byte) and reset the decoder. Return @@ -147,22 +143,20 @@ XZ_EXTERN struct xz_dec_lzma2 *xz_dec_lzma2_create(enum xz_mode mode, * big enough, and XZ_OPTIONS_ERROR if props indicates something that this * decoder doesn't support. */ -XZ_EXTERN enum xz_ret xz_dec_lzma2_reset(struct xz_dec_lzma2 *s, - uint8_t props); +XZ_EXTERN enum xz_ret xz_dec_lzma2_reset(struct xz_dec_lzma2* s, uint8_t props); /* Decode raw LZMA2 stream from b->in to b->out. */ -XZ_EXTERN enum xz_ret xz_dec_lzma2_run(struct xz_dec_lzma2 *s, - struct xz_buf *b); +XZ_EXTERN enum xz_ret xz_dec_lzma2_run(struct xz_dec_lzma2* s, struct xz_buf* b); /* Free the memory allocated for the LZMA2 decoder. */ -XZ_EXTERN void xz_dec_lzma2_end(struct xz_dec_lzma2 *s); +XZ_EXTERN void xz_dec_lzma2_end(struct xz_dec_lzma2* s); #ifdef XZ_DEC_BCJ /* * Allocate memory for BCJ decoders. xz_dec_bcj_reset() must be used before * calling xz_dec_bcj_run(). */ -XZ_EXTERN struct xz_dec_bcj *xz_dec_bcj_create(bool single_call); +XZ_EXTERN struct xz_dec_bcj* xz_dec_bcj_create(bool single_call); /* * Decode the Filter ID of a BCJ filter. This implementation doesn't @@ -170,16 +164,14 @@ XZ_EXTERN struct xz_dec_bcj *xz_dec_bcj_create(bool single_call); * is needed. Returns XZ_OK if the given Filter ID is supported. * Otherwise XZ_OPTIONS_ERROR is returned. */ -XZ_EXTERN enum xz_ret xz_dec_bcj_reset(struct xz_dec_bcj *s, uint8_t id); +XZ_EXTERN enum xz_ret xz_dec_bcj_reset(struct xz_dec_bcj* s, uint8_t id); /* * Decode raw BCJ + LZMA2 stream. This must be used only if there actually is * a BCJ filter in the chain. If the chain has only LZMA2, xz_dec_lzma2_run() * must be called directly. */ -XZ_EXTERN enum xz_ret xz_dec_bcj_run(struct xz_dec_bcj *s, - struct xz_dec_lzma2 *lzma2, - struct xz_buf *b); +XZ_EXTERN enum xz_ret xz_dec_bcj_run(struct xz_dec_bcj* s, struct xz_dec_lzma2* lzma2, struct xz_buf* b); /* Free the memory allocated for the BCJ filters. */ #define xz_dec_bcj_end(s) kfree(s) diff --git a/ext_libs/minixz/xz_stream.h b/ext_libs/minixz/xz_stream.h index 8c1913da..e601e6db 100644 --- a/ext_libs/minixz/xz_stream.h +++ b/ext_libs/minixz/xz_stream.h @@ -42,10 +42,9 @@ #define XZ_STREAM_H #if defined(__KERNEL__) && !XZ_INTERNAL_CRC32 -# include -# undef crc32 -# define xz_crc32(buf, size, crc) \ - (~crc32_le(~(uint32_t)(crc), buf, size)) +#include +#undef crc32 +#define xz_crc32(buf, size, crc) (~crc32_le(~(uint32_t)(crc), buf, size)) #endif /* @@ -80,11 +79,12 @@ typedef uint64_t vli_type; #define VLI_BYTES_MAX (sizeof(vli_type) * 8 / 7) /* Integrity Check types */ -enum xz_check { - XZ_CHECK_NONE = 0, - XZ_CHECK_CRC32 = 1, - XZ_CHECK_CRC64 = 4, - XZ_CHECK_SHA256 = 10 +enum xz_check +{ + XZ_CHECK_NONE = 0, + XZ_CHECK_CRC32 = 1, + XZ_CHECK_CRC64 = 4, + XZ_CHECK_SHA256 = 10 }; /* Maximum possible Check ID */ diff --git a/ext_libs/muparser/muParser.cpp b/ext_libs/muparser/muParser.cpp old mode 100755 new mode 100644 index 39ea8610..ca38ae35 --- a/ext_libs/muparser/muParser.cpp +++ b/ext_libs/muparser/muParser.cpp @@ -1,27 +1,27 @@ -/* - __________ - _____ __ __\______ \_____ _______ ______ ____ _______ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ - |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| - \/ \/ \/ \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ Copyright (C) 2013 Ingo Berg - Permission is hereby granted, free of charge, to any person obtaining a copy of this + 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 + 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 + 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. + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "muParser.h" #include "muParserTemplateMagic.h" @@ -32,10 +32,10 @@ #include /** \brief Pi (what else?). */ -#define PARSER_CONST_PI 3.141592653589793238462643 +#define PARSER_CONST_PI 3.141592653589793238462643 /** \brief The Eulerian number. */ -#define PARSER_CONST_E 2.718281828459045235360287 +#define PARSER_CONST_E 2.718281828459045235360287 using namespace std; @@ -43,299 +43,344 @@ using namespace std; \brief Implementation of the standard floating point parser. */ - - /** \brief Namespace for mathematical applications. */ namespace mu { +//--------------------------------------------------------------------------- +// Trigonometric function +value_type Parser::Sin(value_type v) +{ + return MathImpl::Sin(v); +} +value_type Parser::Cos(value_type v) +{ + return MathImpl::Cos(v); +} +value_type Parser::Tan(value_type v) +{ + return MathImpl::Tan(v); +} +value_type Parser::ASin(value_type v) +{ + return MathImpl::ASin(v); +} +value_type Parser::ACos(value_type v) +{ + return MathImpl::ACos(v); +} +value_type Parser::ATan(value_type v) +{ + return MathImpl::ATan(v); +} +value_type Parser::ATan2(value_type v1, value_type v2) +{ + return MathImpl::ATan2(v1, v2); +} +value_type Parser::Sinh(value_type v) +{ + return MathImpl::Sinh(v); +} +value_type Parser::Cosh(value_type v) +{ + return MathImpl::Cosh(v); +} +value_type Parser::Tanh(value_type v) +{ + return MathImpl::Tanh(v); +} +value_type Parser::ASinh(value_type v) +{ + return MathImpl::ASinh(v); +} +value_type Parser::ACosh(value_type v) +{ + return MathImpl::ACosh(v); +} +value_type Parser::ATanh(value_type v) +{ + return MathImpl::ATanh(v); +} +//--------------------------------------------------------------------------- +// Logarithm functions - //--------------------------------------------------------------------------- - // Trigonometric function - value_type Parser::Sin(value_type v) { return MathImpl::Sin(v); } - value_type Parser::Cos(value_type v) { return MathImpl::Cos(v); } - value_type Parser::Tan(value_type v) { return MathImpl::Tan(v); } - value_type Parser::ASin(value_type v) { return MathImpl::ASin(v); } - value_type Parser::ACos(value_type v) { return MathImpl::ACos(v); } - value_type Parser::ATan(value_type v) { return MathImpl::ATan(v); } - value_type Parser::ATan2(value_type v1, value_type v2) { return MathImpl::ATan2(v1, v2); } - value_type Parser::Sinh(value_type v) { return MathImpl::Sinh(v); } - value_type Parser::Cosh(value_type v) { return MathImpl::Cosh(v); } - value_type Parser::Tanh(value_type v) { return MathImpl::Tanh(v); } - value_type Parser::ASinh(value_type v) { return MathImpl::ASinh(v); } - value_type Parser::ACosh(value_type v) { return MathImpl::ACosh(v); } - value_type Parser::ATanh(value_type v) { return MathImpl::ATanh(v); } - - //--------------------------------------------------------------------------- - // Logarithm functions - - // Logarithm base 2 - value_type Parser::Log2(value_type v) - { - #ifdef MUP_MATH_EXCEPTIONS - if (v<=0) - throw ParserError(ecDOMAIN_ERROR, _T("Log2")); - #endif - - return MathImpl::Log2(v); - } - - // Logarithm base 10 - value_type Parser::Log10(value_type v) - { - #ifdef MUP_MATH_EXCEPTIONS - if (v<=0) - throw ParserError(ecDOMAIN_ERROR, _T("Log10")); - #endif - - return MathImpl::Log10(v); - } +// Logarithm base 2 +value_type Parser::Log2(value_type v) +{ +#ifdef MUP_MATH_EXCEPTIONS + if (v <= 0) + throw ParserError(ecDOMAIN_ERROR, _T("Log2")); +#endif + + return MathImpl::Log2(v); +} + +// Logarithm base 10 +value_type Parser::Log10(value_type v) +{ +#ifdef MUP_MATH_EXCEPTIONS + if (v <= 0) + throw ParserError(ecDOMAIN_ERROR, _T("Log10")); +#endif + + return MathImpl::Log10(v); +} // Logarithm base e (natural logarithm) - value_type Parser::Ln(value_type v) - { - #ifdef MUP_MATH_EXCEPTIONS - if (v<=0) - throw ParserError(ecDOMAIN_ERROR, _T("Ln")); - #endif - - return MathImpl::Log(v); - } - - //--------------------------------------------------------------------------- - // misc - value_type Parser::Exp(value_type v) { return MathImpl::Exp(v); } - value_type Parser::Abs(value_type v) { return MathImpl::Abs(v); } - value_type Parser::Sqrt(value_type v) - { - #ifdef MUP_MATH_EXCEPTIONS - if (v<0) - throw ParserError(ecDOMAIN_ERROR, _T("sqrt")); - #endif - - return MathImpl::Sqrt(v); - } - value_type Parser::Rint(value_type v) { return MathImpl::Rint(v); } - value_type Parser::Sign(value_type v) { return MathImpl::Sign(v); } - - //--------------------------------------------------------------------------- - /** \brief Callback for the unary minus operator. - \param v The value to negate - \return -v - */ - value_type Parser::UnaryMinus(value_type v) - { - return -v; - } - - //--------------------------------------------------------------------------- - /** \brief Callback for the unary minus operator. - \param v The value to negate - \return -v - */ - value_type Parser::UnaryPlus(value_type v) - { - return v; - } - - //--------------------------------------------------------------------------- - /** \brief Callback for adding multiple values. - \param [in] a_afArg Vector with the function arguments - \param [in] a_iArgc The size of a_afArg - */ - value_type Parser::Sum(const value_type *a_afArg, int a_iArgc) - { - if (!a_iArgc) - throw exception_type(_T("too few arguments for function sum.")); - - value_type fRes=0; - for (int i=0; i::Log(v); +} + +//--------------------------------------------------------------------------- +// misc +value_type Parser::Exp(value_type v) +{ + return MathImpl::Exp(v); +} +value_type Parser::Abs(value_type v) +{ + return MathImpl::Abs(v); +} +value_type Parser::Sqrt(value_type v) +{ +#ifdef MUP_MATH_EXCEPTIONS + if (v < 0) + throw ParserError(ecDOMAIN_ERROR, _T("sqrt")); +#endif + + return MathImpl::Sqrt(v); +} +value_type Parser::Rint(value_type v) +{ + return MathImpl::Rint(v); +} +value_type Parser::Sign(value_type v) +{ + return MathImpl::Sign(v); +} +//--------------------------------------------------------------------------- +/** \brief Callback for the unary minus operator. + \param v The value to negate + \return -v +*/ +value_type Parser::UnaryMinus(value_type v) +{ + return -v; +} + +//--------------------------------------------------------------------------- +/** \brief Callback for the unary minus operator. + \param v The value to negate + \return -v +*/ +value_type Parser::UnaryPlus(value_type v) +{ + return v; +} + +//--------------------------------------------------------------------------- +/** \brief Callback for adding multiple values. + \param [in] a_afArg Vector with the function arguments + \param [in] a_iArgc The size of a_afArg +*/ +value_type Parser::Sum(const value_type* a_afArg, int a_iArgc) +{ + if (!a_iArgc) + throw exception_type(_T("too few arguments for function sum.")); + + value_type fRes = 0; + for (int i = 0; i < a_iArgc; ++i) + fRes += a_afArg[i]; return fRes; - } +} +//--------------------------------------------------------------------------- +/** \brief Callback for averaging multiple values. + \param [in] a_afArg Vector with the function arguments + \param [in] a_iArgc The size of a_afArg +*/ +value_type Parser::Avg(const value_type* a_afArg, int a_iArgc) +{ + if (!a_iArgc) + throw exception_type(_T("too few arguments for function sum.")); + + value_type fRes = 0; + for (int i = 0; i < a_iArgc; ++i) + fRes += a_afArg[i]; + return fRes / (value_type)a_iArgc; +} + +//--------------------------------------------------------------------------- +/** \brief Callback for determining the minimum value out of a vector. + \param [in] a_afArg Vector with the function arguments + \param [in] a_iArgc The size of a_afArg +*/ +value_type Parser::Min(const value_type* a_afArg, int a_iArgc) +{ + if (!a_iArgc) + throw exception_type(_T("too few arguments for function min.")); - //--------------------------------------------------------------------------- - /** \brief Callback for determining the maximum value out of a vector. - \param [in] a_afArg Vector with the function arguments - \param [in] a_iArgc The size of a_afArg - */ - value_type Parser::Max(const value_type *a_afArg, int a_iArgc) - { - if (!a_iArgc) - throw exception_type(_T("too few arguments for function min.")); + value_type fRes = a_afArg[0]; + for (int i = 0; i < a_iArgc; ++i) + fRes = std::min(fRes, a_afArg[i]); + + return fRes; +} + +//--------------------------------------------------------------------------- +/** \brief Callback for determining the maximum value out of a vector. + \param [in] a_afArg Vector with the function arguments + \param [in] a_iArgc The size of a_afArg +*/ +value_type Parser::Max(const value_type* a_afArg, int a_iArgc) +{ + if (!a_iArgc) + throw exception_type(_T("too few arguments for function min.")); - value_type fRes=a_afArg[0]; - for (int i=0; i> fVal; stringstream_type::pos_type iEnd = stream.tellg(); // Position after reading - if (iEnd==(stringstream_type::pos_type)-1) - return 0; + if (iEnd == (stringstream_type::pos_type)-1) + return 0; *a_iPos += (int)iEnd; *a_fVal = fVal; return 1; - } +} +//--------------------------------------------------------------------------- +/** \brief Constructor. - //--------------------------------------------------------------------------- - /** \brief Constructor. - - Call ParserBase class constructor and trigger Function, Operator and Constant initialization. - */ - Parser::Parser() - :ParserBase() - { + Call ParserBase class constructor and trigger Function, Operator and Constant initialization. +*/ +Parser::Parser() : ParserBase() +{ AddValIdent(IsVal); InitCharSets(); InitFun(); InitConst(); InitOprt(); - } - - //--------------------------------------------------------------------------- - /** \brief Define the character sets. - \sa DefineNameChars, DefineOprtChars, DefineInfixOprtChars - - This function is used for initializing the default character sets that define - the characters to be useable in function and variable names and operators. - */ - void Parser::InitCharSets() - { - DefineNameChars( _T("0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") ); - DefineOprtChars( _T("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+-*^/?<>=#!$%&|~'_{}") ); - DefineInfixOprtChars( _T("/+-*^?<>=#!$%&|~'_") ); - } - - //--------------------------------------------------------------------------- - /** \brief Initialize the default functions. */ - void Parser::InitFun() - { +} + +//--------------------------------------------------------------------------- +/** \brief Define the character sets. + \sa DefineNameChars, DefineOprtChars, DefineInfixOprtChars + + This function is used for initializing the default character sets that define + the characters to be useable in function and variable names and operators. +*/ +void Parser::InitCharSets() +{ + DefineNameChars(_T("0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")); + DefineOprtChars(_T("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+-*^/?<>=#!$%&|~'_{}")); + DefineInfixOprtChars(_T("/+-*^?<>=#!$%&|~'_")); +} + +//--------------------------------------------------------------------------- +/** \brief Initialize the default functions. */ +void Parser::InitFun() +{ if (mu::TypeInfo::IsInteger()) { - // When setting MUP_BASETYPE to an integer type - // Place functions for dealing with integer values here - // ... - // ... - // ... + // When setting MUP_BASETYPE to an integer type + // Place functions for dealing with integer values here + // ... + // ... + // ... } else { - // trigonometric functions - DefineFun(_T("sin"), Sin); - DefineFun(_T("cos"), Cos); - DefineFun(_T("tan"), Tan); - // arcus functions - DefineFun(_T("asin"), ASin); - DefineFun(_T("acos"), ACos); - DefineFun(_T("atan"), ATan); - DefineFun(_T("atan2"), ATan2); - // hyperbolic functions - DefineFun(_T("sinh"), Sinh); - DefineFun(_T("cosh"), Cosh); - DefineFun(_T("tanh"), Tanh); - // arcus hyperbolic functions - DefineFun(_T("asinh"), ASinh); - DefineFun(_T("acosh"), ACosh); - DefineFun(_T("atanh"), ATanh); - // Logarithm functions - DefineFun(_T("log2"), Log2); - DefineFun(_T("log10"), Log10); - DefineFun(_T("log"), Ln); - DefineFun(_T("ln"), Ln); - // misc - DefineFun(_T("exp"), Exp); - DefineFun(_T("sqrt"), Sqrt); - DefineFun(_T("sign"), Sign); - DefineFun(_T("rint"), Rint); - DefineFun(_T("abs"), Abs); - // Functions with variable number of arguments - DefineFun(_T("sum"), Sum); - DefineFun(_T("avg"), Avg); - DefineFun(_T("min"), Min); - DefineFun(_T("max"), Max); + // trigonometric functions + DefineFun(_T("sin"), Sin); + DefineFun(_T("cos"), Cos); + DefineFun(_T("tan"), Tan); + // arcus functions + DefineFun(_T("asin"), ASin); + DefineFun(_T("acos"), ACos); + DefineFun(_T("atan"), ATan); + DefineFun(_T("atan2"), ATan2); + // hyperbolic functions + DefineFun(_T("sinh"), Sinh); + DefineFun(_T("cosh"), Cosh); + DefineFun(_T("tanh"), Tanh); + // arcus hyperbolic functions + DefineFun(_T("asinh"), ASinh); + DefineFun(_T("acosh"), ACosh); + DefineFun(_T("atanh"), ATanh); + // Logarithm functions + DefineFun(_T("log2"), Log2); + DefineFun(_T("log10"), Log10); + DefineFun(_T("log"), Ln); + DefineFun(_T("ln"), Ln); + // misc + DefineFun(_T("exp"), Exp); + DefineFun(_T("sqrt"), Sqrt); + DefineFun(_T("sign"), Sign); + DefineFun(_T("rint"), Rint); + DefineFun(_T("abs"), Abs); + // Functions with variable number of arguments + DefineFun(_T("sum"), Sum); + DefineFun(_T("avg"), Avg); + DefineFun(_T("min"), Min); + DefineFun(_T("max"), Max); } - } - - //--------------------------------------------------------------------------- - /** \brief Initialize constants. - - By default the parser recognizes two constants. Pi ("pi") and the Eulerian - number ("_e"). - */ - void Parser::InitConst() - { +} + +//--------------------------------------------------------------------------- +/** \brief Initialize constants. + + By default the parser recognizes two constants. Pi ("pi") and the Eulerian + number ("_e"). +*/ +void Parser::InitConst() +{ DefineConst(_T("_pi"), (value_type)PARSER_CONST_PI); DefineConst(_T("_e"), (value_type)PARSER_CONST_E); - } - - //--------------------------------------------------------------------------- - /** \brief Initialize operators. - - By default only the unary minus operator is added. - */ - void Parser::InitOprt() - { +} + +//--------------------------------------------------------------------------- +/** \brief Initialize operators. + + By default only the unary minus operator is added. +*/ +void Parser::InitOprt() +{ DefineInfixOprt(_T("-"), UnaryMinus); DefineInfixOprt(_T("+"), UnaryPlus); - } +} - //--------------------------------------------------------------------------- - void Parser::OnDetectVar(string_type * /*pExpr*/, int & /*nStart*/, int & /*nEnd*/) - { +//--------------------------------------------------------------------------- +void Parser::OnDetectVar(string_type* /*pExpr*/, int& /*nStart*/, int& /*nEnd*/) +{ // this is just sample code to illustrate modifying variable names on the fly. // I'm not sure anyone really needs such a feature... /* @@ -343,7 +388,7 @@ namespace mu string sVar(pExpr->begin()+nStart, pExpr->begin()+nEnd); string sRepl = std::string("_") + sVar + "_"; - + int nOrigVarEnd = nEnd; cout << "variable detected!\n"; cout << " Expr: " << *pExpr << "\n"; @@ -356,42 +401,41 @@ namespace mu pExpr->replace(pExpr->begin()+nStart, pExpr->begin()+nOrigVarEnd, sRepl); cout << " New expr: " << *pExpr << "\n"; */ - } - - //--------------------------------------------------------------------------- - /** \brief Numerically differentiate with regard to a variable. - \param [in] a_Var Pointer to the differentiation variable. - \param [in] a_fPos Position at which the differentiation should take place. - \param [in] a_fEpsilon Epsilon used for the numerical differentiation. - - Numerical differentiation uses a 5 point operator yielding a 4th order - formula. The default value for epsilon is 0.00074 which is - numeric_limits::epsilon() ^ (1/5) as suggested in the muparser - forum: - - http://sourceforge.net/forum/forum.php?thread_id=1994611&forum_id=462843 - */ - value_type Parser::Diff(value_type *a_Var, - value_type a_fPos, - value_type a_fEpsilon) const - { - value_type fRes(0), - fBuf(*a_Var), - f[4] = {0,0,0,0}, - fEpsilon(a_fEpsilon); +} + +//--------------------------------------------------------------------------- +/** \brief Numerically differentiate with regard to a variable. + \param [in] a_Var Pointer to the differentiation variable. + \param [in] a_fPos Position at which the differentiation should take place. + \param [in] a_fEpsilon Epsilon used for the numerical differentiation. + + Numerical differentiation uses a 5 point operator yielding a 4th order + formula. The default value for epsilon is 0.00074 which is + numeric_limits::epsilon() ^ (1/5) as suggested in the muparser + forum: + + http://sourceforge.net/forum/forum.php?thread_id=1994611&forum_id=462843 +*/ +value_type Parser::Diff(value_type* a_Var, value_type a_fPos, value_type a_fEpsilon) const +{ + value_type fRes(0), fBuf(*a_Var), f[4] = {0, 0, 0, 0}, fEpsilon(a_fEpsilon); // Backwards compatible calculation of epsilon inc case the user doesn't provide // his own epsilon - if (fEpsilon==0) - fEpsilon = (a_fPos==0) ? (value_type)1e-10 : (value_type)1e-7 * a_fPos; - - *a_Var = a_fPos+2 * fEpsilon; f[0] = Eval(); - *a_Var = a_fPos+1 * fEpsilon; f[1] = Eval(); - *a_Var = a_fPos-1 * fEpsilon; f[2] = Eval(); - *a_Var = a_fPos-2 * fEpsilon; f[3] = Eval(); + if (fEpsilon == 0) + fEpsilon = (a_fPos == 0) ? (value_type)1e-10 : (value_type)1e-7 * a_fPos; + + *a_Var = a_fPos + 2 * fEpsilon; + f[0] = Eval(); + *a_Var = a_fPos + 1 * fEpsilon; + f[1] = Eval(); + *a_Var = a_fPos - 1 * fEpsilon; + f[2] = Eval(); + *a_Var = a_fPos - 2 * fEpsilon; + f[3] = Eval(); *a_Var = fBuf; // restore variable - fRes = (-f[0] + 8*f[1] - 8*f[2] + f[3]) / (12*fEpsilon); + fRes = (-f[0] + 8 * f[1] - 8 * f[2] + f[3]) / (12 * fEpsilon); return fRes; - } +} } // namespace mu diff --git a/ext_libs/muparser/muParser.h b/ext_libs/muparser/muParser.h old mode 100755 new mode 100644 index 39fe137f..c864a93f --- a/ext_libs/muparser/muParser.h +++ b/ext_libs/muparser/muParser.h @@ -1,26 +1,26 @@ /* - __________ - _____ __ __\______ \_____ _______ ______ ____ _______ + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ - |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| - \/ \/ \/ \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ Copyright (C) 2013 Ingo Berg - Permission is hereby granted, free of charge, to any person obtaining a copy of this + 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 + 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 + 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. + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MU_PARSER_H #define MU_PARSER_H @@ -38,78 +38,73 @@ namespace mu { - /** \brief Mathematical expressions parser. - - Standard implementation of the mathematical expressions parser. - Can be used as a reference implementation for subclassing the parser. - - - (C) 2011 Ingo Berg
- muparser(at)beltoforion.de -
- */ - /* final */ class Parser : public ParserBase - { - public: +/** \brief Mathematical expressions parser. + Standard implementation of the mathematical expressions parser. + Can be used as a reference implementation for subclassing the parser. + + + (C) 2011 Ingo Berg
+ muparser(at)beltoforion.de +
+*/ +/* final */ class Parser : public ParserBase +{ +public: Parser(); virtual void InitCharSets(); virtual void InitFun(); virtual void InitConst(); virtual void InitOprt(); - virtual void OnDetectVar(string_type *pExpr, int &nStart, int &nEnd); + virtual void OnDetectVar(string_type* pExpr, int& nStart, int& nEnd); - value_type Diff(value_type *a_Var, - value_type a_fPos, - value_type a_fEpsilon = 0) const; - - protected: + value_type Diff(value_type* a_Var, value_type a_fPos, value_type a_fEpsilon = 0) const; +protected: // Trigonometric functions - static value_type Sin(value_type); - static value_type Cos(value_type); - static value_type Tan(value_type); - static value_type Tan2(value_type, value_type); + static value_type Sin(value_type); + static value_type Cos(value_type); + static value_type Tan(value_type); + static value_type Tan2(value_type, value_type); // arcus functions - static value_type ASin(value_type); - static value_type ACos(value_type); - static value_type ATan(value_type); - static value_type ATan2(value_type, value_type); + static value_type ASin(value_type); + static value_type ACos(value_type); + static value_type ATan(value_type); + static value_type ATan2(value_type, value_type); // hyperbolic functions - static value_type Sinh(value_type); - static value_type Cosh(value_type); - static value_type Tanh(value_type); + static value_type Sinh(value_type); + static value_type Cosh(value_type); + static value_type Tanh(value_type); // arcus hyperbolic functions - static value_type ASinh(value_type); - static value_type ACosh(value_type); - static value_type ATanh(value_type); + static value_type ASinh(value_type); + static value_type ACosh(value_type); + static value_type ATanh(value_type); // Logarithm functions - static value_type Log2(value_type); // Logarithm Base 2 - static value_type Log10(value_type); // Logarithm Base 10 - static value_type Ln(value_type); // Logarithm Base e (natural logarithm) + static value_type Log2(value_type); // Logarithm Base 2 + static value_type Log10(value_type); // Logarithm Base 10 + static value_type Ln(value_type); // Logarithm Base e (natural logarithm) // misc - static value_type Exp(value_type); - static value_type Abs(value_type); - static value_type Sqrt(value_type); - static value_type Rint(value_type); - static value_type Sign(value_type); + static value_type Exp(value_type); + static value_type Abs(value_type); + static value_type Sqrt(value_type); + static value_type Rint(value_type); + static value_type Sign(value_type); // Prefix operators // !!! Unary Minus is a MUST if you want to use negative signs !!! - static value_type UnaryMinus(value_type); - static value_type UnaryPlus(value_type); + static value_type UnaryMinus(value_type); + static value_type UnaryPlus(value_type); // Functions with variable number of arguments - static value_type Sum(const value_type*, int); // sum - static value_type Avg(const value_type*, int); // mean value - static value_type Min(const value_type*, int); // minimum - static value_type Max(const value_type*, int); // maximum + static value_type Sum(const value_type*, int); // sum + static value_type Avg(const value_type*, int); // mean value + static value_type Min(const value_type*, int); // minimum + static value_type Max(const value_type*, int); // maximum - static int IsVal(const char_type* a_szExpr, int *a_iPos, value_type *a_fVal); - }; + static int IsVal(const char_type* a_szExpr, int* a_iPos, value_type* a_fVal); +}; } // namespace mu #endif - diff --git a/ext_libs/muparser/muParserBase.cpp b/ext_libs/muparser/muParserBase.cpp old mode 100755 new mode 100644 index b5e17aa4..773b0627 --- a/ext_libs/muparser/muParserBase.cpp +++ b/ext_libs/muparser/muParserBase.cpp @@ -1,26 +1,26 @@ /* - __________ - _____ __ __\______ \_____ _______ ______ ____ _______ + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ - |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| - \/ \/ \/ \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ Copyright (C) 2011 Ingo Berg - Permission is hereby granted, free of charge, to any person obtaining a copy of this + 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 + 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 + 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. + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "muParserBase.h" @@ -37,7 +37,7 @@ #include #ifdef MUP_USE_OPENMP - #include +#include #endif using namespace std; @@ -48,128 +48,121 @@ using namespace std; namespace mu { - std::locale ParserBase::s_locale = std::locale(std::locale::classic(), new change_dec_sep('.')); - - bool ParserBase::g_DbgDumpCmdCode = false; - bool ParserBase::g_DbgDumpStack = false; - - //------------------------------------------------------------------------------ - /** \brief Identifiers for built in binary operators. - - When defining custom binary operators with #AddOprt(...) make sure not to choose - names conflicting with these definitions. - */ - const char_type* ParserBase::c_DefaultOprt[] = - { - _T("<="), _T(">="), _T("!="), - _T("=="), _T("<"), _T(">"), - _T("+"), _T("-"), _T("*"), - _T("/"), _T("^"), _T("&&"), - _T("||"), _T("="), _T("("), - _T(")"), _T("?"), _T(":"), 0 - }; - - //------------------------------------------------------------------------------ - /** \brief Constructor. - \param a_szFormula the formula to interpret. - \throw ParserException if a_szFormula is null. - */ - ParserBase::ParserBase() - :m_pParseFormula(&ParserBase::ParseString) - ,m_vRPN() - ,m_vStringBuf() - ,m_pTokenReader() - ,m_FunDef() - ,m_PostOprtDef() - ,m_InfixOprtDef() - ,m_OprtDef() - ,m_ConstDef() - ,m_StrVarDef() - ,m_VarDef() - ,m_bBuiltInOp(true) - ,m_sNameChars() - ,m_sOprtChars() - ,m_sInfixOprtChars() - ,m_nIfElseCounter(0) - ,m_vStackBuffer() - ,m_nFinalResultIdx(0) - { +std::locale ParserBase::s_locale = std::locale(std::locale::classic(), new change_dec_sep('.')); + +bool ParserBase::g_DbgDumpCmdCode = false; +bool ParserBase::g_DbgDumpStack = false; + +//------------------------------------------------------------------------------ +/** \brief Identifiers for built in binary operators. + + When defining custom binary operators with #AddOprt(...) make sure not to choose + names conflicting with these definitions. +*/ +const char_type* ParserBase::c_DefaultOprt[] = {_T("<="), _T(">="), _T("!="), _T("=="), _T("<"), _T(">"), _T("+"), + _T("-"), _T("*"), _T("/"), _T("^"), _T("&&"), _T("||"), _T("="), + _T("("), _T(")"), _T("?"), _T(":"), 0}; + +//------------------------------------------------------------------------------ +/** \brief Constructor. + \param a_szFormula the formula to interpret. + \throw ParserException if a_szFormula is null. +*/ +ParserBase::ParserBase() : + m_pParseFormula(&ParserBase::ParseString), + m_vRPN(), + m_vStringBuf(), + m_pTokenReader(), + m_FunDef(), + m_PostOprtDef(), + m_InfixOprtDef(), + m_OprtDef(), + m_ConstDef(), + m_StrVarDef(), + m_VarDef(), + m_bBuiltInOp(true), + m_sNameChars(), + m_sOprtChars(), + m_sInfixOprtChars(), + m_nIfElseCounter(0), + m_vStackBuffer(), + m_nFinalResultIdx(0) +{ InitTokenReader(); - } - - //--------------------------------------------------------------------------- - /** \brief Copy constructor. - - The parser can be safely copy constructed but the bytecode is reset during - copy construction. - */ - ParserBase::ParserBase(const ParserBase &a_Parser) - :m_pParseFormula(&ParserBase::ParseString) - ,m_vRPN() - ,m_vStringBuf() - ,m_pTokenReader() - ,m_FunDef() - ,m_PostOprtDef() - ,m_InfixOprtDef() - ,m_OprtDef() - ,m_ConstDef() - ,m_StrVarDef() - ,m_VarDef() - ,m_bBuiltInOp(true) - ,m_sNameChars() - ,m_sOprtChars() - ,m_sInfixOprtChars() - ,m_nIfElseCounter(0) - { +} + +//--------------------------------------------------------------------------- +/** \brief Copy constructor. + + The parser can be safely copy constructed but the bytecode is reset during + copy construction. +*/ +ParserBase::ParserBase(const ParserBase& a_Parser) : + m_pParseFormula(&ParserBase::ParseString), + m_vRPN(), + m_vStringBuf(), + m_pTokenReader(), + m_FunDef(), + m_PostOprtDef(), + m_InfixOprtDef(), + m_OprtDef(), + m_ConstDef(), + m_StrVarDef(), + m_VarDef(), + m_bBuiltInOp(true), + m_sNameChars(), + m_sOprtChars(), + m_sInfixOprtChars(), + m_nIfElseCounter(0) +{ m_pTokenReader.reset(new token_reader_type(this)); Assign(a_Parser); - } +} - //--------------------------------------------------------------------------- - ParserBase::~ParserBase() - {} +//--------------------------------------------------------------------------- +ParserBase::~ParserBase() {} - //--------------------------------------------------------------------------- - /** \brief Assignment operator. +//--------------------------------------------------------------------------- +/** \brief Assignment operator. - Implemented by calling Assign(a_Parser). Self assignment is suppressed. - \param a_Parser Object to copy to this. - \return *this - \throw nothrow - */ - ParserBase& ParserBase::operator=(const ParserBase &a_Parser) - { + Implemented by calling Assign(a_Parser). Self assignment is suppressed. + \param a_Parser Object to copy to this. + \return *this + \throw nothrow +*/ +ParserBase& ParserBase::operator=(const ParserBase& a_Parser) +{ Assign(a_Parser); return *this; - } +} - //--------------------------------------------------------------------------- - /** \brief Copy state of a parser object to this. +//--------------------------------------------------------------------------- +/** \brief Copy state of a parser object to this. - Clears Variables and Functions of this parser. - Copies the states of all internal variables. - Resets parse function to string parse mode. + Clears Variables and Functions of this parser. + Copies the states of all internal variables. + Resets parse function to string parse mode. - \param a_Parser the source object. - */ - void ParserBase::Assign(const ParserBase &a_Parser) - { - if (&a_Parser==this) - return; + \param a_Parser the source object. +*/ +void ParserBase::Assign(const ParserBase& a_Parser) +{ + if (&a_Parser == this) + return; // Don't copy bytecode instead cause the parser to create new bytecode // by resetting the parse function. ReInit(); - m_ConstDef = a_Parser.m_ConstDef; // Copy user define constants - m_VarDef = a_Parser.m_VarDef; // Copy user defined variables - m_bBuiltInOp = a_Parser.m_bBuiltInOp; - m_vStringBuf = a_Parser.m_vStringBuf; - m_vStackBuffer = a_Parser.m_vStackBuffer; + m_ConstDef = a_Parser.m_ConstDef; // Copy user define constants + m_VarDef = a_Parser.m_VarDef; // Copy user defined variables + m_bBuiltInOp = a_Parser.m_bBuiltInOp; + m_vStringBuf = a_Parser.m_vStringBuf; + m_vStackBuffer = a_Parser.m_vStackBuffer; m_nFinalResultIdx = a_Parser.m_nFinalResultIdx; - m_StrVarDef = a_Parser.m_StrVarDef; - m_vStringVarBuf = a_Parser.m_vStringVarBuf; - m_nIfElseCounter = a_Parser.m_nIfElseCounter; + m_StrVarDef = a_Parser.m_StrVarDef; + m_vStringVarBuf = a_Parser.m_vStringVarBuf; + m_nIfElseCounter = a_Parser.m_nIfElseCounter; m_pTokenReader.reset(a_Parser.m_pTokenReader->Clone(this)); // Copy function and operator callbacks @@ -181,622 +174,634 @@ namespace mu m_sNameChars = a_Parser.m_sNameChars; m_sOprtChars = a_Parser.m_sOprtChars; m_sInfixOprtChars = a_Parser.m_sInfixOprtChars; - } - - //--------------------------------------------------------------------------- - /** \brief Set the decimal separator. - \param cDecSep Decimal separator as a character value. - \sa SetThousandsSep - - By default muparser uses the "C" locale. The decimal separator of this - locale is overwritten by the one provided here. - */ - void ParserBase::SetDecSep(char_type cDecSep) - { - char_type cThousandsSep = std::use_facet< change_dec_sep >(s_locale).thousands_sep(); +} + +//--------------------------------------------------------------------------- +/** \brief Set the decimal separator. + \param cDecSep Decimal separator as a character value. + \sa SetThousandsSep + + By default muparser uses the "C" locale. The decimal separator of this + locale is overwritten by the one provided here. +*/ +void ParserBase::SetDecSep(char_type cDecSep) +{ + char_type cThousandsSep = std::use_facet >(s_locale).thousands_sep(); s_locale = std::locale(std::locale("C"), new change_dec_sep(cDecSep, cThousandsSep)); - } - - //--------------------------------------------------------------------------- - /** \brief Sets the thousands operator. - \param cThousandsSep The thousands separator as a character - \sa SetDecSep - - By default muparser uses the "C" locale. The thousands separator of this - locale is overwritten by the one provided here. - */ - void ParserBase::SetThousandsSep(char_type cThousandsSep) - { - char_type cDecSep = std::use_facet< change_dec_sep >(s_locale).decimal_point(); +} + +//--------------------------------------------------------------------------- +/** \brief Sets the thousands operator. + \param cThousandsSep The thousands separator as a character + \sa SetDecSep + + By default muparser uses the "C" locale. The thousands separator of this + locale is overwritten by the one provided here. +*/ +void ParserBase::SetThousandsSep(char_type cThousandsSep) +{ + char_type cDecSep = std::use_facet >(s_locale).decimal_point(); s_locale = std::locale(std::locale("C"), new change_dec_sep(cDecSep, cThousandsSep)); - } +} - //--------------------------------------------------------------------------- - /** \brief Resets the locale. +//--------------------------------------------------------------------------- +/** \brief Resets the locale. - The default locale used "." as decimal separator, no thousands separator and - "," as function argument separator. - */ - void ParserBase::ResetLocale() - { + The default locale used "." as decimal separator, no thousands separator and + "," as function argument separator. +*/ +void ParserBase::ResetLocale() +{ s_locale = std::locale(std::locale("C"), new change_dec_sep('.')); SetArgSep(','); - } +} - //--------------------------------------------------------------------------- - /** \brief Initialize the token reader. +//--------------------------------------------------------------------------- +/** \brief Initialize the token reader. - Create new token reader object and submit pointers to function, operator, - constant and variable definitions. + Create new token reader object and submit pointers to function, operator, + constant and variable definitions. - \post m_pTokenReader.get()!=0 - \throw nothrow - */ - void ParserBase::InitTokenReader() - { + \post m_pTokenReader.get()!=0 + \throw nothrow +*/ +void ParserBase::InitTokenReader() +{ m_pTokenReader.reset(new token_reader_type(this)); - } +} - //--------------------------------------------------------------------------- - /** \brief Reset parser to string parsing mode and clear internal buffers. +//--------------------------------------------------------------------------- +/** \brief Reset parser to string parsing mode and clear internal buffers. - Clear bytecode, reset the token reader. - \throw nothrow - */ - void ParserBase::ReInit() const - { + Clear bytecode, reset the token reader. + \throw nothrow +*/ +void ParserBase::ReInit() const +{ m_pParseFormula = &ParserBase::ParseString; m_vStringBuf.clear(); m_vRPN.clear(); m_pTokenReader->ReInit(); m_nIfElseCounter = 0; - } - - //--------------------------------------------------------------------------- - void ParserBase::OnDetectVar(string_type * /*pExpr*/, int & /*nStart*/, int & /*nEnd*/) - {} - - //--------------------------------------------------------------------------- - /** \brief Returns the version of muparser. - \param eInfo A flag indicating whether the full version info should be - returned or not. - - Format is as follows: "MAJOR.MINOR (COMPILER_FLAGS)" The COMPILER_FLAGS - are returned only if eInfo==pviFULL. - */ - string_type ParserBase::GetVersion(EParserVersionInfo eInfo) const - { +} + +//--------------------------------------------------------------------------- +void ParserBase::OnDetectVar(string_type* /*pExpr*/, int& /*nStart*/, int& /*nEnd*/) {} + +//--------------------------------------------------------------------------- +/** \brief Returns the version of muparser. + \param eInfo A flag indicating whether the full version info should be + returned or not. + + Format is as follows: "MAJOR.MINOR (COMPILER_FLAGS)" The COMPILER_FLAGS + are returned only if eInfo==pviFULL. +*/ +string_type ParserBase::GetVersion(EParserVersionInfo eInfo) const +{ stringstream_type ss; ss << MUP_VERSION; - if (eInfo==pviFULL) + if (eInfo == pviFULL) { - ss << _T(" (") << MUP_VERSION_DATE; - ss << std::dec << _T("; ") << sizeof(void*)*8 << _T("BIT"); + ss << _T(" (") << MUP_VERSION_DATE; + ss << std::dec << _T("; ") << sizeof(void*) * 8 << _T("BIT"); #ifdef _DEBUG - ss << _T("; DEBUG"); -#else - ss << _T("; RELEASE"); + ss << _T("; DEBUG"); +#else + ss << _T("; RELEASE"); #endif #ifdef _UNICODE - ss << _T("; UNICODE"); + ss << _T("; UNICODE"); #else - #ifdef _MBCS - ss << _T("; MBCS"); - #else - ss << _T("; ASCII"); - #endif +#ifdef _MBCS + ss << _T("; MBCS"); +#else + ss << _T("; ASCII"); +#endif #endif #ifdef MUP_USE_OPENMP - ss << _T("; OPENMP"); + ss << _T("; OPENMP"); //#else // ss << _T("; NO_OPENMP"); #endif #if defined(MUP_MATH_EXCEPTIONS) - ss << _T("; MATHEXC"); + ss << _T("; MATHEXC"); //#else // ss << _T("; NO_MATHEXC"); #endif - ss << _T(")"); + ss << _T(")"); } return ss.str(); - } - - //--------------------------------------------------------------------------- - /** \brief Add a value parsing function. - - When parsing an expression muParser tries to detect values in the expression - string using different valident callbacks. Thus it's possible to parse - for hex values, binary values and floating point values. - */ - void ParserBase::AddValIdent(identfun_type a_pCallback) - { +} + +//--------------------------------------------------------------------------- +/** \brief Add a value parsing function. + + When parsing an expression muParser tries to detect values in the expression + string using different valident callbacks. Thus it's possible to parse + for hex values, binary values and floating point values. +*/ +void ParserBase::AddValIdent(identfun_type a_pCallback) +{ m_pTokenReader->AddValIdent(a_pCallback); - } - - //--------------------------------------------------------------------------- - /** \brief Set a function that can create variable pointer for unknown expression variables. - \param a_pFactory A pointer to the variable factory. - \param pUserData A user defined context pointer. - */ - void ParserBase::SetVarFactory(facfun_type a_pFactory, void *pUserData) - { - m_pTokenReader->SetVarCreator(a_pFactory, pUserData); - } - - //--------------------------------------------------------------------------- - /** \brief Add a function or operator callback to the parser. */ - void ParserBase::AddCallback( const string_type &a_strName, - const ParserCallback &a_Callback, - funmap_type &a_Storage, - const char_type *a_szCharSet ) - { - if (a_Callback.GetAddr()==0) +} + +//--------------------------------------------------------------------------- +/** \brief Set a function that can create variable pointer for unknown expression variables. + \param a_pFactory A pointer to the variable factory. + \param pUserData A user defined context pointer. +*/ +void ParserBase::SetVarFactory(facfun_type a_pFactory, void* pUserData) +{ + m_pTokenReader->SetVarCreator(a_pFactory, pUserData); +} + +//--------------------------------------------------------------------------- +/** \brief Add a function or operator callback to the parser. */ +void ParserBase::AddCallback(const string_type& a_strName, + const ParserCallback& a_Callback, + funmap_type& a_Storage, + const char_type* a_szCharSet) +{ + if (a_Callback.GetAddr() == 0) Error(ecINVALID_FUN_PTR); - const funmap_type *pFunMap = &a_Storage; + const funmap_type* pFunMap = &a_Storage; // Check for conflicting operator or function names - if ( pFunMap!=&m_FunDef && m_FunDef.find(a_strName)!=m_FunDef.end() ) - Error(ecNAME_CONFLICT, -1, a_strName); + if (pFunMap != &m_FunDef && m_FunDef.find(a_strName) != m_FunDef.end()) + Error(ecNAME_CONFLICT, -1, a_strName); - if ( pFunMap!=&m_PostOprtDef && m_PostOprtDef.find(a_strName)!=m_PostOprtDef.end() ) - Error(ecNAME_CONFLICT, -1, a_strName); + if (pFunMap != &m_PostOprtDef && m_PostOprtDef.find(a_strName) != m_PostOprtDef.end()) + Error(ecNAME_CONFLICT, -1, a_strName); - if ( pFunMap!=&m_InfixOprtDef && pFunMap!=&m_OprtDef && m_InfixOprtDef.find(a_strName)!=m_InfixOprtDef.end() ) - Error(ecNAME_CONFLICT, -1, a_strName); + if (pFunMap != &m_InfixOprtDef && pFunMap != &m_OprtDef && m_InfixOprtDef.find(a_strName) != m_InfixOprtDef.end()) + Error(ecNAME_CONFLICT, -1, a_strName); - if ( pFunMap!=&m_InfixOprtDef && pFunMap!=&m_OprtDef && m_OprtDef.find(a_strName)!=m_OprtDef.end() ) - Error(ecNAME_CONFLICT, -1, a_strName); + if (pFunMap != &m_InfixOprtDef && pFunMap != &m_OprtDef && m_OprtDef.find(a_strName) != m_OprtDef.end()) + Error(ecNAME_CONFLICT, -1, a_strName); CheckOprt(a_strName, a_Callback, a_szCharSet); a_Storage[a_strName] = a_Callback; ReInit(); - } - - //--------------------------------------------------------------------------- - /** \brief Check if a name contains invalid characters. - - \throw ParserException if the name contains invalid characters. - */ - void ParserBase::CheckOprt(const string_type &a_sName, - const ParserCallback &a_Callback, - const string_type &a_szCharSet) const - { - if ( !a_sName.length() || - (a_sName.find_first_not_of(a_szCharSet)!=string_type::npos) || - (a_sName[0]>='0' && a_sName[0]<='9')) +} + +//--------------------------------------------------------------------------- +/** \brief Check if a name contains invalid characters. + + \throw ParserException if the name contains invalid characters. +*/ +void ParserBase::CheckOprt(const string_type& a_sName, + const ParserCallback& a_Callback, + const string_type& a_szCharSet) const +{ + if (!a_sName.length() || (a_sName.find_first_not_of(a_szCharSet) != string_type::npos) || + (a_sName[0] >= '0' && a_sName[0] <= '9')) { - switch(a_Callback.GetCode()) - { - case cmOPRT_POSTFIX: Error(ecINVALID_POSTFIX_IDENT, -1, a_sName); - case cmOPRT_INFIX: Error(ecINVALID_INFIX_IDENT, -1, a_sName); - default: Error(ecINVALID_NAME, -1, a_sName); - } + switch (a_Callback.GetCode()) + { + case cmOPRT_POSTFIX: + Error(ecINVALID_POSTFIX_IDENT, -1, a_sName); + case cmOPRT_INFIX: + Error(ecINVALID_INFIX_IDENT, -1, a_sName); + default: + Error(ecINVALID_NAME, -1, a_sName); + } } - } - - //--------------------------------------------------------------------------- - /** \brief Check if a name contains invalid characters. - - \throw ParserException if the name contains invalid characters. - */ - void ParserBase::CheckName(const string_type &a_sName, - const string_type &a_szCharSet) const - { - if ( !a_sName.length() || - (a_sName.find_first_not_of(a_szCharSet)!=string_type::npos) || - (a_sName[0]>='0' && a_sName[0]<='9')) +} + +//--------------------------------------------------------------------------- +/** \brief Check if a name contains invalid characters. + + \throw ParserException if the name contains invalid characters. +*/ +void ParserBase::CheckName(const string_type& a_sName, const string_type& a_szCharSet) const +{ + if (!a_sName.length() || (a_sName.find_first_not_of(a_szCharSet) != string_type::npos) || + (a_sName[0] >= '0' && a_sName[0] <= '9')) { - Error(ecINVALID_NAME); + Error(ecINVALID_NAME); } - } - - //--------------------------------------------------------------------------- - /** \brief Set the formula. - \param a_strFormula Formula as string_type - \throw ParserException in case of syntax errors. - - Triggers first time calculation thus the creation of the bytecode and - scanning of used variables. - */ - void ParserBase::SetExpr(const string_type &a_sExpr) - { +} + +//--------------------------------------------------------------------------- +/** \brief Set the formula. + \param a_strFormula Formula as string_type + \throw ParserException in case of syntax errors. + + Triggers first time calculation thus the creation of the bytecode and + scanning of used variables. +*/ +void ParserBase::SetExpr(const string_type& a_sExpr) +{ // Check locale compatibility std::locale loc; - if (m_pTokenReader->GetArgSep()==std::use_facet >(loc).decimal_point()) - Error(ecLOCALE); + if (m_pTokenReader->GetArgSep() == std::use_facet >(loc).decimal_point()) + Error(ecLOCALE); // 20060222: Bugfix for Borland-Kylix: // adding a space to the expression will keep Borlands KYLIX from going wild - // when calling tellg on a stringstream created from the expression after + // when calling tellg on a stringstream created from the expression after // reading a value at the end of an expression. (mu::Parser::IsVal function) // (tellg returns -1 otherwise causing the parser to ignore the value) - string_type sBuf(a_sExpr + _T(" ") ); + string_type sBuf(a_sExpr + _T(" ")); m_pTokenReader->SetFormula(sBuf); ReInit(); - } - - //--------------------------------------------------------------------------- - /** \brief Get the default symbols used for the built in operators. - \sa c_DefaultOprt - */ - const char_type** ParserBase::GetOprtDef() const - { - return (const char_type **)(&c_DefaultOprt[0]); - } - - //--------------------------------------------------------------------------- - /** \brief Define the set of valid characters to be used in names of - functions, variables, constants. - */ - void ParserBase::DefineNameChars(const char_type *a_szCharset) - { +} + +//--------------------------------------------------------------------------- +/** \brief Get the default symbols used for the built in operators. + \sa c_DefaultOprt +*/ +const char_type** ParserBase::GetOprtDef() const +{ + return (const char_type**)(&c_DefaultOprt[0]); +} + +//--------------------------------------------------------------------------- +/** \brief Define the set of valid characters to be used in names of + functions, variables, constants. +*/ +void ParserBase::DefineNameChars(const char_type* a_szCharset) +{ m_sNameChars = a_szCharset; - } - - //--------------------------------------------------------------------------- - /** \brief Define the set of valid characters to be used in names of - binary operators and postfix operators. - */ - void ParserBase::DefineOprtChars(const char_type *a_szCharset) - { +} + +//--------------------------------------------------------------------------- +/** \brief Define the set of valid characters to be used in names of + binary operators and postfix operators. +*/ +void ParserBase::DefineOprtChars(const char_type* a_szCharset) +{ m_sOprtChars = a_szCharset; - } - - //--------------------------------------------------------------------------- - /** \brief Define the set of valid characters to be used in names of - infix operators. - */ - void ParserBase::DefineInfixOprtChars(const char_type *a_szCharset) - { +} + +//--------------------------------------------------------------------------- +/** \brief Define the set of valid characters to be used in names of + infix operators. +*/ +void ParserBase::DefineInfixOprtChars(const char_type* a_szCharset) +{ m_sInfixOprtChars = a_szCharset; - } - - //--------------------------------------------------------------------------- - /** \brief Virtual function that defines the characters allowed in name identifiers. - \sa #ValidOprtChars, #ValidPrefixOprtChars - */ - const char_type* ParserBase::ValidNameChars() const - { +} + +//--------------------------------------------------------------------------- +/** \brief Virtual function that defines the characters allowed in name identifiers. + \sa #ValidOprtChars, #ValidPrefixOprtChars +*/ +const char_type* ParserBase::ValidNameChars() const +{ assert(m_sNameChars.size()); return m_sNameChars.c_str(); - } - - //--------------------------------------------------------------------------- - /** \brief Virtual function that defines the characters allowed in operator definitions. - \sa #ValidNameChars, #ValidPrefixOprtChars - */ - const char_type* ParserBase::ValidOprtChars() const - { +} + +//--------------------------------------------------------------------------- +/** \brief Virtual function that defines the characters allowed in operator definitions. + \sa #ValidNameChars, #ValidPrefixOprtChars +*/ +const char_type* ParserBase::ValidOprtChars() const +{ assert(m_sOprtChars.size()); return m_sOprtChars.c_str(); - } - - //--------------------------------------------------------------------------- - /** \brief Virtual function that defines the characters allowed in infix operator definitions. - \sa #ValidNameChars, #ValidOprtChars - */ - const char_type* ParserBase::ValidInfixOprtChars() const - { +} + +//--------------------------------------------------------------------------- +/** \brief Virtual function that defines the characters allowed in infix operator definitions. + \sa #ValidNameChars, #ValidOprtChars +*/ +const char_type* ParserBase::ValidInfixOprtChars() const +{ assert(m_sInfixOprtChars.size()); return m_sInfixOprtChars.c_str(); - } - - //--------------------------------------------------------------------------- - /** \brief Add a user defined operator. - \post Will reset the Parser to string parsing mode. - */ - void ParserBase::DefinePostfixOprt(const string_type &a_sName, - fun_type1 a_pFun, - bool a_bAllowOpt) - { - AddCallback(a_sName, - ParserCallback(a_pFun, a_bAllowOpt, prPOSTFIX, cmOPRT_POSTFIX), - m_PostOprtDef, - ValidOprtChars() ); - } - - //--------------------------------------------------------------------------- - /** \brief Initialize user defined functions. - - Calls the virtual functions InitFun(), InitConst() and InitOprt(). - */ - void ParserBase::Init() - { +} + +//--------------------------------------------------------------------------- +/** \brief Add a user defined operator. + \post Will reset the Parser to string parsing mode. +*/ +void ParserBase::DefinePostfixOprt(const string_type& a_sName, fun_type1 a_pFun, bool a_bAllowOpt) +{ + AddCallback( + a_sName, ParserCallback(a_pFun, a_bAllowOpt, prPOSTFIX, cmOPRT_POSTFIX), m_PostOprtDef, ValidOprtChars()); +} + +//--------------------------------------------------------------------------- +/** \brief Initialize user defined functions. + + Calls the virtual functions InitFun(), InitConst() and InitOprt(). +*/ +void ParserBase::Init() +{ InitCharSets(); InitFun(); InitConst(); InitOprt(); - } - - //--------------------------------------------------------------------------- - /** \brief Add a user defined operator. - \post Will reset the Parser to string parsing mode. - \param [in] a_sName operator Identifier - \param [in] a_pFun Operator callback function - \param [in] a_iPrec Operator Precedence (default=prSIGN) - \param [in] a_bAllowOpt True if operator is volatile (default=false) - \sa EPrec - */ - void ParserBase::DefineInfixOprt(const string_type &a_sName, - fun_type1 a_pFun, - int a_iPrec, - bool a_bAllowOpt) - { - AddCallback(a_sName, - ParserCallback(a_pFun, a_bAllowOpt, a_iPrec, cmOPRT_INFIX), - m_InfixOprtDef, - ValidInfixOprtChars() ); - } - - - //--------------------------------------------------------------------------- - /** \brief Define a binary operator. - \param [in] a_sName The identifier of the operator. - \param [in] a_pFun Pointer to the callback function. - \param [in] a_iPrec Precedence of the operator. - \param [in] a_eAssociativity The associativity of the operator. - \param [in] a_bAllowOpt If this is true the operator may be optimized away. - - Adds a new Binary operator the the parser instance. - */ - void ParserBase::DefineOprt( const string_type &a_sName, - fun_type2 a_pFun, - unsigned a_iPrec, - EOprtAssociativity a_eAssociativity, - bool a_bAllowOpt ) - { +} + +//--------------------------------------------------------------------------- +/** \brief Add a user defined operator. + \post Will reset the Parser to string parsing mode. + \param [in] a_sName operator Identifier + \param [in] a_pFun Operator callback function + \param [in] a_iPrec Operator Precedence (default=prSIGN) + \param [in] a_bAllowOpt True if operator is volatile (default=false) + \sa EPrec +*/ +void ParserBase::DefineInfixOprt(const string_type& a_sName, fun_type1 a_pFun, int a_iPrec, bool a_bAllowOpt) +{ + AddCallback( + a_sName, ParserCallback(a_pFun, a_bAllowOpt, a_iPrec, cmOPRT_INFIX), m_InfixOprtDef, ValidInfixOprtChars()); +} + +//--------------------------------------------------------------------------- +/** \brief Define a binary operator. + \param [in] a_sName The identifier of the operator. + \param [in] a_pFun Pointer to the callback function. + \param [in] a_iPrec Precedence of the operator. + \param [in] a_eAssociativity The associativity of the operator. + \param [in] a_bAllowOpt If this is true the operator may be optimized away. + + Adds a new Binary operator the the parser instance. +*/ +void ParserBase::DefineOprt(const string_type& a_sName, + fun_type2 a_pFun, + unsigned a_iPrec, + EOprtAssociativity a_eAssociativity, + bool a_bAllowOpt) +{ // Check for conflicts with built in operator names - for (int i=0; m_bBuiltInOp && iIgnoreUndefVar(true); - CreateRPN(); // try to create bytecode, but don't use it for any further calculations since it - // may contain references to nonexisting variables. - m_pParseFormula = &ParserBase::ParseString; - m_pTokenReader->IgnoreUndefVar(false); + m_pTokenReader->IgnoreUndefVar(true); + CreateRPN(); // try to create bytecode, but don't use it for any further calculations since it + // may contain references to nonexisting variables. + m_pParseFormula = &ParserBase::ParseString; + m_pTokenReader->IgnoreUndefVar(false); } - catch(exception_type & /*e*/) + catch (exception_type& /*e*/) { - // Make sure to stay in string parse mode, dont call ReInit() - // because it deletes the array with the used variables - m_pParseFormula = &ParserBase::ParseString; - m_pTokenReader->IgnoreUndefVar(false); - throw; + // Make sure to stay in string parse mode, dont call ReInit() + // because it deletes the array with the used variables + m_pParseFormula = &ParserBase::ParseString; + m_pTokenReader->IgnoreUndefVar(false); + throw; } - + return m_pTokenReader->GetUsedVar(); - } +} - //--------------------------------------------------------------------------- - /** \brief Return a map containing the used variables only. */ - const varmap_type& ParserBase::GetVar() const - { +//--------------------------------------------------------------------------- +/** \brief Return a map containing the used variables only. */ +const varmap_type& ParserBase::GetVar() const +{ return m_VarDef; - } +} - //--------------------------------------------------------------------------- - /** \brief Return a map containing all parser constants. */ - const valmap_type& ParserBase::GetConst() const - { +//--------------------------------------------------------------------------- +/** \brief Return a map containing all parser constants. */ +const valmap_type& ParserBase::GetConst() const +{ return m_ConstDef; - } - - //--------------------------------------------------------------------------- - /** \brief Return prototypes of all parser functions. - \return #m_FunDef - \sa FunProt - \throw nothrow - - The return type is a map of the public type #funmap_type containing the prototype - definitions for all numerical parser functions. String functions are not part of - this map. The Prototype definition is encapsulated in objects of the class FunProt - one per parser function each associated with function names via a map construct. - */ - const funmap_type& ParserBase::GetFunDef() const - { +} + +//--------------------------------------------------------------------------- +/** \brief Return prototypes of all parser functions. + \return #m_FunDef + \sa FunProt + \throw nothrow + + The return type is a map of the public type #funmap_type containing the prototype + definitions for all numerical parser functions. String functions are not part of + this map. The Prototype definition is encapsulated in objects of the class FunProt + one per parser function each associated with function names via a map construct. +*/ +const funmap_type& ParserBase::GetFunDef() const +{ return m_FunDef; - } +} - //--------------------------------------------------------------------------- - /** \brief Retrieve the formula. */ - const string_type& ParserBase::GetExpr() const - { +//--------------------------------------------------------------------------- +/** \brief Retrieve the formula. */ +const string_type& ParserBase::GetExpr() const +{ return m_pTokenReader->GetExpr(); - } - - //--------------------------------------------------------------------------- - /** \brief Execute a function that takes a single string argument. - \param a_FunTok Function token. - \throw exception_type If the function token is not a string function - */ - ParserBase::token_type ParserBase::ApplyStrFunc(const token_type &a_FunTok, - const std::vector &a_vArg) const - { - if (a_vArg.back().GetCode()!=cmSTRING) - Error(ecSTRING_EXPECTED, m_pTokenReader->GetPos(), a_FunTok.GetAsString()); - - token_type valTok; +} + +//--------------------------------------------------------------------------- +/** \brief Execute a function that takes a single string argument. + \param a_FunTok Function token. + \throw exception_type If the function token is not a string function +*/ +ParserBase::token_type ParserBase::ApplyStrFunc(const token_type& a_FunTok, const std::vector& a_vArg) const +{ + if (a_vArg.back().GetCode() != cmSTRING) + Error(ecSTRING_EXPECTED, m_pTokenReader->GetPos(), a_FunTok.GetAsString()); + + token_type valTok; generic_fun_type pFunc = a_FunTok.GetFuncAddr(); assert(pFunc); try { - // Check function arguments; write dummy value into valtok to represent the result - switch(a_FunTok.GetArgCount()) - { - case 0: valTok.SetVal(1); a_vArg[0].GetAsString(); break; - case 1: valTok.SetVal(1); a_vArg[1].GetAsString(); a_vArg[0].GetVal(); break; - case 2: valTok.SetVal(1); a_vArg[2].GetAsString(); a_vArg[1].GetVal(); a_vArg[0].GetVal(); break; - default: Error(ecINTERNAL_ERROR); - } + // Check function arguments; write dummy value into valtok to represent the result + switch (a_FunTok.GetArgCount()) + { + case 0: + valTok.SetVal(1); + a_vArg[0].GetAsString(); + break; + case 1: + valTok.SetVal(1); + a_vArg[1].GetAsString(); + a_vArg[0].GetVal(); + break; + case 2: + valTok.SetVal(1); + a_vArg[2].GetAsString(); + a_vArg[1].GetVal(); + a_vArg[0].GetVal(); + break; + default: + Error(ecINTERNAL_ERROR); + } } - catch(ParserError& ) + catch (ParserError&) { - Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), a_FunTok.GetAsString()); + Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), a_FunTok.GetAsString()); } // string functions won't be optimized m_vRPN.AddStrFun(pFunc, a_FunTok.GetArgCount(), a_vArg.back().GetIdx()); - + // Push dummy value representing the function result to the stack return valTok; - } - - //--------------------------------------------------------------------------- - /** \brief Apply a function token. - \param iArgCount Number of Arguments actually gathered used only for multiarg functions. - \post The result is pushed to the value stack - \post The function token is removed from the stack - \throw exception_type if Argument count does not match function requirements. - */ - void ParserBase::ApplyFunc( ParserStack &a_stOpt, - ParserStack &a_stVal, - int a_iArgCount) const - { +} + +//--------------------------------------------------------------------------- +/** \brief Apply a function token. + \param iArgCount Number of Arguments actually gathered used only for multiarg functions. + \post The result is pushed to the value stack + \post The function token is removed from the stack + \throw exception_type if Argument count does not match function requirements. +*/ +void ParserBase::ApplyFunc(ParserStack& a_stOpt, ParserStack& a_stVal, int a_iArgCount) const +{ assert(m_pTokenReader.get()); // Operator stack empty or does not contain tokens with callback functions - if (a_stOpt.empty() || a_stOpt.top().GetFuncAddr()==0 ) - return; + if (a_stOpt.empty() || a_stOpt.top().GetFuncAddr() == 0) + return; token_type funTok = a_stOpt.pop(); assert(funTok.GetFuncAddr()); @@ -804,975 +809,1183 @@ namespace mu // Binary operators must rely on their internal operator number // since counting of operators relies on commas for function arguments // binary operators do not have commas in their expression - int iArgCount = (funTok.GetCode()==cmOPRT_BIN) ? funTok.GetArgCount() : a_iArgCount; + int iArgCount = (funTok.GetCode() == cmOPRT_BIN) ? funTok.GetArgCount() : a_iArgCount; - // determine how many parameters the function needs. To remember iArgCount includes the + // determine how many parameters the function needs. To remember iArgCount includes the // string parameter whilst GetArgCount() counts only numeric parameters. - int iArgRequired = funTok.GetArgCount() + ((funTok.GetType()==tpSTR) ? 1 : 0); + int iArgRequired = funTok.GetArgCount() + ((funTok.GetType() == tpSTR) ? 1 : 0); // Thats the number of numerical parameters - int iArgNumerical = iArgCount - ((funTok.GetType()==tpSTR) ? 1 : 0); + int iArgNumerical = iArgCount - ((funTok.GetType() == tpSTR) ? 1 : 0); - if (funTok.GetCode()==cmFUNC_STR && iArgCount-iArgNumerical>1) - Error(ecINTERNAL_ERROR); + if (funTok.GetCode() == cmFUNC_STR && iArgCount - iArgNumerical > 1) + Error(ecINTERNAL_ERROR); - if (funTok.GetArgCount()>=0 && iArgCount>iArgRequired) - Error(ecTOO_MANY_PARAMS, m_pTokenReader->GetPos()-1, funTok.GetAsString()); + if (funTok.GetArgCount() >= 0 && iArgCount > iArgRequired) + Error(ecTOO_MANY_PARAMS, m_pTokenReader->GetPos() - 1, funTok.GetAsString()); - if (funTok.GetCode()!=cmOPRT_BIN && iArgCountGetPos()-1, funTok.GetAsString()); + if (funTok.GetCode() != cmOPRT_BIN && iArgCount < iArgRequired) + Error(ecTOO_FEW_PARAMS, m_pTokenReader->GetPos() - 1, funTok.GetAsString()); - if (funTok.GetCode()==cmFUNC_STR && iArgCount>iArgRequired ) - Error(ecTOO_MANY_PARAMS, m_pTokenReader->GetPos()-1, funTok.GetAsString()); + if (funTok.GetCode() == cmFUNC_STR && iArgCount > iArgRequired) + Error(ecTOO_MANY_PARAMS, m_pTokenReader->GetPos() - 1, funTok.GetAsString()); // Collect the numeric function arguments from the value stack and store them // in a vector - std::vector stArg; - for (int i=0; i stArg; + for (int i = 0; i < iArgNumerical; ++i) { - stArg.push_back( a_stVal.pop() ); - if ( stArg.back().GetType()==tpSTR && funTok.GetType()!=tpSTR ) - Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), funTok.GetAsString()); + stArg.push_back(a_stVal.pop()); + if (stArg.back().GetType() == tpSTR && funTok.GetType() != tpSTR) + Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), funTok.GetAsString()); } - switch((int)funTok.GetCode()) + switch ((int)funTok.GetCode()) { - case cmFUNC_STR: - stArg.push_back(a_stVal.pop()); - - if ( stArg.back().GetType()==tpSTR && funTok.GetType()!=tpSTR ) - Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), funTok.GetAsString()); + case cmFUNC_STR: + stArg.push_back(a_stVal.pop()); - ApplyStrFunc(funTok, stArg); - break; + if (stArg.back().GetType() == tpSTR && funTok.GetType() != tpSTR) + Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), funTok.GetAsString()); - case cmFUNC_BULK: - m_vRPN.AddBulkFun(funTok.GetFuncAddr(), (int)stArg.size()); - break; + ApplyStrFunc(funTok, stArg); + break; - case cmOPRT_BIN: - case cmOPRT_POSTFIX: - case cmOPRT_INFIX: - case cmFUNC: - if (funTok.GetArgCount()==-1 && iArgCount==0) - Error(ecTOO_FEW_PARAMS, m_pTokenReader->GetPos(), funTok.GetAsString()); + case cmFUNC_BULK: + m_vRPN.AddBulkFun(funTok.GetFuncAddr(), (int)stArg.size()); + break; - m_vRPN.AddFun(funTok.GetFuncAddr(), (funTok.GetArgCount()==-1) ? -iArgNumerical : iArgNumerical); - break; + case cmOPRT_BIN: + case cmOPRT_POSTFIX: + case cmOPRT_INFIX: + case cmFUNC: + if (funTok.GetArgCount() == -1 && iArgCount == 0) + Error(ecTOO_FEW_PARAMS, m_pTokenReader->GetPos(), funTok.GetAsString()); + + m_vRPN.AddFun(funTok.GetFuncAddr(), (funTok.GetArgCount() == -1) ? -iArgNumerical : iArgNumerical); + break; } // Push dummy value representing the function result to the stack token_type token; - token.SetVal(1); + token.SetVal(1); a_stVal.push(token); - } +} - //--------------------------------------------------------------------------- - void ParserBase::ApplyIfElse(ParserStack &a_stOpt, - ParserStack &a_stVal) const - { +//--------------------------------------------------------------------------- +void ParserBase::ApplyIfElse(ParserStack& a_stOpt, ParserStack& a_stVal) const +{ // Check if there is an if Else clause to be calculated - while (a_stOpt.size() && a_stOpt.top().GetCode()==cmELSE) + while (a_stOpt.size() && a_stOpt.top().GetCode() == cmELSE) { - token_type opElse = a_stOpt.pop(); - MUP_ASSERT(a_stOpt.size()>0); + token_type opElse = a_stOpt.pop(); + MUP_ASSERT(a_stOpt.size() > 0); - // Take the value associated with the else branch from the value stack - token_type vVal2 = a_stVal.pop(); + // Take the value associated with the else branch from the value stack + token_type vVal2 = a_stVal.pop(); - MUP_ASSERT(a_stOpt.size()>0); - MUP_ASSERT(a_stVal.size()>=2); + MUP_ASSERT(a_stOpt.size() > 0); + MUP_ASSERT(a_stVal.size() >= 2); - // it then else is a ternary operator Pop all three values from the value s - // tack and just return the right value - token_type vVal1 = a_stVal.pop(); - token_type vExpr = a_stVal.pop(); + // it then else is a ternary operator Pop all three values from the value s + // tack and just return the right value + token_type vVal1 = a_stVal.pop(); + token_type vExpr = a_stVal.pop(); - a_stVal.push( (vExpr.GetVal()!=0) ? vVal1 : vVal2); + a_stVal.push((vExpr.GetVal() != 0) ? vVal1 : vVal2); - token_type opIf = a_stOpt.pop(); - MUP_ASSERT(opElse.GetCode()==cmELSE); - MUP_ASSERT(opIf.GetCode()==cmIF); + token_type opIf = a_stOpt.pop(); + MUP_ASSERT(opElse.GetCode() == cmELSE); + MUP_ASSERT(opIf.GetCode() == cmIF); - m_vRPN.AddIfElse(cmENDIF); + m_vRPN.AddIfElse(cmENDIF); } // while pending if-else-clause found - } - - //--------------------------------------------------------------------------- - /** \brief Performs the necessary steps to write code for - the execution of binary operators into the bytecode. - */ - void ParserBase::ApplyBinOprt(ParserStack &a_stOpt, - ParserStack &a_stVal) const - { +} + +//--------------------------------------------------------------------------- +/** \brief Performs the necessary steps to write code for + the execution of binary operators into the bytecode. +*/ +void ParserBase::ApplyBinOprt(ParserStack& a_stOpt, ParserStack& a_stVal) const +{ // is it a user defined binary operator? - if (a_stOpt.top().GetCode()==cmOPRT_BIN) + if (a_stOpt.top().GetCode() == cmOPRT_BIN) { - ApplyFunc(a_stOpt, a_stVal, 2); + ApplyFunc(a_stOpt, a_stVal, 2); } else { - MUP_ASSERT(a_stVal.size()>=2); - token_type valTok1 = a_stVal.pop(), - valTok2 = a_stVal.pop(), - optTok = a_stOpt.pop(), - resTok; - - if ( valTok1.GetType()!=valTok2.GetType() || - (valTok1.GetType()==tpSTR && valTok2.GetType()==tpSTR) ) - Error(ecOPRT_TYPE_CONFLICT, m_pTokenReader->GetPos(), optTok.GetAsString()); - - if (optTok.GetCode()==cmASSIGN) - { - if (valTok2.GetCode()!=cmVAR) - Error(ecUNEXPECTED_OPERATOR, -1, _T("=")); - - m_vRPN.AddAssignOp(valTok2.GetVar()); - } - else - m_vRPN.AddOp(optTok.GetCode()); - - resTok.SetVal(1); - a_stVal.push(resTok); + MUP_ASSERT(a_stVal.size() >= 2); + token_type valTok1 = a_stVal.pop(), valTok2 = a_stVal.pop(), optTok = a_stOpt.pop(), resTok; + + if (valTok1.GetType() != valTok2.GetType() || (valTok1.GetType() == tpSTR && valTok2.GetType() == tpSTR)) + Error(ecOPRT_TYPE_CONFLICT, m_pTokenReader->GetPos(), optTok.GetAsString()); + + if (optTok.GetCode() == cmASSIGN) + { + if (valTok2.GetCode() != cmVAR) + Error(ecUNEXPECTED_OPERATOR, -1, _T("=")); + + m_vRPN.AddAssignOp(valTok2.GetVar()); + } + else + m_vRPN.AddOp(optTok.GetCode()); + + resTok.SetVal(1); + a_stVal.push(resTok); } - } - - //--------------------------------------------------------------------------- - /** \brief Apply a binary operator. - \param a_stOpt The operator stack - \param a_stVal The value stack - */ - void ParserBase::ApplyRemainingOprt(ParserStack &stOpt, - ParserStack &stVal) const - { - while (stOpt.size() && - stOpt.top().GetCode() != cmBO && - stOpt.top().GetCode() != cmIF) +} + +//--------------------------------------------------------------------------- +/** \brief Apply a binary operator. + \param a_stOpt The operator stack + \param a_stVal The value stack +*/ +void ParserBase::ApplyRemainingOprt(ParserStack& stOpt, ParserStack& stVal) const +{ + while (stOpt.size() && stOpt.top().GetCode() != cmBO && stOpt.top().GetCode() != cmIF) { - token_type tok = stOpt.top(); - switch (tok.GetCode()) - { - case cmOPRT_INFIX: - case cmOPRT_BIN: - case cmLE: - case cmGE: - case cmNEQ: - case cmEQ: - case cmLT: - case cmGT: - case cmADD: - case cmSUB: - case cmMUL: - case cmDIV: - case cmPOW: - case cmLAND: - case cmLOR: - case cmASSIGN: - if (stOpt.top().GetCode()==cmOPRT_INFIX) - ApplyFunc(stOpt, stVal, 1); - else - ApplyBinOprt(stOpt, stVal); - break; - - case cmELSE: - ApplyIfElse(stOpt, stVal); - break; - - default: - Error(ecINTERNAL_ERROR); - } + token_type tok = stOpt.top(); + switch (tok.GetCode()) + { + case cmOPRT_INFIX: + case cmOPRT_BIN: + case cmLE: + case cmGE: + case cmNEQ: + case cmEQ: + case cmLT: + case cmGT: + case cmADD: + case cmSUB: + case cmMUL: + case cmDIV: + case cmPOW: + case cmLAND: + case cmLOR: + case cmASSIGN: + if (stOpt.top().GetCode() == cmOPRT_INFIX) + ApplyFunc(stOpt, stVal, 1); + else + ApplyBinOprt(stOpt, stVal); + break; + + case cmELSE: + ApplyIfElse(stOpt, stVal); + break; + + default: + Error(ecINTERNAL_ERROR); + } } - } - - //--------------------------------------------------------------------------- - /** \brief Parse the command code. - \sa ParseString(...) - - Command code contains precalculated stack positions of the values and the - associated operators. The Stack is filled beginning from index one the - value at index zero is not used at all. - */ - value_type ParserBase::ParseCmdCode() const - { +} + +//--------------------------------------------------------------------------- +/** \brief Parse the command code. + \sa ParseString(...) + + Command code contains precalculated stack positions of the values and the + associated operators. The Stack is filled beginning from index one the + value at index zero is not used at all. +*/ +value_type ParserBase::ParseCmdCode() const +{ return ParseCmdCodeBulk(0, 0); - } - - //--------------------------------------------------------------------------- - /** \brief Evaluate the RPN. - \param nOffset The offset added to variable addresses (for bulk mode) - \param nThreadID OpenMP Thread id of the calling thread - */ - value_type ParserBase::ParseCmdCodeBulk(int nOffset, int nThreadID) const - { - assert(nThreadID<=s_MaxNumOpenMPThreads); - - // Note: The check for nOffset==0 and nThreadID here is not necessary but +} + +//--------------------------------------------------------------------------- +/** \brief Evaluate the RPN. + \param nOffset The offset added to variable addresses (for bulk mode) + \param nThreadID OpenMP Thread id of the calling thread +*/ +value_type ParserBase::ParseCmdCodeBulk(int nOffset, int nThreadID) const +{ + assert(nThreadID <= s_MaxNumOpenMPThreads); + + // Note: The check for nOffset==0 and nThreadID here is not necessary but // brings a minor performance gain when not in bulk mode. - value_type *Stack = ((nOffset==0) && (nThreadID==0)) ? &m_vStackBuffer[0] : &m_vStackBuffer[nThreadID * (m_vStackBuffer.size() / s_MaxNumOpenMPThreads)]; + value_type* Stack = ((nOffset == 0) && (nThreadID == 0)) ? + &m_vStackBuffer[0] : + &m_vStackBuffer[nThreadID * (m_vStackBuffer.size() / s_MaxNumOpenMPThreads)]; value_type buf; int sidx(0); - for (const SToken *pTok = m_vRPN.GetBase(); pTok->Cmd!=cmEND ; ++pTok) + for (const SToken* pTok = m_vRPN.GetBase(); pTok->Cmd != cmEND; ++pTok) { - switch (pTok->Cmd) - { - // built in binary operators - case cmLE: --sidx; Stack[sidx] = Stack[sidx] <= Stack[sidx+1]; continue; - case cmGE: --sidx; Stack[sidx] = Stack[sidx] >= Stack[sidx+1]; continue; - case cmNEQ: --sidx; Stack[sidx] = Stack[sidx] != Stack[sidx+1]; continue; - case cmEQ: --sidx; Stack[sidx] = Stack[sidx] == Stack[sidx+1]; continue; - case cmLT: --sidx; Stack[sidx] = Stack[sidx] < Stack[sidx+1]; continue; - case cmGT: --sidx; Stack[sidx] = Stack[sidx] > Stack[sidx+1]; continue; - case cmADD: --sidx; Stack[sidx] += Stack[1+sidx]; continue; - case cmSUB: --sidx; Stack[sidx] -= Stack[1+sidx]; continue; - case cmMUL: --sidx; Stack[sidx] *= Stack[1+sidx]; continue; - case cmDIV: --sidx; - - #if defined(MUP_MATH_EXCEPTIONS) - if (Stack[1+sidx]==0) + switch (pTok->Cmd) + { + // built in binary operators + case cmLE: + --sidx; + Stack[sidx] = Stack[sidx] <= Stack[sidx + 1]; + continue; + case cmGE: + --sidx; + Stack[sidx] = Stack[sidx] >= Stack[sidx + 1]; + continue; + case cmNEQ: + --sidx; + Stack[sidx] = Stack[sidx] != Stack[sidx + 1]; + continue; + case cmEQ: + --sidx; + Stack[sidx] = Stack[sidx] == Stack[sidx + 1]; + continue; + case cmLT: + --sidx; + Stack[sidx] = Stack[sidx] < Stack[sidx + 1]; + continue; + case cmGT: + --sidx; + Stack[sidx] = Stack[sidx] > Stack[sidx + 1]; + continue; + case cmADD: + --sidx; + Stack[sidx] += Stack[1 + sidx]; + continue; + case cmSUB: + --sidx; + Stack[sidx] -= Stack[1 + sidx]; + continue; + case cmMUL: + --sidx; + Stack[sidx] *= Stack[1 + sidx]; + continue; + case cmDIV: + --sidx; + +#if defined(MUP_MATH_EXCEPTIONS) + if (Stack[1 + sidx] == 0) Error(ecDIV_BY_ZERO); - #endif - Stack[sidx] /= Stack[1+sidx]; - continue; - - case cmPOW: - --sidx; Stack[sidx] = MathImpl::Pow(Stack[sidx], Stack[1+sidx]); - continue; - - case cmLAND: --sidx; Stack[sidx] = Stack[sidx] && Stack[sidx+1]; continue; - case cmLOR: --sidx; Stack[sidx] = Stack[sidx] || Stack[sidx+1]; continue; - - case cmASSIGN: - // Bugfix for Bulkmode: - // for details see: - // https://groups.google.com/forum/embed/?place=forum/muparser-dev&showsearch=true&showpopout=true&showtabs=false&parenturl=http://muparser.beltoforion.de/mup_forum.html&afterlogin&pli=1#!topic/muparser-dev/szgatgoHTws - --sidx; Stack[sidx] = *(pTok->Oprt.ptr + nOffset) = Stack[sidx + 1]; continue; - // original code: - //--sidx; Stack[sidx] = *pTok->Oprt.ptr = Stack[sidx+1]; continue; - - //case cmBO: // unused, listed for compiler optimization purposes - //case cmBC: - // MUP_FAIL(INVALID_CODE_IN_BYTECODE); - // continue; - - case cmIF: - if (Stack[sidx--]==0) - pTok += pTok->Oprt.offset; - continue; - - case cmELSE: - pTok += pTok->Oprt.offset; - continue; - - case cmENDIF: - continue; - - //case cmARG_SEP: - // MUP_FAIL(INVALID_CODE_IN_BYTECODE); - // continue; - - // value and variable tokens - case cmVAR: Stack[++sidx] = *(pTok->Val.ptr + nOffset); continue; - case cmVAL: Stack[++sidx] = pTok->Val.data2; continue; - - case cmVARPOW2: buf = *(pTok->Val.ptr + nOffset); - Stack[++sidx] = buf*buf; - continue; - - case cmVARPOW3: buf = *(pTok->Val.ptr + nOffset); - Stack[++sidx] = buf*buf*buf; - continue; - - case cmVARPOW4: buf = *(pTok->Val.ptr + nOffset); - Stack[++sidx] = buf*buf*buf*buf; - continue; - - case cmVARMUL: Stack[++sidx] = *(pTok->Val.ptr + nOffset) * pTok->Val.data + pTok->Val.data2; - continue; - - // Next is treatment of numeric functions - case cmFUNC: - { - int iArgCount = pTok->Fun.argc; - - // switch according to argument count - switch(iArgCount) - { - case 0: sidx += 1; Stack[sidx] = (*(fun_type0)pTok->Fun.ptr)(); continue; - case 1: Stack[sidx] = (*(fun_type1)pTok->Fun.ptr)(Stack[sidx]); continue; - case 2: sidx -= 1; Stack[sidx] = (*(fun_type2)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1]); continue; - case 3: sidx -= 2; Stack[sidx] = (*(fun_type3)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2]); continue; - case 4: sidx -= 3; Stack[sidx] = (*(fun_type4)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3]); continue; - case 5: sidx -= 4; Stack[sidx] = (*(fun_type5)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4]); continue; - case 6: sidx -= 5; Stack[sidx] = (*(fun_type6)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5]); continue; - case 7: sidx -= 6; Stack[sidx] = (*(fun_type7)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6]); continue; - case 8: sidx -= 7; Stack[sidx] = (*(fun_type8)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7]); continue; - case 9: sidx -= 8; Stack[sidx] = (*(fun_type9)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7], Stack[sidx+8]); continue; - case 10:sidx -= 9; Stack[sidx] = (*(fun_type10)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7], Stack[sidx+8], Stack[sidx+9]); continue; - default: - if (iArgCount>0) // function with variable arguments store the number as a negative value - Error(ecINTERNAL_ERROR, 1); - - sidx -= -iArgCount - 1; - Stack[sidx] =(*(multfun_type)pTok->Fun.ptr)(&Stack[sidx], -iArgCount); +#endif + Stack[sidx] /= Stack[1 + sidx]; + continue; + + case cmPOW: + --sidx; + Stack[sidx] = MathImpl::Pow(Stack[sidx], Stack[1 + sidx]); + continue; + + case cmLAND: + --sidx; + Stack[sidx] = Stack[sidx] && Stack[sidx + 1]; + continue; + case cmLOR: + --sidx; + Stack[sidx] = Stack[sidx] || Stack[sidx + 1]; + continue; + + case cmASSIGN: + // Bugfix for Bulkmode: + // for details see: + // https://groups.google.com/forum/embed/?place=forum/muparser-dev&showsearch=true&showpopout=true&showtabs=false&parenturl=http://muparser.beltoforion.de/mup_forum.html&afterlogin&pli=1#!topic/muparser-dev/szgatgoHTws + --sidx; + Stack[sidx] = *(pTok->Oprt.ptr + nOffset) = Stack[sidx + 1]; + continue; + // original code: + //--sidx; Stack[sidx] = *pTok->Oprt.ptr = Stack[sidx+1]; continue; + + // case cmBO: // unused, listed for compiler optimization purposes + // case cmBC: + // MUP_FAIL(INVALID_CODE_IN_BYTECODE); + // continue; + + case cmIF: + if (Stack[sidx--] == 0) + pTok += pTok->Oprt.offset; + continue; + + case cmELSE: + pTok += pTok->Oprt.offset; + continue; + + case cmENDIF: continue; - } + + // case cmARG_SEP: + // MUP_FAIL(INVALID_CODE_IN_BYTECODE); + // continue; + + // value and variable tokens + case cmVAR: + Stack[++sidx] = *(pTok->Val.ptr + nOffset); + continue; + case cmVAL: + Stack[++sidx] = pTok->Val.data2; + continue; + + case cmVARPOW2: + buf = *(pTok->Val.ptr + nOffset); + Stack[++sidx] = buf * buf; + continue; + + case cmVARPOW3: + buf = *(pTok->Val.ptr + nOffset); + Stack[++sidx] = buf * buf * buf; + continue; + + case cmVARPOW4: + buf = *(pTok->Val.ptr + nOffset); + Stack[++sidx] = buf * buf * buf * buf; + continue; + + case cmVARMUL: + Stack[++sidx] = *(pTok->Val.ptr + nOffset) * pTok->Val.data + pTok->Val.data2; + continue; + + // Next is treatment of numeric functions + case cmFUNC: + { + int iArgCount = pTok->Fun.argc; + + // switch according to argument count + switch (iArgCount) + { + case 0: + sidx += 1; + Stack[sidx] = (*(fun_type0)pTok->Fun.ptr)(); + continue; + case 1: + Stack[sidx] = (*(fun_type1)pTok->Fun.ptr)(Stack[sidx]); + continue; + case 2: + sidx -= 1; + Stack[sidx] = (*(fun_type2)pTok->Fun.ptr)(Stack[sidx], Stack[sidx + 1]); + continue; + case 3: + sidx -= 2; + Stack[sidx] = (*(fun_type3)pTok->Fun.ptr)(Stack[sidx], Stack[sidx + 1], Stack[sidx + 2]); + continue; + case 4: + sidx -= 3; + Stack[sidx] = + (*(fun_type4)pTok->Fun.ptr)(Stack[sidx], Stack[sidx + 1], Stack[sidx + 2], Stack[sidx + 3]); + continue; + case 5: + sidx -= 4; + Stack[sidx] = (*(fun_type5)pTok->Fun.ptr)( + Stack[sidx], Stack[sidx + 1], Stack[sidx + 2], Stack[sidx + 3], Stack[sidx + 4]); + continue; + case 6: + sidx -= 5; + Stack[sidx] = (*(fun_type6)pTok->Fun.ptr)(Stack[sidx], + Stack[sidx + 1], + Stack[sidx + 2], + Stack[sidx + 3], + Stack[sidx + 4], + Stack[sidx + 5]); + continue; + case 7: + sidx -= 6; + Stack[sidx] = (*(fun_type7)pTok->Fun.ptr)(Stack[sidx], + Stack[sidx + 1], + Stack[sidx + 2], + Stack[sidx + 3], + Stack[sidx + 4], + Stack[sidx + 5], + Stack[sidx + 6]); + continue; + case 8: + sidx -= 7; + Stack[sidx] = (*(fun_type8)pTok->Fun.ptr)(Stack[sidx], + Stack[sidx + 1], + Stack[sidx + 2], + Stack[sidx + 3], + Stack[sidx + 4], + Stack[sidx + 5], + Stack[sidx + 6], + Stack[sidx + 7]); + continue; + case 9: + sidx -= 8; + Stack[sidx] = (*(fun_type9)pTok->Fun.ptr)(Stack[sidx], + Stack[sidx + 1], + Stack[sidx + 2], + Stack[sidx + 3], + Stack[sidx + 4], + Stack[sidx + 5], + Stack[sidx + 6], + Stack[sidx + 7], + Stack[sidx + 8]); + continue; + case 10: + sidx -= 9; + Stack[sidx] = (*(fun_type10)pTok->Fun.ptr)(Stack[sidx], + Stack[sidx + 1], + Stack[sidx + 2], + Stack[sidx + 3], + Stack[sidx + 4], + Stack[sidx + 5], + Stack[sidx + 6], + Stack[sidx + 7], + Stack[sidx + 8], + Stack[sidx + 9]); + continue; + default: + if (iArgCount > 0) // function with variable arguments store the number as a negative value + Error(ecINTERNAL_ERROR, 1); + + sidx -= -iArgCount - 1; + Stack[sidx] = (*(multfun_type)pTok->Fun.ptr)(&Stack[sidx], -iArgCount); + continue; + } } - // Next is treatment of string functions - case cmFUNC_STR: + // Next is treatment of string functions + case cmFUNC_STR: { - sidx -= pTok->Fun.argc -1; + sidx -= pTok->Fun.argc - 1; - // The index of the string argument in the string table - int iIdxStack = pTok->Fun.idx; - MUP_ASSERT( iIdxStack>=0 && iIdxStack<(int)m_vStringBuf.size() ); + // The index of the string argument in the string table + int iIdxStack = pTok->Fun.idx; + MUP_ASSERT(iIdxStack >= 0 && iIdxStack < (int)m_vStringBuf.size()); - switch(pTok->Fun.argc) // switch according to argument count - { - case 0: Stack[sidx] = (*(strfun_type1)pTok->Fun.ptr)(m_vStringBuf[iIdxStack].c_str()); continue; - case 1: Stack[sidx] = (*(strfun_type2)pTok->Fun.ptr)(m_vStringBuf[iIdxStack].c_str(), Stack[sidx]); continue; - case 2: Stack[sidx] = (*(strfun_type3)pTok->Fun.ptr)(m_vStringBuf[iIdxStack].c_str(), Stack[sidx], Stack[sidx+1]); continue; - } + switch (pTok->Fun.argc) // switch according to argument count + { + case 0: + Stack[sidx] = (*(strfun_type1)pTok->Fun.ptr)(m_vStringBuf[iIdxStack].c_str()); + continue; + case 1: + Stack[sidx] = (*(strfun_type2)pTok->Fun.ptr)(m_vStringBuf[iIdxStack].c_str(), Stack[sidx]); + continue; + case 2: + Stack[sidx] = + (*(strfun_type3)pTok->Fun.ptr)(m_vStringBuf[iIdxStack].c_str(), Stack[sidx], Stack[sidx + 1]); + continue; + } - continue; + continue; } - case cmFUNC_BULK: - { + case cmFUNC_BULK: + { int iArgCount = pTok->Fun.argc; // switch according to argument count - switch(iArgCount) + switch (iArgCount) { - case 0: sidx += 1; Stack[sidx] = (*(bulkfun_type0 )pTok->Fun.ptr)(nOffset, nThreadID); continue; - case 1: Stack[sidx] = (*(bulkfun_type1 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx]); continue; - case 2: sidx -= 1; Stack[sidx] = (*(bulkfun_type2 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1]); continue; - case 3: sidx -= 2; Stack[sidx] = (*(bulkfun_type3 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2]); continue; - case 4: sidx -= 3; Stack[sidx] = (*(bulkfun_type4 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3]); continue; - case 5: sidx -= 4; Stack[sidx] = (*(bulkfun_type5 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4]); continue; - case 6: sidx -= 5; Stack[sidx] = (*(bulkfun_type6 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5]); continue; - case 7: sidx -= 6; Stack[sidx] = (*(bulkfun_type7 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6]); continue; - case 8: sidx -= 7; Stack[sidx] = (*(bulkfun_type8 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7]); continue; - case 9: sidx -= 8; Stack[sidx] = (*(bulkfun_type9 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7], Stack[sidx+8]); continue; - case 10:sidx -= 9; Stack[sidx] = (*(bulkfun_type10)pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7], Stack[sidx+8], Stack[sidx+9]); continue; - default: - Error(ecINTERNAL_ERROR, 2); - continue; + case 0: + sidx += 1; + Stack[sidx] = (*(bulkfun_type0)pTok->Fun.ptr)(nOffset, nThreadID); + continue; + case 1: + Stack[sidx] = (*(bulkfun_type1)pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx]); + continue; + case 2: + sidx -= 1; + Stack[sidx] = (*(bulkfun_type2)pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx + 1]); + continue; + case 3: + sidx -= 2; + Stack[sidx] = (*(bulkfun_type3)pTok->Fun.ptr)( + nOffset, nThreadID, Stack[sidx], Stack[sidx + 1], Stack[sidx + 2]); + continue; + case 4: + sidx -= 3; + Stack[sidx] = (*(bulkfun_type4)pTok->Fun.ptr)( + nOffset, nThreadID, Stack[sidx], Stack[sidx + 1], Stack[sidx + 2], Stack[sidx + 3]); + continue; + case 5: + sidx -= 4; + Stack[sidx] = (*(bulkfun_type5)pTok->Fun.ptr)(nOffset, + nThreadID, + Stack[sidx], + Stack[sidx + 1], + Stack[sidx + 2], + Stack[sidx + 3], + Stack[sidx + 4]); + continue; + case 6: + sidx -= 5; + Stack[sidx] = (*(bulkfun_type6)pTok->Fun.ptr)(nOffset, + nThreadID, + Stack[sidx], + Stack[sidx + 1], + Stack[sidx + 2], + Stack[sidx + 3], + Stack[sidx + 4], + Stack[sidx + 5]); + continue; + case 7: + sidx -= 6; + Stack[sidx] = (*(bulkfun_type7)pTok->Fun.ptr)(nOffset, + nThreadID, + Stack[sidx], + Stack[sidx + 1], + Stack[sidx + 2], + Stack[sidx + 3], + Stack[sidx + 4], + Stack[sidx + 5], + Stack[sidx + 6]); + continue; + case 8: + sidx -= 7; + Stack[sidx] = (*(bulkfun_type8)pTok->Fun.ptr)(nOffset, + nThreadID, + Stack[sidx], + Stack[sidx + 1], + Stack[sidx + 2], + Stack[sidx + 3], + Stack[sidx + 4], + Stack[sidx + 5], + Stack[sidx + 6], + Stack[sidx + 7]); + continue; + case 9: + sidx -= 8; + Stack[sidx] = (*(bulkfun_type9)pTok->Fun.ptr)(nOffset, + nThreadID, + Stack[sidx], + Stack[sidx + 1], + Stack[sidx + 2], + Stack[sidx + 3], + Stack[sidx + 4], + Stack[sidx + 5], + Stack[sidx + 6], + Stack[sidx + 7], + Stack[sidx + 8]); + continue; + case 10: + sidx -= 9; + Stack[sidx] = (*(bulkfun_type10)pTok->Fun.ptr)(nOffset, + nThreadID, + Stack[sidx], + Stack[sidx + 1], + Stack[sidx + 2], + Stack[sidx + 3], + Stack[sidx + 4], + Stack[sidx + 5], + Stack[sidx + 6], + Stack[sidx + 7], + Stack[sidx + 8], + Stack[sidx + 9]); + continue; + default: + Error(ecINTERNAL_ERROR, 2); + continue; } - } + } - default: - Error(ecINTERNAL_ERROR, 3); - return 0; - } // switch CmdCode - } // for all bytecode tokens + default: + Error(ecINTERNAL_ERROR, 3); + return 0; + } // switch CmdCode + } // for all bytecode tokens - return Stack[m_nFinalResultIdx]; - } + return Stack[m_nFinalResultIdx]; +} - //--------------------------------------------------------------------------- - void ParserBase::CreateRPN() const - { +//--------------------------------------------------------------------------- +void ParserBase::CreateRPN() const +{ if (!m_pTokenReader->GetExpr().length()) - Error(ecUNEXPECTED_EOF, 0); + Error(ecUNEXPECTED_EOF, 0); ParserStack stOpt, stVal; ParserStack stArgCount; - token_type opta, opt; // for storing operators - token_type val, tval; // for storing value + token_type opta, opt; // for storing operators + token_type val, tval; // for storing value ReInit(); - + // The outermost counter counts the number of separated items // such as in "a=10,b=20,c=c+a" stArgCount.push(1); - - for(;;) + + for (;;) { - opt = m_pTokenReader->ReadNextToken(); - - switch (opt.GetCode()) - { - // - // Next three are different kind of value entries - // - case cmSTRING: - opt.SetIdx((int)m_vStringBuf.size()); // Assign buffer index to token + opt = m_pTokenReader->ReadNextToken(); + + switch (opt.GetCode()) + { + // + // Next three are different kind of value entries + // + case cmSTRING: + opt.SetIdx((int)m_vStringBuf.size()); // Assign buffer index to token stVal.push(opt); - m_vStringBuf.push_back(opt.GetAsString()); // Store string in internal buffer + m_vStringBuf.push_back(opt.GetAsString()); // Store string in internal buffer break; - - case cmVAR: + + case cmVAR: stVal.push(opt); - m_vRPN.AddVar( static_cast(opt.GetVar()) ); + m_vRPN.AddVar(static_cast(opt.GetVar())); break; - case cmVAL: - stVal.push(opt); - m_vRPN.AddVal( opt.GetVal() ); + case cmVAL: + stVal.push(opt); + m_vRPN.AddVal(opt.GetVal()); break; - case cmELSE: + case cmELSE: m_nIfElseCounter--; - if (m_nIfElseCounter<0) - Error(ecMISPLACED_COLON, m_pTokenReader->GetPos()); + if (m_nIfElseCounter < 0) + Error(ecMISPLACED_COLON, m_pTokenReader->GetPos()); ApplyRemainingOprt(stOpt, stVal); m_vRPN.AddIfElse(cmELSE); stOpt.push(opt); break; - - case cmARG_SEP: + case cmARG_SEP: if (stArgCount.empty()) - Error(ecUNEXPECTED_ARG_SEP, m_pTokenReader->GetPos()); + Error(ecUNEXPECTED_ARG_SEP, m_pTokenReader->GetPos()); ++stArgCount.top(); // fallthrough intentional (no break!) - case cmEND: + case cmEND: ApplyRemainingOprt(stOpt, stVal); break; - case cmBC: - { - // The argument count for parameterless functions is zero - // by default an opening bracket sets parameter count to 1 - // in preparation of arguments to come. If the last token - // was an opening bracket we know better... - if (opta.GetCode()==cmBO) + case cmBC: + { + // The argument count for parameterless functions is zero + // by default an opening bracket sets parameter count to 1 + // in preparation of arguments to come. If the last token + // was an opening bracket we know better... + if (opta.GetCode() == cmBO) --stArgCount.top(); - - ApplyRemainingOprt(stOpt, stVal); - // Check if the bracket content has been evaluated completely - if (stOpt.size() && stOpt.top().GetCode()==cmBO) - { + ApplyRemainingOprt(stOpt, stVal); + + // Check if the bracket content has been evaluated completely + if (stOpt.size() && stOpt.top().GetCode() == cmBO) + { // if opt is ")" and opta is "(" the bracket has been evaluated, now its time to check // if there is either a function or a sign pending // neither the opening nor the closing bracket will be pushed back to // the operator stack - // Check if a function is standing in front of the opening bracket, + // Check if a function is standing in front of the opening bracket, // if yes evaluate it afterwards check for infix operators assert(stArgCount.size()); int iArgCount = stArgCount.pop(); - + stOpt.pop(); // Take opening bracket from stack - if (iArgCount>1 && ( stOpt.size()==0 || - (stOpt.top().GetCode()!=cmFUNC && - stOpt.top().GetCode()!=cmFUNC_BULK && - stOpt.top().GetCode()!=cmFUNC_STR) ) ) - Error(ecUNEXPECTED_ARG, m_pTokenReader->GetPos()); - + if (iArgCount > 1 && (stOpt.size() == 0 || + (stOpt.top().GetCode() != cmFUNC && stOpt.top().GetCode() != cmFUNC_BULK && + stOpt.top().GetCode() != cmFUNC_STR))) + Error(ecUNEXPECTED_ARG, m_pTokenReader->GetPos()); + // The opening bracket was popped from the stack now check if there // was a function before this bracket - if (stOpt.size() && - stOpt.top().GetCode()!=cmOPRT_INFIX && - stOpt.top().GetCode()!=cmOPRT_BIN && - stOpt.top().GetFuncAddr()!=0) + if (stOpt.size() && stOpt.top().GetCode() != cmOPRT_INFIX && stOpt.top().GetCode() != cmOPRT_BIN && + stOpt.top().GetFuncAddr() != 0) { - ApplyFunc(stOpt, stVal, iArgCount); + ApplyFunc(stOpt, stVal, iArgCount); } - } - } // if bracket content is evaluated - break; - - // - // Next are the binary operator entries - // - //case cmAND: // built in binary operators - //case cmOR: - //case cmXOR: - case cmIF: + } + } // if bracket content is evaluated + break; + + // + // Next are the binary operator entries + // + // case cmAND: // built in binary operators + // case cmOR: + // case cmXOR: + case cmIF: m_nIfElseCounter++; // fallthrough intentional (no break!) - case cmLAND: - case cmLOR: - case cmLT: - case cmGT: - case cmLE: - case cmGE: - case cmNEQ: - case cmEQ: - case cmADD: - case cmSUB: - case cmMUL: - case cmDIV: - case cmPOW: - case cmASSIGN: - case cmOPRT_BIN: - - // A binary operator (user defined or built in) has been found. - while ( stOpt.size() && - stOpt.top().GetCode() != cmBO && - stOpt.top().GetCode() != cmELSE && - stOpt.top().GetCode() != cmIF) + case cmLAND: + case cmLOR: + case cmLT: + case cmGT: + case cmLE: + case cmGE: + case cmNEQ: + case cmEQ: + case cmADD: + case cmSUB: + case cmMUL: + case cmDIV: + case cmPOW: + case cmASSIGN: + case cmOPRT_BIN: + + // A binary operator (user defined or built in) has been found. + while (stOpt.size() && stOpt.top().GetCode() != cmBO && stOpt.top().GetCode() != cmELSE && + stOpt.top().GetCode() != cmIF) { - int nPrec1 = GetOprtPrecedence(stOpt.top()), - nPrec2 = GetOprtPrecedence(opt); - - if (stOpt.top().GetCode()==opt.GetCode()) - { + int nPrec1 = GetOprtPrecedence(stOpt.top()), nPrec2 = GetOprtPrecedence(opt); - // Deal with operator associativity - EOprtAssociativity eOprtAsct = GetOprtAssociativity(opt); - if ( (eOprtAsct==oaRIGHT && (nPrec1 <= nPrec2)) || - (eOprtAsct==oaLEFT && (nPrec1 < nPrec2)) ) + if (stOpt.top().GetCode() == opt.GetCode()) { - break; + // Deal with operator associativity + EOprtAssociativity eOprtAsct = GetOprtAssociativity(opt); + if ((eOprtAsct == oaRIGHT && (nPrec1 <= nPrec2)) || (eOprtAsct == oaLEFT && (nPrec1 < nPrec2))) + { + break; + } } - } - else if (nPrec1 < nPrec2) - { - // In case the operators are not equal the precedence decides alone... - break; - } - - if (stOpt.top().GetCode()==cmOPRT_INFIX) - ApplyFunc(stOpt, stVal, 1); - else - ApplyBinOprt(stOpt, stVal); + else if (nPrec1 < nPrec2) + { + // In case the operators are not equal the precedence decides alone... + break; + } + + if (stOpt.top().GetCode() == cmOPRT_INFIX) + ApplyFunc(stOpt, stVal, 1); + else + ApplyBinOprt(stOpt, stVal); } // while ( ... ) - if (opt.GetCode()==cmIF) - m_vRPN.AddIfElse(opt.GetCode()); + if (opt.GetCode() == cmIF) + m_vRPN.AddIfElse(opt.GetCode()); - // The operator can't be evaluated right now, push back to the operator stack + // The operator can't be evaluated right now, push back to the operator stack stOpt.push(opt); break; - // - // Last section contains functions and operators implicitly mapped to functions - // - case cmBO: + // + // Last section contains functions and operators implicitly mapped to functions + // + case cmBO: stArgCount.push(1); stOpt.push(opt); break; - case cmOPRT_INFIX: - case cmFUNC: - case cmFUNC_BULK: - case cmFUNC_STR: + case cmOPRT_INFIX: + case cmFUNC: + case cmFUNC_BULK: + case cmFUNC_STR: stOpt.push(opt); break; - case cmOPRT_POSTFIX: + case cmOPRT_POSTFIX: stOpt.push(opt); - ApplyFunc(stOpt, stVal, 1); // this is the postfix operator + ApplyFunc(stOpt, stVal, 1); // this is the postfix operator break; - default: Error(ecINTERNAL_ERROR, 3); - } // end of switch operator-token + default: + Error(ecINTERNAL_ERROR, 3); + } // end of switch operator-token - opta = opt; + opta = opt; - if ( opt.GetCode() == cmEND ) - { - m_vRPN.Finalize(); - break; - } + if (opt.GetCode() == cmEND) + { + m_vRPN.Finalize(); + break; + } - if (ParserBase::g_DbgDumpStack) - { - StackDump(stVal, stOpt); - m_vRPN.AsciiDump(); - } + if (ParserBase::g_DbgDumpStack) + { + StackDump(stVal, stOpt); + m_vRPN.AsciiDump(); + } } // while (true) if (ParserBase::g_DbgDumpCmdCode) - m_vRPN.AsciiDump(); + m_vRPN.AsciiDump(); - if (m_nIfElseCounter>0) - Error(ecMISSING_ELSE_CLAUSE); + if (m_nIfElseCounter > 0) + Error(ecMISSING_ELSE_CLAUSE); // get the last value (= final result) from the stack - MUP_ASSERT(stArgCount.size()==1); + MUP_ASSERT(stArgCount.size() == 1); m_nFinalResultIdx = stArgCount.top(); - if (m_nFinalResultIdx==0) - Error(ecINTERNAL_ERROR, 9); + if (m_nFinalResultIdx == 0) + Error(ecINTERNAL_ERROR, 9); - if (stVal.size()==0) - Error(ecEMPTY_EXPRESSION); + if (stVal.size() == 0) + Error(ecEMPTY_EXPRESSION); - if (stVal.top().GetType()!=tpDBL) - Error(ecSTR_RESULT); + if (stVal.top().GetType() != tpDBL) + Error(ecSTR_RESULT); m_vStackBuffer.resize(m_vRPN.GetMaxStackSize() * s_MaxNumOpenMPThreads); - } - - //--------------------------------------------------------------------------- - /** \brief One of the two main parse functions. - \sa ParseCmdCode(...) - - Parse expression from input string. Perform syntax checking and create - bytecode. After parsing the string and creating the bytecode the function - pointer #m_pParseFormula will be changed to the second parse routine the - uses bytecode instead of string parsing. - */ - value_type ParserBase::ParseString() const - { +} + +//--------------------------------------------------------------------------- +/** \brief One of the two main parse functions. + \sa ParseCmdCode(...) + + Parse expression from input string. Perform syntax checking and create + bytecode. After parsing the string and creating the bytecode the function + pointer #m_pParseFormula will be changed to the second parse routine the + uses bytecode instead of string parsing. +*/ +value_type ParserBase::ParseString() const +{ try { - CreateRPN(); - m_pParseFormula = &ParserBase::ParseCmdCode; - return (this->*m_pParseFormula)(); + CreateRPN(); + m_pParseFormula = &ParserBase::ParseCmdCode; + return (this->*m_pParseFormula)(); } - catch(ParserError &exc) + catch (ParserError& exc) { - exc.SetFormula(m_pTokenReader->GetExpr()); - throw; + exc.SetFormula(m_pTokenReader->GetExpr()); + throw; } - } +} - //--------------------------------------------------------------------------- - /** \brief Create an error containing the parse error position. +//--------------------------------------------------------------------------- +/** \brief Create an error containing the parse error position. - This function will create an Parser Exception object containing the error text and - its position. + This function will create an Parser Exception object containing the error text and + its position. - \param a_iErrc [in] The error code of type #EErrorCodes. - \param a_iPos [in] The position where the error was detected. - \param a_strTok [in] The token string representation associated with the error. - \throw ParserException always throws thats the only purpose of this function. - */ - void ParserBase::Error(EErrorCodes a_iErrc, int a_iPos, const string_type &a_sTok) const - { + \param a_iErrc [in] The error code of type #EErrorCodes. + \param a_iPos [in] The position where the error was detected. + \param a_strTok [in] The token string representation associated with the error. + \throw ParserException always throws thats the only purpose of this function. +*/ +void ParserBase::Error(EErrorCodes a_iErrc, int a_iPos, const string_type& a_sTok) const +{ throw exception_type(a_iErrc, a_sTok, m_pTokenReader->GetExpr(), a_iPos); - } +} - //------------------------------------------------------------------------------ - /** \brief Clear all user defined variables. - \throw nothrow +//------------------------------------------------------------------------------ +/** \brief Clear all user defined variables. + \throw nothrow - Resets the parser to string parsing mode by calling #ReInit. - */ - void ParserBase::ClearVar() - { + Resets the parser to string parsing mode by calling #ReInit. +*/ +void ParserBase::ClearVar() +{ m_VarDef.clear(); ReInit(); - } +} - //------------------------------------------------------------------------------ - /** \brief Remove a variable from internal storage. - \throw nothrow +//------------------------------------------------------------------------------ +/** \brief Remove a variable from internal storage. + \throw nothrow - Removes a variable if it exists. If the Variable does not exist nothing will be done. - */ - void ParserBase::RemoveVar(const string_type &a_strVarName) - { + Removes a variable if it exists. If the Variable does not exist nothing will be done. +*/ +void ParserBase::RemoveVar(const string_type& a_strVarName) +{ varmap_type::iterator item = m_VarDef.find(a_strVarName); - if (item!=m_VarDef.end()) + if (item != m_VarDef.end()) { - m_VarDef.erase(item); - ReInit(); + m_VarDef.erase(item); + ReInit(); } - } - - //------------------------------------------------------------------------------ - /** \brief Clear all functions. - \post Resets the parser to string parsing mode. - \throw nothrow - */ - void ParserBase::ClearFun() - { +} + +//------------------------------------------------------------------------------ +/** \brief Clear all functions. + \post Resets the parser to string parsing mode. + \throw nothrow +*/ +void ParserBase::ClearFun() +{ m_FunDef.clear(); ReInit(); - } +} - //------------------------------------------------------------------------------ - /** \brief Clear all user defined constants. +//------------------------------------------------------------------------------ +/** \brief Clear all user defined constants. - Both numeric and string constants will be removed from the internal storage. - \post Resets the parser to string parsing mode. - \throw nothrow - */ - void ParserBase::ClearConst() - { + Both numeric and string constants will be removed from the internal storage. + \post Resets the parser to string parsing mode. + \throw nothrow +*/ +void ParserBase::ClearConst() +{ m_ConstDef.clear(); m_StrVarDef.clear(); ReInit(); - } - - //------------------------------------------------------------------------------ - /** \brief Clear all user defined postfix operators. - \post Resets the parser to string parsing mode. - \throw nothrow - */ - void ParserBase::ClearPostfixOprt() - { +} + +//------------------------------------------------------------------------------ +/** \brief Clear all user defined postfix operators. + \post Resets the parser to string parsing mode. + \throw nothrow +*/ +void ParserBase::ClearPostfixOprt() +{ m_PostOprtDef.clear(); ReInit(); - } - - //------------------------------------------------------------------------------ - /** \brief Clear all user defined binary operators. - \post Resets the parser to string parsing mode. - \throw nothrow - */ - void ParserBase::ClearOprt() - { +} + +//------------------------------------------------------------------------------ +/** \brief Clear all user defined binary operators. + \post Resets the parser to string parsing mode. + \throw nothrow +*/ +void ParserBase::ClearOprt() +{ m_OprtDef.clear(); ReInit(); - } - - //------------------------------------------------------------------------------ - /** \brief Clear the user defined Prefix operators. - \post Resets the parser to string parser mode. - \throw nothrow - */ - void ParserBase::ClearInfixOprt() - { +} + +//------------------------------------------------------------------------------ +/** \brief Clear the user defined Prefix operators. + \post Resets the parser to string parser mode. + \throw nothrow +*/ +void ParserBase::ClearInfixOprt() +{ m_InfixOprtDef.clear(); ReInit(); - } - - //------------------------------------------------------------------------------ - /** \brief Enable or disable the formula optimization feature. - \post Resets the parser to string parser mode. - \throw nothrow - */ - void ParserBase::EnableOptimizer(bool a_bIsOn) - { +} + +//------------------------------------------------------------------------------ +/** \brief Enable or disable the formula optimization feature. + \post Resets the parser to string parser mode. + \throw nothrow +*/ +void ParserBase::EnableOptimizer(bool a_bIsOn) +{ m_vRPN.EnableOptimizer(a_bIsOn); ReInit(); - } +} - //--------------------------------------------------------------------------- - /** \brief Enable the dumping of bytecode and stack content on the console. - \param bDumpCmd Flag to enable dumping of the current bytecode to the console. - \param bDumpStack Flag to enable dumping of the stack content is written to the console. +//--------------------------------------------------------------------------- +/** \brief Enable the dumping of bytecode and stack content on the console. + \param bDumpCmd Flag to enable dumping of the current bytecode to the console. + \param bDumpStack Flag to enable dumping of the stack content is written to the console. - This function is for debug purposes only! - */ - void ParserBase::EnableDebugDump(bool bDumpCmd, bool bDumpStack) - { + This function is for debug purposes only! +*/ +void ParserBase::EnableDebugDump(bool bDumpCmd, bool bDumpStack) +{ ParserBase::g_DbgDumpCmdCode = bDumpCmd; - ParserBase::g_DbgDumpStack = bDumpStack; - } - - //------------------------------------------------------------------------------ - /** \brief Enable or disable the built in binary operators. - \throw nothrow - \sa m_bBuiltInOp, ReInit() - - If you disable the built in binary operators there will be no binary operators - defined. Thus you must add them manually one by one. It is not possible to - disable built in operators selectively. This function will Reinitialize the - parser by calling ReInit(). - */ - void ParserBase::EnableBuiltInOprt(bool a_bIsOn) - { + ParserBase::g_DbgDumpStack = bDumpStack; +} + +//------------------------------------------------------------------------------ +/** \brief Enable or disable the built in binary operators. + \throw nothrow + \sa m_bBuiltInOp, ReInit() + + If you disable the built in binary operators there will be no binary operators + defined. Thus you must add them manually one by one. It is not possible to + disable built in operators selectively. This function will Reinitialize the + parser by calling ReInit(). +*/ +void ParserBase::EnableBuiltInOprt(bool a_bIsOn) +{ m_bBuiltInOp = a_bIsOn; ReInit(); - } - - //------------------------------------------------------------------------------ - /** \brief Query status of built in variables. - \return #m_bBuiltInOp; true if built in operators are enabled. - \throw nothrow - */ - bool ParserBase::HasBuiltInOprt() const - { +} + +//------------------------------------------------------------------------------ +/** \brief Query status of built in variables. + \return #m_bBuiltInOp; true if built in operators are enabled. + \throw nothrow +*/ +bool ParserBase::HasBuiltInOprt() const +{ return m_bBuiltInOp; - } +} - //------------------------------------------------------------------------------ - /** \brief Get the argument separator character. - */ - char_type ParserBase::GetArgSep() const - { +//------------------------------------------------------------------------------ +/** \brief Get the argument separator character. + */ +char_type ParserBase::GetArgSep() const +{ return m_pTokenReader->GetArgSep(); - } - - //------------------------------------------------------------------------------ - /** \brief Set argument separator. - \param cArgSep the argument separator character. - */ - void ParserBase::SetArgSep(char_type cArgSep) - { +} + +//------------------------------------------------------------------------------ +/** \brief Set argument separator. + \param cArgSep the argument separator character. +*/ +void ParserBase::SetArgSep(char_type cArgSep) +{ m_pTokenReader->SetArgSep(cArgSep); - } +} - //------------------------------------------------------------------------------ - /** \brief Dump stack content. +//------------------------------------------------------------------------------ +/** \brief Dump stack content. - This function is used for debugging only. - */ - void ParserBase::StackDump(const ParserStack &a_stVal, - const ParserStack &a_stOprt) const - { - ParserStack stOprt(a_stOprt), - stVal(a_stVal); + This function is used for debugging only. +*/ +void ParserBase::StackDump(const ParserStack& a_stVal, const ParserStack& a_stOprt) const +{ + ParserStack stOprt(a_stOprt), stVal(a_stVal); mu::console() << _T("\nValue stack:\n"); - while ( !stVal.empty() ) + while (!stVal.empty()) { - token_type val = stVal.pop(); - if (val.GetType()==tpSTR) - mu::console() << _T(" \"") << val.GetAsString() << _T("\" "); - else - mu::console() << _T(" ") << val.GetVal() << _T(" "); + token_type val = stVal.pop(); + if (val.GetType() == tpSTR) + mu::console() << _T(" \"") << val.GetAsString() << _T("\" "); + else + mu::console() << _T(" ") << val.GetVal() << _T(" "); } mu::console() << "\nOperator stack:\n"; - while ( !stOprt.empty() ) + while (!stOprt.empty()) { - if (stOprt.top().GetCode()<=cmASSIGN) - { - mu::console() << _T("OPRT_INTRNL \"") - << ParserBase::c_DefaultOprt[stOprt.top().GetCode()] - << _T("\" \n"); - } - else - { - switch(stOprt.top().GetCode()) + if (stOprt.top().GetCode() <= cmASSIGN) { - case cmVAR: mu::console() << _T("VAR\n"); break; - case cmVAL: mu::console() << _T("VAL\n"); break; - case cmFUNC: mu::console() << _T("FUNC \"") - << stOprt.top().GetAsString() - << _T("\"\n"); break; - case cmFUNC_BULK: mu::console() << _T("FUNC_BULK \"") - << stOprt.top().GetAsString() - << _T("\"\n"); break; - case cmOPRT_INFIX: mu::console() << _T("OPRT_INFIX \"") - << stOprt.top().GetAsString() - << _T("\"\n"); break; - case cmOPRT_BIN: mu::console() << _T("OPRT_BIN \"") - << stOprt.top().GetAsString() - << _T("\"\n"); break; - case cmFUNC_STR: mu::console() << _T("FUNC_STR\n"); break; - case cmEND: mu::console() << _T("END\n"); break; - case cmUNKNOWN: mu::console() << _T("UNKNOWN\n"); break; - case cmBO: mu::console() << _T("BRACKET \"(\"\n"); break; - case cmBC: mu::console() << _T("BRACKET \")\"\n"); break; - case cmIF: mu::console() << _T("IF\n"); break; - case cmELSE: mu::console() << _T("ELSE\n"); break; - case cmENDIF: mu::console() << _T("ENDIF\n"); break; - default: mu::console() << stOprt.top().GetCode() << _T(" "); break; + mu::console() << _T("OPRT_INTRNL \"") << ParserBase::c_DefaultOprt[stOprt.top().GetCode()] << _T("\" \n"); + } + else + { + switch (stOprt.top().GetCode()) + { + case cmVAR: + mu::console() << _T("VAR\n"); + break; + case cmVAL: + mu::console() << _T("VAL\n"); + break; + case cmFUNC: + mu::console() << _T("FUNC \"") << stOprt.top().GetAsString() << _T("\"\n"); + break; + case cmFUNC_BULK: + mu::console() << _T("FUNC_BULK \"") << stOprt.top().GetAsString() << _T("\"\n"); + break; + case cmOPRT_INFIX: + mu::console() << _T("OPRT_INFIX \"") << stOprt.top().GetAsString() << _T("\"\n"); + break; + case cmOPRT_BIN: + mu::console() << _T("OPRT_BIN \"") << stOprt.top().GetAsString() << _T("\"\n"); + break; + case cmFUNC_STR: + mu::console() << _T("FUNC_STR\n"); + break; + case cmEND: + mu::console() << _T("END\n"); + break; + case cmUNKNOWN: + mu::console() << _T("UNKNOWN\n"); + break; + case cmBO: + mu::console() << _T("BRACKET \"(\"\n"); + break; + case cmBC: + mu::console() << _T("BRACKET \")\"\n"); + break; + case cmIF: + mu::console() << _T("IF\n"); + break; + case cmELSE: + mu::console() << _T("ELSE\n"); + break; + case cmENDIF: + mu::console() << _T("ENDIF\n"); + break; + default: + mu::console() << stOprt.top().GetCode() << _T(" "); + break; + } } - } - stOprt.pop(); + stOprt.pop(); } mu::console() << dec << endl; - } - - //------------------------------------------------------------------------------ - /** \brief Evaluate an expression containing comma separated subexpressions - \param [out] nStackSize The total number of results available - \return Pointer to the array containing all expression results - - This member function can be used to retrieve all results of an expression - made up of multiple comma separated subexpressions (i.e. "x+y,sin(x),cos(y)") - */ - value_type* ParserBase::Eval(int &nStackSize) const - { - (this->*m_pParseFormula)(); +} + +//------------------------------------------------------------------------------ +/** \brief Evaluate an expression containing comma separated subexpressions + \param [out] nStackSize The total number of results available + \return Pointer to the array containing all expression results + + This member function can be used to retrieve all results of an expression + made up of multiple comma separated subexpressions (i.e. "x+y,sin(x),cos(y)") +*/ +value_type* ParserBase::Eval(int& nStackSize) const +{ + (this->*m_pParseFormula)(); nStackSize = m_nFinalResultIdx; // (for historic reasons the stack starts at position 1) return &m_vStackBuffer[1]; - } - - //--------------------------------------------------------------------------- - /** \brief Return the number of results on the calculation stack. - - If the expression contains comma separated subexpressions (i.e. "sin(y), x+y"). - There may be more than one return value. This function returns the number of - available results. - */ - int ParserBase::GetNumResults() const - { +} + +//--------------------------------------------------------------------------- +/** \brief Return the number of results on the calculation stack. + + If the expression contains comma separated subexpressions (i.e. "sin(y), x+y"). + There may be more than one return value. This function returns the number of + available results. +*/ +int ParserBase::GetNumResults() const +{ return m_nFinalResultIdx; - } - - //--------------------------------------------------------------------------- - /** \brief Calculate the result. - - A note on const correctness: - I consider it important that Calc is a const function. - Due to caching operations Calc changes only the state of internal variables with one exception - m_UsedVar this is reset during string parsing and accessible from the outside. Instead of making - Calc non const GetUsedVar is non const because it explicitly calls Eval() forcing this update. - - \pre A formula must be set. - \pre Variables must have been set (if needed) - - \sa #m_pParseFormula - \return The evaluation result - \throw ParseException if no Formula is set or in case of any other error related to the formula. - */ - value_type ParserBase::Eval() const - { - return (this->*m_pParseFormula)(); - } - - //--------------------------------------------------------------------------- - void ParserBase::Eval(value_type *results, int nBulkSize) - { -/* Commented because it is making a unit test impossible - - // Parallelization does not make sense for fewer than 10000 computations - // due to thread creation overhead. If the bulk size is below 2000 - // computation is refused. - if (nBulkSize<2000) - { - throw ParserError(ecUNREASONABLE_NUMBER_OF_COMPUTATIONS); - } +} + +//--------------------------------------------------------------------------- +/** \brief Calculate the result. + + A note on const correctness: + I consider it important that Calc is a const function. + Due to caching operations Calc changes only the state of internal variables with one exception + m_UsedVar this is reset during string parsing and accessible from the outside. Instead of making + Calc non const GetUsedVar is non const because it explicitly calls Eval() forcing this update. + + \pre A formula must be set. + \pre Variables must have been set (if needed) + + \sa #m_pParseFormula + \return The evaluation result + \throw ParseException if no Formula is set or in case of any other error related to the formula. */ +value_type ParserBase::Eval() const +{ + return (this->*m_pParseFormula)(); +} + +//--------------------------------------------------------------------------- +void ParserBase::Eval(value_type* results, int nBulkSize) +{ + /* Commented because it is making a unit test impossible + + // Parallelization does not make sense for fewer than 10000 computations + // due to thread creation overhead. If the bulk size is below 2000 + // computation is refused. + if (nBulkSize<2000) + { + throw ParserError(ecUNREASONABLE_NUMBER_OF_COMPUTATIONS); + } + */ CreateRPN(); int i = 0; #ifdef MUP_USE_OPENMP -//#define DEBUG_OMP_STUFF - #ifdef DEBUG_OMP_STUFF - int *pThread = new int[nBulkSize]; - int *pIdx = new int[nBulkSize]; - #endif + //#define DEBUG_OMP_STUFF +#ifdef DEBUG_OMP_STUFF + int* pThread = new int[nBulkSize]; + int* pIdx = new int[nBulkSize]; +#endif int nMaxThreads = std::min(omp_get_max_threads(), s_MaxNumOpenMPThreads); - int nThreadID = 0, ct = 0; + int nThreadID = 0, ct = 0; omp_set_num_threads(nMaxThreads); - #pragma omp parallel for schedule(static, nBulkSize/nMaxThreads) private(nThreadID) - for (i=0; i \___ >|__| - \/ \/ \/ \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ Copyright (C) 2013 Ingo Berg - Permission is hereby granted, free of charge, to any person obtaining a copy of this + 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 + 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 + 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. + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MU_PARSER_BASE_H #define MU_PARSER_BASE_H @@ -41,7 +41,6 @@ #include "muParserBytecode.h" #include "muParserError.h" - namespace mu { /** \file @@ -52,26 +51,25 @@ namespace mu /** \brief Mathematical expressions parser (base parser engine). \author (C) 2013 Ingo Berg - This is the implementation of a bytecode based mathematical expressions parser. - The formula will be parsed from string and converted into a bytecode. + This is the implementation of a bytecode based mathematical expressions parser. + The formula will be parsed from string and converted into a bytecode. Future calculations will be done with the bytecode instead the formula string - resulting in a significant performance increase. - Complementary to a set of internally implemented functions the parser is able to handle - user defined functions and variables. + resulting in a significant performance increase. + Complementary to a set of internally implemented functions the parser is able to handle + user defined functions and variables. */ -class ParserBase +class ParserBase { -friend class ParserTokenReader; + friend class ParserTokenReader; private: + /** \brief Typedef for the parse functions. - /** \brief Typedef for the parse functions. - The parse function do the actual work. The parser exchanges - the function pointer to the parser function depending on + the function pointer to the parser function depending on which state it is in. (i.e. bytecode parser vs. string parser) */ - typedef value_type (ParserBase::*ParseFunction)() const; + typedef value_type (ParserBase::*ParseFunction)() const; /** \brief Type used for storing an array of values. */ typedef std::vector valbuf_type; @@ -81,70 +79,70 @@ friend class ParserTokenReader; /** \brief Typedef for the token reader. */ typedef ParserTokenReader token_reader_type; - + /** \brief Type used for parser tokens. */ typedef ParserToken token_type; /** \brief Maximum number of threads spawned by OpenMP when using the bulk mode. */ static const int s_MaxNumOpenMPThreads = 16; - public: +public: + /** \brief Type of the error class. - /** \brief Type of the error class. - Included for backwards compatibility. */ typedef ParserError exception_type; static void EnableDebugDump(bool bDumpCmd, bool bDumpStack); - ParserBase(); - ParserBase(const ParserBase &a_Parser); - ParserBase& operator=(const ParserBase &a_Parser); + ParserBase(); + ParserBase(const ParserBase& a_Parser); + ParserBase& operator=(const ParserBase& a_Parser); virtual ~ParserBase(); - - value_type Eval() const; - value_type* Eval(int &nStackSize) const; - void Eval(value_type *results, int nBulkSize); + + value_type Eval() const; + value_type* Eval(int& nStackSize) const; + void Eval(value_type* results, int nBulkSize); int GetNumResults() const; - void SetExpr(const string_type &a_sExpr); - void SetVarFactory(facfun_type a_pFactory, void *pUserData = NULL); + void SetExpr(const string_type& a_sExpr); + void SetVarFactory(facfun_type a_pFactory, void* pUserData = NULL); void SetDecSep(char_type cDecSep); void SetThousandsSep(char_type cThousandsSep = 0); void ResetLocale(); - void EnableOptimizer(bool a_bIsOn=true); - void EnableBuiltInOprt(bool a_bIsOn=true); + void EnableOptimizer(bool a_bIsOn = true); + void EnableBuiltInOprt(bool a_bIsOn = true); bool HasBuiltInOprt() const; void AddValIdent(identfun_type a_pCallback); - /** \fn void mu::ParserBase::DefineFun(const string_type &a_strName, fun_type0 a_pFun, bool a_bAllowOpt = true) + /** \fn void mu::ParserBase::DefineFun(const string_type &a_strName, fun_type0 a_pFun, bool a_bAllowOpt = true) \brief Define a parser function without arguments. \param a_strName Name of the function \param a_pFun Pointer to the callback function \param a_bAllowOpt A flag indicating this function may be optimized */ template - void DefineFun(const string_type &a_strName, T a_pFun, bool a_bAllowOpt = true) + void DefineFun(const string_type& a_strName, T a_pFun, bool a_bAllowOpt = true) { - AddCallback( a_strName, ParserCallback(a_pFun, a_bAllowOpt), m_FunDef, ValidNameChars() ); + AddCallback(a_strName, ParserCallback(a_pFun, a_bAllowOpt), m_FunDef, ValidNameChars()); } - void DefineOprt(const string_type &a_strName, - fun_type2 a_pFun, - unsigned a_iPri=0, + void DefineOprt(const string_type& a_strName, + fun_type2 a_pFun, + unsigned a_iPri = 0, EOprtAssociativity a_eAssociativity = oaLEFT, bool a_bAllowOpt = false); - void DefineConst(const string_type &a_sName, value_type a_fVal); - void DefineStrConst(const string_type &a_sName, const string_type &a_strVal); - void DefineVar(const string_type &a_sName, value_type *a_fVar); - void DefinePostfixOprt(const string_type &a_strFun, fun_type1 a_pOprt, bool a_bAllowOpt=true); - void DefineInfixOprt(const string_type &a_strName, fun_type1 a_pOprt, int a_iPrec=prINFIX, bool a_bAllowOpt=true); + void DefineConst(const string_type& a_sName, value_type a_fVal); + void DefineStrConst(const string_type& a_sName, const string_type& a_strVal); + void DefineVar(const string_type& a_sName, value_type* a_fVar); + void DefinePostfixOprt(const string_type& a_strFun, fun_type1 a_pOprt, bool a_bAllowOpt = true); + void + DefineInfixOprt(const string_type& a_strName, fun_type1 a_pOprt, int a_iPrec = prINFIX, bool a_bAllowOpt = true); // Clear user defined variables, constants or functions void ClearVar(); @@ -153,8 +151,8 @@ friend class ParserTokenReader; void ClearInfixOprt(); void ClearPostfixOprt(); void ClearOprt(); - - void RemoveVar(const string_type &a_strVarName); + + void RemoveVar(const string_type& a_strVarName); const varmap_type& GetUsedVar() const; const varmap_type& GetVar() const; const valmap_type& GetConst() const; @@ -162,10 +160,10 @@ friend class ParserTokenReader; const funmap_type& GetFunDef() const; string_type GetVersion(EParserVersionInfo eInfo = pviFULL) const; - const char_type ** GetOprtDef() const; - void DefineNameChars(const char_type *a_szCharset); - void DefineOprtChars(const char_type *a_szCharset); - void DefineInfixOprtChars(const char_type *a_szCharset); + const char_type** GetOprtDef() const; + void DefineNameChars(const char_type* a_szCharset); + void DefineOprtChars(const char_type* a_szCharset); + void DefineInfixOprtChars(const char_type* a_szCharset); const char_type* ValidNameChars() const; const char_type* ValidOprtChars() const; @@ -173,24 +171,23 @@ friend class ParserTokenReader; void SetArgSep(char_type cArgSep); char_type GetArgSep() const; - - void Error(EErrorCodes a_iErrc, - int a_iPos = (int)mu::string_type::npos, - const string_type &a_strTok = string_type() ) const; - protected: - + void Error(EErrorCodes a_iErrc, + int a_iPos = (int)mu::string_type::npos, + const string_type& a_strTok = string_type()) const; + +protected: void Init(); virtual void InitCharSets() = 0; virtual void InitFun() = 0; virtual void InitConst() = 0; - virtual void InitOprt() = 0; + virtual void InitOprt() = 0; - virtual void OnDetectVar(string_type *pExpr, int &nStart, int &nEnd); + virtual void OnDetectVar(string_type* pExpr, int& nStart, int& nEnd); - static const char_type *c_DefaultOprt[]; - static std::locale s_locale; ///< The locale used by the parser + static const char_type* c_DefaultOprt[]; + static std::locale s_locale; ///< The locale used by the parser static bool g_DbgDumpCmdCode; static bool g_DbgDumpStack; @@ -199,112 +196,91 @@ friend class ParserTokenReader; class change_dec_sep : public std::numpunct { public: - - explicit change_dec_sep(char_type cDecSep, char_type cThousandsSep = 0, int nGroup = 3) - :std::numpunct() - ,m_nGroup(nGroup) - ,m_cDecPoint(cDecSep) - ,m_cThousandsSep(cThousandsSep) - {} - + explicit change_dec_sep(char_type cDecSep, char_type cThousandsSep = 0, int nGroup = 3) : + std::numpunct(), m_nGroup(nGroup), m_cDecPoint(cDecSep), m_cThousandsSep(cThousandsSep) + { + } + protected: - - virtual char_type do_decimal_point() const - { - return m_cDecPoint; - } - - virtual char_type do_thousands_sep() const - { - return m_cThousandsSep; - } - - virtual std::string do_grouping() const - { - // fix for issue 4: https://code.google.com/p/muparser/issues/detail?id=4 - // courtesy of Jens Bartsch - // original code: - // return std::string(1, (char)m_nGroup); - // new code: - return std::string(1, (char)(m_cThousandsSep > 0 ? m_nGroup : CHAR_MAX)); - } + virtual char_type do_decimal_point() const { return m_cDecPoint; } - private: + virtual char_type do_thousands_sep() const { return m_cThousandsSep; } - int m_nGroup; - char_type m_cDecPoint; - char_type m_cThousandsSep; - }; + virtual std::string do_grouping() const + { + // fix for issue 4: https://code.google.com/p/muparser/issues/detail?id=4 + // courtesy of Jens Bartsch + // original code: + // return std::string(1, (char)m_nGroup); + // new code: + return std::string(1, (char)(m_cThousandsSep > 0 ? m_nGroup : CHAR_MAX)); + } - private: + private: + int m_nGroup; + char_type m_cDecPoint; + char_type m_cThousandsSep; + }; - void Assign(const ParserBase &a_Parser); +private: + void Assign(const ParserBase& a_Parser); void InitTokenReader(); void ReInit() const; - void AddCallback( const string_type &a_strName, - const ParserCallback &a_Callback, - funmap_type &a_Storage, - const char_type *a_szCharSet ); + void AddCallback(const string_type& a_strName, + const ParserCallback& a_Callback, + funmap_type& a_Storage, + const char_type* a_szCharSet); - void ApplyRemainingOprt(ParserStack &a_stOpt, - ParserStack &a_stVal) const; - void ApplyBinOprt(ParserStack &a_stOpt, - ParserStack &a_stVal) const; + void ApplyRemainingOprt(ParserStack& a_stOpt, ParserStack& a_stVal) const; + void ApplyBinOprt(ParserStack& a_stOpt, ParserStack& a_stVal) const; - void ApplyIfElse(ParserStack &a_stOpt, - ParserStack &a_stVal) const; + void ApplyIfElse(ParserStack& a_stOpt, ParserStack& a_stVal) const; - void ApplyFunc(ParserStack &a_stOpt, - ParserStack &a_stVal, - int iArgCount) const; + void ApplyFunc(ParserStack& a_stOpt, ParserStack& a_stVal, int iArgCount) const; - token_type ApplyStrFunc(const token_type &a_FunTok, - const std::vector &a_vArg) const; + token_type ApplyStrFunc(const token_type& a_FunTok, const std::vector& a_vArg) const; - int GetOprtPrecedence(const token_type &a_Tok) const; - EOprtAssociativity GetOprtAssociativity(const token_type &a_Tok) const; + int GetOprtPrecedence(const token_type& a_Tok) const; + EOprtAssociativity GetOprtAssociativity(const token_type& a_Tok) const; void CreateRPN() const; - value_type ParseString() const; + value_type ParseString() const; value_type ParseCmdCode() const; value_type ParseCmdCodeBulk(int nOffset, int nThreadID) const; - void CheckName(const string_type &a_strName, const string_type &a_CharSet) const; - void CheckOprt(const string_type &a_sName, - const ParserCallback &a_Callback, - const string_type &a_szCharSet) const; + void CheckName(const string_type& a_strName, const string_type& a_CharSet) const; + void CheckOprt(const string_type& a_sName, const ParserCallback& a_Callback, const string_type& a_szCharSet) const; - void StackDump(const ParserStack &a_stVal, - const ParserStack &a_stOprt) const; + void StackDump(const ParserStack& a_stVal, const ParserStack& a_stOprt) const; + + /** \brief Pointer to the parser function. - /** \brief Pointer to the parser function. - Eval() calls the function whose address is stored there. */ - mutable ParseFunction m_pParseFormula; - mutable ParserByteCode m_vRPN; ///< The Bytecode class. - mutable stringbuf_type m_vStringBuf; ///< String buffer, used for storing string function arguments - stringbuf_type m_vStringVarBuf; + mutable ParseFunction m_pParseFormula; + mutable ParserByteCode m_vRPN; ///< The Bytecode class. + mutable stringbuf_type m_vStringBuf; ///< String buffer, used for storing string function arguments + stringbuf_type m_vStringVarBuf; std::auto_ptr m_pTokenReader; ///< Managed pointer to the token reader object. - funmap_type m_FunDef; ///< Map of function names and pointers. - funmap_type m_PostOprtDef; ///< Postfix operator callbacks - funmap_type m_InfixOprtDef; ///< unary infix operator. - funmap_type m_OprtDef; ///< Binary operator callbacks - valmap_type m_ConstDef; ///< user constants. - strmap_type m_StrVarDef; ///< user defined string constants - varmap_type m_VarDef; ///< user defind variables. + funmap_type m_FunDef; ///< Map of function names and pointers. + funmap_type m_PostOprtDef; ///< Postfix operator callbacks + funmap_type m_InfixOprtDef; ///< unary infix operator. + funmap_type m_OprtDef; ///< Binary operator callbacks + valmap_type m_ConstDef; ///< user constants. + strmap_type m_StrVarDef; ///< user defined string constants + varmap_type m_VarDef; ///< user defind variables. - bool m_bBuiltInOp; ///< Flag that can be used for switching built in operators on and off + bool m_bBuiltInOp; ///< Flag that can be used for switching built in operators on and off string_type m_sNameChars; ///< Charset for names string_type m_sOprtChars; ///< Charset for postfix/ binary operator tokens string_type m_sInfixOprtChars; ///< Charset for infix operator tokens - - mutable int m_nIfElseCounter; ///< Internal counter for keeping track of nested if-then-else clauses + + mutable int m_nIfElseCounter; ///< Internal counter for keeping track of nested if-then-else clauses // items merely used for caching state information mutable valbuf_type m_vStackBuffer; ///< This is merely a buffer used for the stack in the cmd parsing routine @@ -314,4 +290,3 @@ friend class ParserTokenReader; } // namespace mu #endif - diff --git a/ext_libs/muparser/muParserBytecode.cpp b/ext_libs/muparser/muParserBytecode.cpp old mode 100755 new mode 100644 index 86d99127..2d67f336 --- a/ext_libs/muparser/muParserBytecode.cpp +++ b/ext_libs/muparser/muParserBytecode.cpp @@ -1,26 +1,26 @@ /* - __________ - _____ __ __\______ \_____ _______ ______ ____ _______ + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ - |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| - \/ \/ \/ \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ Copyright (C) 2011 Ingo Berg - Permission is hereby granted, free of charge, to any person obtaining a copy of this + 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 + 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 + 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. + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "muParserBytecode.h" @@ -38,334 +38,370 @@ #include "muParserStack.h" #include "muParserTemplateMagic.h" - namespace mu { - //--------------------------------------------------------------------------- - /** \brief Bytecode default constructor. */ - ParserByteCode::ParserByteCode() - :m_iStackPos(0) - ,m_iMaxStackSize(0) - ,m_vRPN() - ,m_bEnableOptimizer(true) - { +//--------------------------------------------------------------------------- +/** \brief Bytecode default constructor. */ +ParserByteCode::ParserByteCode() : m_iStackPos(0), m_iMaxStackSize(0), m_vRPN(), m_bEnableOptimizer(true) +{ m_vRPN.reserve(50); - } - - //--------------------------------------------------------------------------- - /** \brief Copy constructor. - - Implemented in Terms of Assign(const ParserByteCode &a_ByteCode) - */ - ParserByteCode::ParserByteCode(const ParserByteCode &a_ByteCode) - { +} + +//--------------------------------------------------------------------------- +/** \brief Copy constructor. + + Implemented in Terms of Assign(const ParserByteCode &a_ByteCode) +*/ +ParserByteCode::ParserByteCode(const ParserByteCode& a_ByteCode) +{ Assign(a_ByteCode); - } - - //--------------------------------------------------------------------------- - /** \brief Assignment operator. - - Implemented in Terms of Assign(const ParserByteCode &a_ByteCode) - */ - ParserByteCode& ParserByteCode::operator=(const ParserByteCode &a_ByteCode) - { +} + +//--------------------------------------------------------------------------- +/** \brief Assignment operator. + + Implemented in Terms of Assign(const ParserByteCode &a_ByteCode) +*/ +ParserByteCode& ParserByteCode::operator=(const ParserByteCode& a_ByteCode) +{ Assign(a_ByteCode); return *this; - } +} - //--------------------------------------------------------------------------- - void ParserByteCode::EnableOptimizer(bool bStat) - { +//--------------------------------------------------------------------------- +void ParserByteCode::EnableOptimizer(bool bStat) +{ m_bEnableOptimizer = bStat; - } - - //--------------------------------------------------------------------------- - /** \brief Copy state of another object to this. - - \throw nowthrow - */ - void ParserByteCode::Assign(const ParserByteCode &a_ByteCode) - { - if (this==&a_ByteCode) - return; +} + +//--------------------------------------------------------------------------- +/** \brief Copy state of another object to this. + + \throw nowthrow +*/ +void ParserByteCode::Assign(const ParserByteCode& a_ByteCode) +{ + if (this == &a_ByteCode) + return; m_iStackPos = a_ByteCode.m_iStackPos; m_vRPN = a_ByteCode.m_vRPN; m_iMaxStackSize = a_ByteCode.m_iMaxStackSize; - m_bEnableOptimizer = a_ByteCode.m_bEnableOptimizer; - } - - //--------------------------------------------------------------------------- - /** \brief Add a Variable pointer to bytecode. - \param a_pVar Pointer to be added. - \throw nothrow - */ - void ParserByteCode::AddVar(value_type *a_pVar) - { + m_bEnableOptimizer = a_ByteCode.m_bEnableOptimizer; +} + +//--------------------------------------------------------------------------- +/** \brief Add a Variable pointer to bytecode. + \param a_pVar Pointer to be added. + \throw nothrow +*/ +void ParserByteCode::AddVar(value_type* a_pVar) +{ ++m_iStackPos; m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos); // optimization does not apply SToken tok; - tok.Cmd = cmVAR; - tok.Val.ptr = a_pVar; - tok.Val.data = 1; + tok.Cmd = cmVAR; + tok.Val.ptr = a_pVar; + tok.Val.data = 1; tok.Val.data2 = 0; m_vRPN.push_back(tok); - } - - //--------------------------------------------------------------------------- - /** \brief Add a Variable pointer to bytecode. - - Value entries in byte code consist of: -
    -
  • value array position of the value
  • -
  • the operator code according to ParserToken::cmVAL
  • -
  • the value stored in #mc_iSizeVal number of bytecode entries.
  • -
- - \param a_pVal Value to be added. - \throw nothrow - */ - void ParserByteCode::AddVal(value_type a_fVal) - { +} + +//--------------------------------------------------------------------------- +/** \brief Add a Variable pointer to bytecode. + + Value entries in byte code consist of: +
    +
  • value array position of the value
  • +
  • the operator code according to ParserToken::cmVAL
  • +
  • the value stored in #mc_iSizeVal number of bytecode entries.
  • +
+ + \param a_pVal Value to be added. + \throw nothrow +*/ +void ParserByteCode::AddVal(value_type a_fVal) +{ ++m_iStackPos; m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos); // If optimization does not apply SToken tok; tok.Cmd = cmVAL; - tok.Val.ptr = NULL; - tok.Val.data = 0; + tok.Val.ptr = NULL; + tok.Val.data = 0; tok.Val.data2 = a_fVal; m_vRPN.push_back(tok); - } +} - //--------------------------------------------------------------------------- - void ParserByteCode::ConstantFolding(ECmdCode a_Oprt) - { +//--------------------------------------------------------------------------- +void ParserByteCode::ConstantFolding(ECmdCode a_Oprt) +{ std::size_t sz = m_vRPN.size(); - value_type &x = m_vRPN[sz-2].Val.data2, - &y = m_vRPN[sz-1].Val.data2; + value_type &x = m_vRPN[sz - 2].Val.data2, &y = m_vRPN[sz - 1].Val.data2; switch (a_Oprt) { - case cmLAND: x = (int)x && (int)y; m_vRPN.pop_back(); break; - case cmLOR: x = (int)x || (int)y; m_vRPN.pop_back(); break; - case cmLT: x = x < y; m_vRPN.pop_back(); break; - case cmGT: x = x > y; m_vRPN.pop_back(); break; - case cmLE: x = x <= y; m_vRPN.pop_back(); break; - case cmGE: x = x >= y; m_vRPN.pop_back(); break; - case cmNEQ: x = x != y; m_vRPN.pop_back(); break; - case cmEQ: x = x == y; m_vRPN.pop_back(); break; - case cmADD: x = x + y; m_vRPN.pop_back(); break; - case cmSUB: x = x - y; m_vRPN.pop_back(); break; - case cmMUL: x = x * y; m_vRPN.pop_back(); break; - case cmDIV: + case cmLAND: + x = (int)x && (int)y; + m_vRPN.pop_back(); + break; + case cmLOR: + x = (int)x || (int)y; + m_vRPN.pop_back(); + break; + case cmLT: + x = x < y; + m_vRPN.pop_back(); + break; + case cmGT: + x = x > y; + m_vRPN.pop_back(); + break; + case cmLE: + x = x <= y; + m_vRPN.pop_back(); + break; + case cmGE: + x = x >= y; + m_vRPN.pop_back(); + break; + case cmNEQ: + x = x != y; + m_vRPN.pop_back(); + break; + case cmEQ: + x = x == y; + m_vRPN.pop_back(); + break; + case cmADD: + x = x + y; + m_vRPN.pop_back(); + break; + case cmSUB: + x = x - y; + m_vRPN.pop_back(); + break; + case cmMUL: + x = x * y; + m_vRPN.pop_back(); + break; + case cmDIV: #if defined(MUP_MATH_EXCEPTIONS) - if (y==0) - throw ParserError(ecDIV_BY_ZERO, _T("0")); + if (y == 0) + throw ParserError(ecDIV_BY_ZERO, _T("0")); #endif - x = x / y; - m_vRPN.pop_back(); - break; + x = x / y; + m_vRPN.pop_back(); + break; - case cmPOW: x = MathImpl::Pow(x, y); - m_vRPN.pop_back(); - break; + case cmPOW: + x = MathImpl::Pow(x, y); + m_vRPN.pop_back(); + break; - default: - break; + default: + break; } // switch opcode - } - - //--------------------------------------------------------------------------- - /** \brief Add an operator identifier to bytecode. - - Operator entries in byte code consist of: -
    -
  • value array position of the result
  • -
  • the operator code according to ParserToken::ECmdCode
  • -
- - \sa ParserToken::ECmdCode - */ - void ParserByteCode::AddOp(ECmdCode a_Oprt) - { +} + +//--------------------------------------------------------------------------- +/** \brief Add an operator identifier to bytecode. + + Operator entries in byte code consist of: +
    +
  • value array position of the result
  • +
  • the operator code according to ParserToken::ECmdCode
  • +
+ + \sa ParserToken::ECmdCode +*/ +void ParserByteCode::AddOp(ECmdCode a_Oprt) +{ bool bOptimized = false; if (m_bEnableOptimizer) { - std::size_t sz = m_vRPN.size(); - - // Check for foldable constants like: - // cmVAL cmVAL cmADD - // where cmADD can stand fopr any binary operator applied to - // two constant values. - if (sz>=2 && m_vRPN[sz-2].Cmd == cmVAL && m_vRPN[sz-1].Cmd == cmVAL) - { - ConstantFolding(a_Oprt); - bOptimized = true; - } - else - { - switch((int)a_Oprt) + std::size_t sz = m_vRPN.size(); + + // Check for foldable constants like: + // cmVAL cmVAL cmADD + // where cmADD can stand fopr any binary operator applied to + // two constant values. + if (sz >= 2 && m_vRPN[sz - 2].Cmd == cmVAL && m_vRPN[sz - 1].Cmd == cmVAL) + { + ConstantFolding(a_Oprt); + bOptimized = true; + } + else { - case cmPOW: - // Optimization for polynomials of low order - if (m_vRPN[sz-2].Cmd == cmVAR && m_vRPN[sz-1].Cmd == cmVAL) - { - if (m_vRPN[sz-1].Val.data2==2) - m_vRPN[sz-2].Cmd = cmVARPOW2; - else if (m_vRPN[sz-1].Val.data2==3) - m_vRPN[sz-2].Cmd = cmVARPOW3; - else if (m_vRPN[sz-1].Val.data2==4) - m_vRPN[sz-2].Cmd = cmVARPOW4; - else - break; - - m_vRPN.pop_back(); - bOptimized = true; - } - break; - - case cmSUB: - case cmADD: - // Simple optimization based on pattern recognition for a shitload of different - // bytecode combinations of addition/subtraction - if ( (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAL) || - (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVAR) || - (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVARMUL) || - (m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVAL) || - (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAR && m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) || - (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVARMUL && m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) || - (m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVAR && m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) || - (m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVARMUL && m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) ) - { - assert( (m_vRPN[sz-2].Val.ptr==NULL && m_vRPN[sz-1].Val.ptr!=NULL) || - (m_vRPN[sz-2].Val.ptr!=NULL && m_vRPN[sz-1].Val.ptr==NULL) || - (m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) ); - - m_vRPN[sz-2].Cmd = cmVARMUL; - m_vRPN[sz-2].Val.ptr = (value_type*)((long long)(m_vRPN[sz-2].Val.ptr) | (long long)(m_vRPN[sz-1].Val.ptr)); // variable - m_vRPN[sz-2].Val.data2 += ((a_Oprt==cmSUB) ? -1 : 1) * m_vRPN[sz-1].Val.data2; // offset - m_vRPN[sz-2].Val.data += ((a_Oprt==cmSUB) ? -1 : 1) * m_vRPN[sz-1].Val.data; // multiplicand - m_vRPN.pop_back(); - bOptimized = true; - } - break; - - case cmMUL: - if ( (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAL) || - (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVAR) ) - { - m_vRPN[sz-2].Cmd = cmVARMUL; - m_vRPN[sz-2].Val.ptr = (value_type*)((long long)(m_vRPN[sz-2].Val.ptr) | (long long)(m_vRPN[sz-1].Val.ptr)); - m_vRPN[sz-2].Val.data = m_vRPN[sz-2].Val.data2 + m_vRPN[sz-1].Val.data2; - m_vRPN[sz-2].Val.data2 = 0; - m_vRPN.pop_back(); - bOptimized = true; - } - else if ( (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVARMUL) || - (m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVAL) ) - { - // Optimization: 2*(3*b+1) or (3*b+1)*2 -> 6*b+2 - m_vRPN[sz-2].Cmd = cmVARMUL; - m_vRPN[sz-2].Val.ptr = (value_type*)((long long)(m_vRPN[sz-2].Val.ptr) | (long long)(m_vRPN[sz-1].Val.ptr)); - if (m_vRPN[sz-1].Cmd == cmVAL) - { - m_vRPN[sz-2].Val.data *= m_vRPN[sz-1].Val.data2; - m_vRPN[sz-2].Val.data2 *= m_vRPN[sz-1].Val.data2; - } - else - { - m_vRPN[sz-2].Val.data = m_vRPN[sz-1].Val.data * m_vRPN[sz-2].Val.data2; - m_vRPN[sz-2].Val.data2 = m_vRPN[sz-1].Val.data2 * m_vRPN[sz-2].Val.data2; - } - m_vRPN.pop_back(); - bOptimized = true; - } - else if (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAR && - m_vRPN[sz-1].Val.ptr == m_vRPN[sz-2].Val.ptr) - { - // Optimization: a*a -> a^2 - m_vRPN[sz-2].Cmd = cmVARPOW2; - m_vRPN.pop_back(); - bOptimized = true; - } - break; + switch ((int)a_Oprt) + { + case cmPOW: + // Optimization for polynomials of low order + if (m_vRPN[sz - 2].Cmd == cmVAR && m_vRPN[sz - 1].Cmd == cmVAL) + { + if (m_vRPN[sz - 1].Val.data2 == 2) + m_vRPN[sz - 2].Cmd = cmVARPOW2; + else if (m_vRPN[sz - 1].Val.data2 == 3) + m_vRPN[sz - 2].Cmd = cmVARPOW3; + else if (m_vRPN[sz - 1].Val.data2 == 4) + m_vRPN[sz - 2].Cmd = cmVARPOW4; + else + break; + + m_vRPN.pop_back(); + bOptimized = true; + } + break; - case cmDIV: - if (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVARMUL && m_vRPN[sz-1].Val.data2!=0) - { - // Optimization: 4*a/2 -> 2*a - m_vRPN[sz-2].Val.data /= m_vRPN[sz-1].Val.data2; - m_vRPN[sz-2].Val.data2 /= m_vRPN[sz-1].Val.data2; - m_vRPN.pop_back(); - bOptimized = true; - } - break; - - } // switch a_Oprt - } + case cmSUB: + case cmADD: + // Simple optimization based on pattern recognition for a shitload of different + // bytecode combinations of addition/subtraction + if ((m_vRPN[sz - 1].Cmd == cmVAR && m_vRPN[sz - 2].Cmd == cmVAL) || + (m_vRPN[sz - 1].Cmd == cmVAL && m_vRPN[sz - 2].Cmd == cmVAR) || + (m_vRPN[sz - 1].Cmd == cmVAL && m_vRPN[sz - 2].Cmd == cmVARMUL) || + (m_vRPN[sz - 1].Cmd == cmVARMUL && m_vRPN[sz - 2].Cmd == cmVAL) || + (m_vRPN[sz - 1].Cmd == cmVAR && m_vRPN[sz - 2].Cmd == cmVAR && + m_vRPN[sz - 2].Val.ptr == m_vRPN[sz - 1].Val.ptr) || + (m_vRPN[sz - 1].Cmd == cmVAR && m_vRPN[sz - 2].Cmd == cmVARMUL && + m_vRPN[sz - 2].Val.ptr == m_vRPN[sz - 1].Val.ptr) || + (m_vRPN[sz - 1].Cmd == cmVARMUL && m_vRPN[sz - 2].Cmd == cmVAR && + m_vRPN[sz - 2].Val.ptr == m_vRPN[sz - 1].Val.ptr) || + (m_vRPN[sz - 1].Cmd == cmVARMUL && m_vRPN[sz - 2].Cmd == cmVARMUL && + m_vRPN[sz - 2].Val.ptr == m_vRPN[sz - 1].Val.ptr)) + { + assert((m_vRPN[sz - 2].Val.ptr == NULL && m_vRPN[sz - 1].Val.ptr != NULL) || + (m_vRPN[sz - 2].Val.ptr != NULL && m_vRPN[sz - 1].Val.ptr == NULL) || + (m_vRPN[sz - 2].Val.ptr == m_vRPN[sz - 1].Val.ptr)); + + m_vRPN[sz - 2].Cmd = cmVARMUL; + m_vRPN[sz - 2].Val.ptr = (value_type*)((long long)(m_vRPN[sz - 2].Val.ptr) | + (long long)(m_vRPN[sz - 1].Val.ptr)); // variable + m_vRPN[sz - 2].Val.data2 += ((a_Oprt == cmSUB) ? -1 : 1) * m_vRPN[sz - 1].Val.data2; // offset + m_vRPN[sz - 2].Val.data += + ((a_Oprt == cmSUB) ? -1 : 1) * m_vRPN[sz - 1].Val.data; // multiplicand + m_vRPN.pop_back(); + bOptimized = true; + } + break; + + case cmMUL: + if ((m_vRPN[sz - 1].Cmd == cmVAR && m_vRPN[sz - 2].Cmd == cmVAL) || + (m_vRPN[sz - 1].Cmd == cmVAL && m_vRPN[sz - 2].Cmd == cmVAR)) + { + m_vRPN[sz - 2].Cmd = cmVARMUL; + m_vRPN[sz - 2].Val.ptr = + (value_type*)((long long)(m_vRPN[sz - 2].Val.ptr) | (long long)(m_vRPN[sz - 1].Val.ptr)); + m_vRPN[sz - 2].Val.data = m_vRPN[sz - 2].Val.data2 + m_vRPN[sz - 1].Val.data2; + m_vRPN[sz - 2].Val.data2 = 0; + m_vRPN.pop_back(); + bOptimized = true; + } + else if ((m_vRPN[sz - 1].Cmd == cmVAL && m_vRPN[sz - 2].Cmd == cmVARMUL) || + (m_vRPN[sz - 1].Cmd == cmVARMUL && m_vRPN[sz - 2].Cmd == cmVAL)) + { + // Optimization: 2*(3*b+1) or (3*b+1)*2 -> 6*b+2 + m_vRPN[sz - 2].Cmd = cmVARMUL; + m_vRPN[sz - 2].Val.ptr = + (value_type*)((long long)(m_vRPN[sz - 2].Val.ptr) | (long long)(m_vRPN[sz - 1].Val.ptr)); + if (m_vRPN[sz - 1].Cmd == cmVAL) + { + m_vRPN[sz - 2].Val.data *= m_vRPN[sz - 1].Val.data2; + m_vRPN[sz - 2].Val.data2 *= m_vRPN[sz - 1].Val.data2; + } + else + { + m_vRPN[sz - 2].Val.data = m_vRPN[sz - 1].Val.data * m_vRPN[sz - 2].Val.data2; + m_vRPN[sz - 2].Val.data2 = m_vRPN[sz - 1].Val.data2 * m_vRPN[sz - 2].Val.data2; + } + m_vRPN.pop_back(); + bOptimized = true; + } + else if (m_vRPN[sz - 1].Cmd == cmVAR && m_vRPN[sz - 2].Cmd == cmVAR && + m_vRPN[sz - 1].Val.ptr == m_vRPN[sz - 2].Val.ptr) + { + // Optimization: a*a -> a^2 + m_vRPN[sz - 2].Cmd = cmVARPOW2; + m_vRPN.pop_back(); + bOptimized = true; + } + break; + + case cmDIV: + if (m_vRPN[sz - 1].Cmd == cmVAL && m_vRPN[sz - 2].Cmd == cmVARMUL && m_vRPN[sz - 1].Val.data2 != 0) + { + // Optimization: 4*a/2 -> 2*a + m_vRPN[sz - 2].Val.data /= m_vRPN[sz - 1].Val.data2; + m_vRPN[sz - 2].Val.data2 /= m_vRPN[sz - 1].Val.data2; + m_vRPN.pop_back(); + bOptimized = true; + } + break; + + } // switch a_Oprt + } } // If optimization can't be applied just write the value if (!bOptimized) { - --m_iStackPos; - SToken tok; - tok.Cmd = a_Oprt; - m_vRPN.push_back(tok); + --m_iStackPos; + SToken tok; + tok.Cmd = a_Oprt; + m_vRPN.push_back(tok); } - } +} - //--------------------------------------------------------------------------- - void ParserByteCode::AddIfElse(ECmdCode a_Oprt) - { +//--------------------------------------------------------------------------- +void ParserByteCode::AddIfElse(ECmdCode a_Oprt) +{ SToken tok; tok.Cmd = a_Oprt; m_vRPN.push_back(tok); - } - - //--------------------------------------------------------------------------- - /** \brief Add an assignment operator - - Operator entries in byte code consist of: -
    -
  • cmASSIGN code
  • -
  • the pointer of the destination variable
  • -
- - \sa ParserToken::ECmdCode - */ - void ParserByteCode::AddAssignOp(value_type *a_pVar) - { +} + +//--------------------------------------------------------------------------- +/** \brief Add an assignment operator + + Operator entries in byte code consist of: +
    +
  • cmASSIGN code
  • +
  • the pointer of the destination variable
  • +
+ + \sa ParserToken::ECmdCode +*/ +void ParserByteCode::AddAssignOp(value_type* a_pVar) +{ --m_iStackPos; SToken tok; tok.Cmd = cmASSIGN; tok.Oprt.ptr = a_pVar; m_vRPN.push_back(tok); - } +} - //--------------------------------------------------------------------------- - /** \brief Add function to bytecode. +//--------------------------------------------------------------------------- +/** \brief Add function to bytecode. - \param a_iArgc Number of arguments, negative numbers indicate multiarg functions. - \param a_pFun Pointer to function callback. - */ - void ParserByteCode::AddFun(generic_fun_type a_pFun, int a_iArgc) - { - if (a_iArgc>=0) + \param a_iArgc Number of arguments, negative numbers indicate multiarg functions. + \param a_pFun Pointer to function callback. +*/ +void ParserByteCode::AddFun(generic_fun_type a_pFun, int a_iArgc) +{ + if (a_iArgc >= 0) { - m_iStackPos = m_iStackPos - a_iArgc + 1; + m_iStackPos = m_iStackPos - a_iArgc + 1; } else { - // function with unlimited number of arguments - m_iStackPos = m_iStackPos + a_iArgc + 1; + // function with unlimited number of arguments + m_iStackPos = m_iStackPos + a_iArgc + 1; } m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos); @@ -374,17 +410,17 @@ namespace mu tok.Fun.argc = a_iArgc; tok.Fun.ptr = a_pFun; m_vRPN.push_back(tok); - } +} - //--------------------------------------------------------------------------- - /** \brief Add a bulk function to bytecode. +//--------------------------------------------------------------------------- +/** \brief Add a bulk function to bytecode. - \param a_iArgc Number of arguments, negative numbers indicate multiarg functions. - \param a_pFun Pointer to function callback. - */ - void ParserByteCode::AddBulkFun(generic_fun_type a_pFun, int a_iArgc) - { - m_iStackPos = m_iStackPos - a_iArgc + 1; + \param a_iArgc Number of arguments, negative numbers indicate multiarg functions. + \param a_pFun Pointer to function callback. +*/ +void ParserByteCode::AddBulkFun(generic_fun_type a_pFun, int a_iArgc) +{ + m_iStackPos = m_iStackPos - a_iArgc + 1; m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos); SToken tok; @@ -392,18 +428,18 @@ namespace mu tok.Fun.argc = a_iArgc; tok.Fun.ptr = a_pFun; m_vRPN.push_back(tok); - } - - //--------------------------------------------------------------------------- - /** \brief Add Strung function entry to the parser bytecode. - \throw nothrow - - A string function entry consists of the stack position of the return value, - followed by a cmSTRFUNC code, the function pointer and an index into the - string buffer maintained by the parser. - */ - void ParserByteCode::AddStrFun(generic_fun_type a_pFun, int a_iArgc, int a_iIdx) - { +} + +//--------------------------------------------------------------------------- +/** \brief Add Strung function entry to the parser bytecode. + \throw nothrow + + A string function entry consists of the stack position of the return value, + followed by a cmSTRFUNC code, the function pointer and an index into the + string buffer maintained by the parser. +*/ +void ParserByteCode::AddStrFun(generic_fun_type a_pFun, int a_iArgc, int a_iIdx) +{ m_iStackPos = m_iStackPos - a_iArgc + 1; SToken tok; @@ -414,175 +450,213 @@ namespace mu m_vRPN.push_back(tok); m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos); - } - - //--------------------------------------------------------------------------- - /** \brief Add end marker to bytecode. - - \throw nothrow - */ - void ParserByteCode::Finalize() - { +} + +//--------------------------------------------------------------------------- +/** \brief Add end marker to bytecode. + + \throw nothrow +*/ +void ParserByteCode::Finalize() +{ SToken tok; tok.Cmd = cmEND; m_vRPN.push_back(tok); - rpn_type(m_vRPN).swap(m_vRPN); // shrink bytecode vector to fit + rpn_type(m_vRPN).swap(m_vRPN); // shrink bytecode vector to fit // Determine the if-then-else jump offsets ParserStack stIf, stElse; int idx; - for (int i=0; i<(int)m_vRPN.size(); ++i) + for (int i = 0; i < (int)m_vRPN.size(); ++i) { - switch(m_vRPN[i].Cmd) - { - case cmIF: - stIf.push(i); - break; + switch (m_vRPN[i].Cmd) + { + case cmIF: + stIf.push(i); + break; - case cmELSE: - stElse.push(i); - idx = stIf.pop(); - m_vRPN[idx].Oprt.offset = i - idx; - break; - - case cmENDIF: - idx = stElse.pop(); - m_vRPN[idx].Oprt.offset = i - idx; - break; + case cmELSE: + stElse.push(i); + idx = stIf.pop(); + m_vRPN[idx].Oprt.offset = i - idx; + break; - default: - break; - } + case cmENDIF: + idx = stElse.pop(); + m_vRPN[idx].Oprt.offset = i - idx; + break; + + default: + break; + } } - } +} - //--------------------------------------------------------------------------- - const SToken* ParserByteCode::GetBase() const - { - if (m_vRPN.size()==0) - throw ParserError(ecINTERNAL_ERROR); +//--------------------------------------------------------------------------- +const SToken* ParserByteCode::GetBase() const +{ + if (m_vRPN.size() == 0) + throw ParserError(ecINTERNAL_ERROR); else - return &m_vRPN[0]; - } - - //--------------------------------------------------------------------------- - std::size_t ParserByteCode::GetMaxStackSize() const - { - return m_iMaxStackSize+1; - } - - //--------------------------------------------------------------------------- - /** \brief Returns the number of entries in the bytecode. */ - std::size_t ParserByteCode::GetSize() const - { + return &m_vRPN[0]; +} + +//--------------------------------------------------------------------------- +std::size_t ParserByteCode::GetMaxStackSize() const +{ + return m_iMaxStackSize + 1; +} + +//--------------------------------------------------------------------------- +/** \brief Returns the number of entries in the bytecode. */ +std::size_t ParserByteCode::GetSize() const +{ return m_vRPN.size(); - } - - //--------------------------------------------------------------------------- - /** \brief Delete the bytecode. - - \throw nothrow - - The name of this function is a violation of my own coding guidelines - but this way it's more in line with the STL functions thus more - intuitive. - */ - void ParserByteCode::clear() - { +} + +//--------------------------------------------------------------------------- +/** \brief Delete the bytecode. + + \throw nothrow + + The name of this function is a violation of my own coding guidelines + but this way it's more in line with the STL functions thus more + intuitive. +*/ +void ParserByteCode::clear() +{ m_vRPN.clear(); m_iStackPos = 0; m_iMaxStackSize = 0; - } +} - //--------------------------------------------------------------------------- - /** \brief Dump bytecode (for debugging only!). */ - void ParserByteCode::AsciiDump() - { - if (!m_vRPN.size()) +//--------------------------------------------------------------------------- +/** \brief Dump bytecode (for debugging only!). */ +void ParserByteCode::AsciiDump() +{ + if (!m_vRPN.size()) { - mu::console() << _T("No bytecode available\n"); - return; + mu::console() << _T("No bytecode available\n"); + return; } mu::console() << _T("Number of RPN tokens:") << (int)m_vRPN.size() << _T("\n"); - for (std::size_t i=0; i \___ >|__| - \/ \/ \/ \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ Copyright (C) 2004-2013 Ingo Berg - Permission is hereby granted, free of charge, to any person obtaining a copy of this + 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 + 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 + 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. + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MU_PARSER_BYTECODE_H #define MU_PARSER_BYTECODE_H @@ -38,56 +38,53 @@ \brief Definition of the parser bytecode class. */ - namespace mu { - struct SToken - { +struct SToken +{ ECmdCode Cmd; int StackPos; union { - struct //SValData - { - value_type *ptr; - value_type data; - value_type data2; - } Val; - - struct //SFunData - { - // Note: generic_fun_type is merely a placeholder. The real type could be - // anything between gun_type1 and fun_type9. I can't use a void - // pointer due to constraints in the ANSI standard which allows - // data pointers and function pointers to differ in size. - generic_fun_type ptr; - int argc; - int idx; - } Fun; - - struct //SOprtData - { - value_type *ptr; - int offset; - } Oprt; + struct // SValData + { + value_type* ptr; + value_type data; + value_type data2; + } Val; + + struct // SFunData + { + // Note: generic_fun_type is merely a placeholder. The real type could be + // anything between gun_type1 and fun_type9. I can't use a void + // pointer due to constraints in the ANSI standard which allows + // data pointers and function pointers to differ in size. + generic_fun_type ptr; + int argc; + int idx; + } Fun; + + struct // SOprtData + { + value_type* ptr; + int offset; + } Oprt; }; - }; - - - /** \brief Bytecode implementation of the Math Parser. +}; - The bytecode contains the formula converted to revers polish notation stored in a continious - memory area. Associated with this data are operator codes, variable pointers, constant - values and function pointers. Those are necessary in order to calculate the result. - All those data items will be casted to the underlying datatype of the bytecode. +/** \brief Bytecode implementation of the Math Parser. - \author (C) 2004-2013 Ingo Berg +The bytecode contains the formula converted to revers polish notation stored in a continious +memory area. Associated with this data are operator codes, variable pointers, constant +values and function pointers. Those are necessary in order to calculate the result. +All those data items will be casted to the underlying datatype of the bytecode. + +\author (C) 2004-2013 Ingo Berg */ class ParserByteCode { private: - /** \brief Token type for internal use only. */ typedef ParserToken token_type; @@ -99,26 +96,25 @@ class ParserByteCode /** \brief Maximum size needed for the stack. */ std::size_t m_iMaxStackSize; - + /** \brief The actual rpn storage. */ - rpn_type m_vRPN; + rpn_type m_vRPN; bool m_bEnableOptimizer; void ConstantFolding(ECmdCode a_Oprt); public: - ParserByteCode(); - ParserByteCode(const ParserByteCode &a_ByteCode); - ParserByteCode& operator=(const ParserByteCode &a_ByteCode); - void Assign(const ParserByteCode &a_ByteCode); + ParserByteCode(const ParserByteCode& a_ByteCode); + ParserByteCode& operator=(const ParserByteCode& a_ByteCode); + void Assign(const ParserByteCode& a_ByteCode); - void AddVar(value_type *a_pVar); + void AddVar(value_type* a_pVar); void AddVal(value_type a_fVal); void AddOp(ECmdCode a_Oprt); void AddIfElse(ECmdCode a_Oprt); - void AddAssignOp(value_type *a_pVar); + void AddAssignOp(value_type* a_pVar); void AddFun(generic_fun_type a_pFun, int a_iArgc); void AddBulkFun(generic_fun_type a_pFun, int a_iArgc); void AddStrFun(generic_fun_type a_pFun, int a_iArgc, int a_iIdx); @@ -137,5 +133,3 @@ class ParserByteCode } // namespace mu #endif - - diff --git a/ext_libs/muparser/muParserCallback.cpp b/ext_libs/muparser/muParserCallback.cpp old mode 100755 new mode 100644 index 2044fe1c..8db3c1d6 --- a/ext_libs/muparser/muParserCallback.cpp +++ b/ext_libs/muparser/muParserCallback.cpp @@ -1,26 +1,26 @@ /* - __________ - _____ __ __\______ \_____ _______ ______ ____ _______ + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ - |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| - \/ \/ \/ \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ Copyright (C) 2004-2011 Ingo Berg - Permission is hereby granted, free of charge, to any person obtaining a copy of this + 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 + 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 + 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. + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "muParserCallback.h" @@ -29,435 +29,440 @@ \brief Implementation of the parser callback class. */ - namespace mu { - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(fun_type0 a_pFun, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(0) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - {} - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(fun_type1 a_pFun, bool a_bAllowOpti, int a_iPrec, ECmdCode a_iCode) - :m_pFun((void*)a_pFun) - ,m_iArgc(1) - ,m_iPri(a_iPrec) - ,m_eOprtAsct(oaNONE) - ,m_iCode(a_iCode) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - {} - - - //--------------------------------------------------------------------------- - /** \brief Constructor for constructing function callbacks taking two arguments. - \throw nothrow - */ - ParserCallback::ParserCallback(fun_type2 a_pFun, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(2) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - {} - - //--------------------------------------------------------------------------- - /** \brief Constructor for constructing binary operator callbacks. - \param a_pFun Pointer to a static function taking two arguments - \param a_bAllowOpti A flag indicating this function can be optimized - \param a_iPrec The operator precedence - \param a_eOprtAsct The operators associativity - \throw nothrow - */ - ParserCallback::ParserCallback(fun_type2 a_pFun, - bool a_bAllowOpti, - int a_iPrec, - EOprtAssociativity a_eOprtAsct) - :m_pFun((void*)a_pFun) - ,m_iArgc(2) - ,m_iPri(a_iPrec) - ,m_eOprtAsct(a_eOprtAsct) - ,m_iCode(cmOPRT_BIN) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - {} - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(fun_type3 a_pFun, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(3) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - {} - - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(fun_type4 a_pFun, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(4) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - {} - - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(fun_type5 a_pFun, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(5) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - {} - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(fun_type6 a_pFun, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(6) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - {} - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(fun_type7 a_pFun, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(7) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - {} - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(fun_type8 a_pFun, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(8) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - {} - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(fun_type9 a_pFun, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(9) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - {} - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(fun_type10 a_pFun, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(10) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - {} - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(bulkfun_type0 a_pFun, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(0) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC_BULK) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - {} - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(bulkfun_type1 a_pFun, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(1) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC_BULK) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - {} - - - //--------------------------------------------------------------------------- - /** \brief Constructor for constructing function callbacks taking two arguments. - \throw nothrow - */ - ParserCallback::ParserCallback(bulkfun_type2 a_pFun, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(2) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC_BULK) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - {} - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(bulkfun_type3 a_pFun, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(3) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC_BULK) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - {} - - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(bulkfun_type4 a_pFun, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(4) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC_BULK) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - {} - - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(bulkfun_type5 a_pFun, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(5) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC_BULK) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - {} - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(bulkfun_type6 a_pFun, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(6) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC_BULK) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - {} - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(bulkfun_type7 a_pFun, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(7) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC_BULK) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - {} - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(bulkfun_type8 a_pFun, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(8) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC_BULK) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - {} - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(bulkfun_type9 a_pFun, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(9) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC_BULK) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - {} - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(bulkfun_type10 a_pFun, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(10) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC_BULK) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - {} - - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(multfun_type a_pFun, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(-1) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - {} - - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(strfun_type1 a_pFun, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(0) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC_STR) - ,m_iType(tpSTR) - ,m_bAllowOpti(a_bAllowOpti) - {} - - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(strfun_type2 a_pFun, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(1) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC_STR) - ,m_iType(tpSTR) - ,m_bAllowOpti(a_bAllowOpti) - {} - - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(strfun_type3 a_pFun, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(2) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC_STR) - ,m_iType(tpSTR) - ,m_bAllowOpti(a_bAllowOpti) - {} - - - //--------------------------------------------------------------------------- - /** \brief Default constructor. - \throw nothrow - */ - ParserCallback::ParserCallback() - :m_pFun(0) - ,m_iArgc(0) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmUNKNOWN) - ,m_iType(tpVOID) - ,m_bAllowOpti(0) - {} - - - //--------------------------------------------------------------------------- - /** \brief Copy constructor. - \throw nothrow - */ - ParserCallback::ParserCallback(const ParserCallback &ref) - { - m_pFun = ref.m_pFun; - m_iArgc = ref.m_iArgc; +//--------------------------------------------------------------------------- +ParserCallback::ParserCallback(fun_type0 a_pFun, bool a_bAllowOpti) : + m_pFun((void*)a_pFun), + m_iArgc(0), + m_iPri(-1), + m_eOprtAsct(oaNONE), + m_iCode(cmFUNC), + m_iType(tpDBL), + m_bAllowOpti(a_bAllowOpti) +{ +} + +//--------------------------------------------------------------------------- +ParserCallback::ParserCallback(fun_type1 a_pFun, bool a_bAllowOpti, int a_iPrec, ECmdCode a_iCode) : + m_pFun((void*)a_pFun), + m_iArgc(1), + m_iPri(a_iPrec), + m_eOprtAsct(oaNONE), + m_iCode(a_iCode), + m_iType(tpDBL), + m_bAllowOpti(a_bAllowOpti) +{ +} + +//--------------------------------------------------------------------------- +/** \brief Constructor for constructing function callbacks taking two arguments. + \throw nothrow +*/ +ParserCallback::ParserCallback(fun_type2 a_pFun, bool a_bAllowOpti) : + m_pFun((void*)a_pFun), + m_iArgc(2), + m_iPri(-1), + m_eOprtAsct(oaNONE), + m_iCode(cmFUNC), + m_iType(tpDBL), + m_bAllowOpti(a_bAllowOpti) +{ +} + +//--------------------------------------------------------------------------- +/** \brief Constructor for constructing binary operator callbacks. + \param a_pFun Pointer to a static function taking two arguments + \param a_bAllowOpti A flag indicating this function can be optimized + \param a_iPrec The operator precedence + \param a_eOprtAsct The operators associativity + \throw nothrow +*/ +ParserCallback::ParserCallback(fun_type2 a_pFun, bool a_bAllowOpti, int a_iPrec, EOprtAssociativity a_eOprtAsct) : + m_pFun((void*)a_pFun), + m_iArgc(2), + m_iPri(a_iPrec), + m_eOprtAsct(a_eOprtAsct), + m_iCode(cmOPRT_BIN), + m_iType(tpDBL), + m_bAllowOpti(a_bAllowOpti) +{ +} + +//--------------------------------------------------------------------------- +ParserCallback::ParserCallback(fun_type3 a_pFun, bool a_bAllowOpti) : + m_pFun((void*)a_pFun), + m_iArgc(3), + m_iPri(-1), + m_eOprtAsct(oaNONE), + m_iCode(cmFUNC), + m_iType(tpDBL), + m_bAllowOpti(a_bAllowOpti) +{ +} + +//--------------------------------------------------------------------------- +ParserCallback::ParserCallback(fun_type4 a_pFun, bool a_bAllowOpti) : + m_pFun((void*)a_pFun), + m_iArgc(4), + m_iPri(-1), + m_eOprtAsct(oaNONE), + m_iCode(cmFUNC), + m_iType(tpDBL), + m_bAllowOpti(a_bAllowOpti) +{ +} + +//--------------------------------------------------------------------------- +ParserCallback::ParserCallback(fun_type5 a_pFun, bool a_bAllowOpti) : + m_pFun((void*)a_pFun), + m_iArgc(5), + m_iPri(-1), + m_eOprtAsct(oaNONE), + m_iCode(cmFUNC), + m_iType(tpDBL), + m_bAllowOpti(a_bAllowOpti) +{ +} + +//--------------------------------------------------------------------------- +ParserCallback::ParserCallback(fun_type6 a_pFun, bool a_bAllowOpti) : + m_pFun((void*)a_pFun), + m_iArgc(6), + m_iPri(-1), + m_eOprtAsct(oaNONE), + m_iCode(cmFUNC), + m_iType(tpDBL), + m_bAllowOpti(a_bAllowOpti) +{ +} + +//--------------------------------------------------------------------------- +ParserCallback::ParserCallback(fun_type7 a_pFun, bool a_bAllowOpti) : + m_pFun((void*)a_pFun), + m_iArgc(7), + m_iPri(-1), + m_eOprtAsct(oaNONE), + m_iCode(cmFUNC), + m_iType(tpDBL), + m_bAllowOpti(a_bAllowOpti) +{ +} + +//--------------------------------------------------------------------------- +ParserCallback::ParserCallback(fun_type8 a_pFun, bool a_bAllowOpti) : + m_pFun((void*)a_pFun), + m_iArgc(8), + m_iPri(-1), + m_eOprtAsct(oaNONE), + m_iCode(cmFUNC), + m_iType(tpDBL), + m_bAllowOpti(a_bAllowOpti) +{ +} + +//--------------------------------------------------------------------------- +ParserCallback::ParserCallback(fun_type9 a_pFun, bool a_bAllowOpti) : + m_pFun((void*)a_pFun), + m_iArgc(9), + m_iPri(-1), + m_eOprtAsct(oaNONE), + m_iCode(cmFUNC), + m_iType(tpDBL), + m_bAllowOpti(a_bAllowOpti) +{ +} + +//--------------------------------------------------------------------------- +ParserCallback::ParserCallback(fun_type10 a_pFun, bool a_bAllowOpti) : + m_pFun((void*)a_pFun), + m_iArgc(10), + m_iPri(-1), + m_eOprtAsct(oaNONE), + m_iCode(cmFUNC), + m_iType(tpDBL), + m_bAllowOpti(a_bAllowOpti) +{ +} + +//--------------------------------------------------------------------------- +ParserCallback::ParserCallback(bulkfun_type0 a_pFun, bool a_bAllowOpti) : + m_pFun((void*)a_pFun), + m_iArgc(0), + m_iPri(-1), + m_eOprtAsct(oaNONE), + m_iCode(cmFUNC_BULK), + m_iType(tpDBL), + m_bAllowOpti(a_bAllowOpti) +{ +} + +//--------------------------------------------------------------------------- +ParserCallback::ParserCallback(bulkfun_type1 a_pFun, bool a_bAllowOpti) : + m_pFun((void*)a_pFun), + m_iArgc(1), + m_iPri(-1), + m_eOprtAsct(oaNONE), + m_iCode(cmFUNC_BULK), + m_iType(tpDBL), + m_bAllowOpti(a_bAllowOpti) +{ +} + +//--------------------------------------------------------------------------- +/** \brief Constructor for constructing function callbacks taking two arguments. + \throw nothrow +*/ +ParserCallback::ParserCallback(bulkfun_type2 a_pFun, bool a_bAllowOpti) : + m_pFun((void*)a_pFun), + m_iArgc(2), + m_iPri(-1), + m_eOprtAsct(oaNONE), + m_iCode(cmFUNC_BULK), + m_iType(tpDBL), + m_bAllowOpti(a_bAllowOpti) +{ +} + +//--------------------------------------------------------------------------- +ParserCallback::ParserCallback(bulkfun_type3 a_pFun, bool a_bAllowOpti) : + m_pFun((void*)a_pFun), + m_iArgc(3), + m_iPri(-1), + m_eOprtAsct(oaNONE), + m_iCode(cmFUNC_BULK), + m_iType(tpDBL), + m_bAllowOpti(a_bAllowOpti) +{ +} + +//--------------------------------------------------------------------------- +ParserCallback::ParserCallback(bulkfun_type4 a_pFun, bool a_bAllowOpti) : + m_pFun((void*)a_pFun), + m_iArgc(4), + m_iPri(-1), + m_eOprtAsct(oaNONE), + m_iCode(cmFUNC_BULK), + m_iType(tpDBL), + m_bAllowOpti(a_bAllowOpti) +{ +} + +//--------------------------------------------------------------------------- +ParserCallback::ParserCallback(bulkfun_type5 a_pFun, bool a_bAllowOpti) : + m_pFun((void*)a_pFun), + m_iArgc(5), + m_iPri(-1), + m_eOprtAsct(oaNONE), + m_iCode(cmFUNC_BULK), + m_iType(tpDBL), + m_bAllowOpti(a_bAllowOpti) +{ +} + +//--------------------------------------------------------------------------- +ParserCallback::ParserCallback(bulkfun_type6 a_pFun, bool a_bAllowOpti) : + m_pFun((void*)a_pFun), + m_iArgc(6), + m_iPri(-1), + m_eOprtAsct(oaNONE), + m_iCode(cmFUNC_BULK), + m_iType(tpDBL), + m_bAllowOpti(a_bAllowOpti) +{ +} + +//--------------------------------------------------------------------------- +ParserCallback::ParserCallback(bulkfun_type7 a_pFun, bool a_bAllowOpti) : + m_pFun((void*)a_pFun), + m_iArgc(7), + m_iPri(-1), + m_eOprtAsct(oaNONE), + m_iCode(cmFUNC_BULK), + m_iType(tpDBL), + m_bAllowOpti(a_bAllowOpti) +{ +} + +//--------------------------------------------------------------------------- +ParserCallback::ParserCallback(bulkfun_type8 a_pFun, bool a_bAllowOpti) : + m_pFun((void*)a_pFun), + m_iArgc(8), + m_iPri(-1), + m_eOprtAsct(oaNONE), + m_iCode(cmFUNC_BULK), + m_iType(tpDBL), + m_bAllowOpti(a_bAllowOpti) +{ +} + +//--------------------------------------------------------------------------- +ParserCallback::ParserCallback(bulkfun_type9 a_pFun, bool a_bAllowOpti) : + m_pFun((void*)a_pFun), + m_iArgc(9), + m_iPri(-1), + m_eOprtAsct(oaNONE), + m_iCode(cmFUNC_BULK), + m_iType(tpDBL), + m_bAllowOpti(a_bAllowOpti) +{ +} + +//--------------------------------------------------------------------------- +ParserCallback::ParserCallback(bulkfun_type10 a_pFun, bool a_bAllowOpti) : + m_pFun((void*)a_pFun), + m_iArgc(10), + m_iPri(-1), + m_eOprtAsct(oaNONE), + m_iCode(cmFUNC_BULK), + m_iType(tpDBL), + m_bAllowOpti(a_bAllowOpti) +{ +} + +//--------------------------------------------------------------------------- +ParserCallback::ParserCallback(multfun_type a_pFun, bool a_bAllowOpti) : + m_pFun((void*)a_pFun), + m_iArgc(-1), + m_iPri(-1), + m_eOprtAsct(oaNONE), + m_iCode(cmFUNC), + m_iType(tpDBL), + m_bAllowOpti(a_bAllowOpti) +{ +} + +//--------------------------------------------------------------------------- +ParserCallback::ParserCallback(strfun_type1 a_pFun, bool a_bAllowOpti) : + m_pFun((void*)a_pFun), + m_iArgc(0), + m_iPri(-1), + m_eOprtAsct(oaNONE), + m_iCode(cmFUNC_STR), + m_iType(tpSTR), + m_bAllowOpti(a_bAllowOpti) +{ +} + +//--------------------------------------------------------------------------- +ParserCallback::ParserCallback(strfun_type2 a_pFun, bool a_bAllowOpti) : + m_pFun((void*)a_pFun), + m_iArgc(1), + m_iPri(-1), + m_eOprtAsct(oaNONE), + m_iCode(cmFUNC_STR), + m_iType(tpSTR), + m_bAllowOpti(a_bAllowOpti) +{ +} + +//--------------------------------------------------------------------------- +ParserCallback::ParserCallback(strfun_type3 a_pFun, bool a_bAllowOpti) : + m_pFun((void*)a_pFun), + m_iArgc(2), + m_iPri(-1), + m_eOprtAsct(oaNONE), + m_iCode(cmFUNC_STR), + m_iType(tpSTR), + m_bAllowOpti(a_bAllowOpti) +{ +} + +//--------------------------------------------------------------------------- +/** \brief Default constructor. + \throw nothrow +*/ +ParserCallback::ParserCallback() : + m_pFun(0), m_iArgc(0), m_iPri(-1), m_eOprtAsct(oaNONE), m_iCode(cmUNKNOWN), m_iType(tpVOID), m_bAllowOpti(0) +{ +} + +//--------------------------------------------------------------------------- +/** \brief Copy constructor. + \throw nothrow +*/ +ParserCallback::ParserCallback(const ParserCallback& ref) +{ + m_pFun = ref.m_pFun; + m_iArgc = ref.m_iArgc; m_bAllowOpti = ref.m_bAllowOpti; - m_iCode = ref.m_iCode; - m_iType = ref.m_iType; - m_iPri = ref.m_iPri; - m_eOprtAsct = ref.m_eOprtAsct; - } - - //--------------------------------------------------------------------------- - /** \brief Clone this instance and return a pointer to the new instance. */ - ParserCallback* ParserCallback::Clone() const - { + m_iCode = ref.m_iCode; + m_iType = ref.m_iType; + m_iPri = ref.m_iPri; + m_eOprtAsct = ref.m_eOprtAsct; +} + +//--------------------------------------------------------------------------- +/** \brief Clone this instance and return a pointer to the new instance. */ +ParserCallback* ParserCallback::Clone() const +{ return new ParserCallback(*this); - } - - //--------------------------------------------------------------------------- - /** \brief Return tru if the function is conservative. - - Conservative functions return always the same result for the same argument. - \throw nothrow - */ - bool ParserCallback::IsOptimizable() const - { - return m_bAllowOpti; - } - - //--------------------------------------------------------------------------- - /** \brief Get the callback address for the parser function. - - The type of the address is void. It needs to be recasted according to the - argument number to the right type. - - \throw nothrow - \return #pFun - */ - void* ParserCallback::GetAddr() const - { - return m_pFun; - } - - //--------------------------------------------------------------------------- - /** \brief Return the callback code. */ - ECmdCode ParserCallback::GetCode() const - { - return m_iCode; - } - - //--------------------------------------------------------------------------- - ETypeCode ParserCallback::GetType() const - { - return m_iType; - } - - - //--------------------------------------------------------------------------- - /** \brief Return the operator precedence. - \throw nothrown - - Only valid if the callback token is an operator token (binary or infix). - */ - int ParserCallback::GetPri() const - { - return m_iPri; - } - - //--------------------------------------------------------------------------- - /** \brief Return the operators associativity. - \throw nothrown - - Only valid if the callback token is a binary operator token. - */ - EOprtAssociativity ParserCallback::GetAssociativity() const - { +} + +//--------------------------------------------------------------------------- +/** \brief Return tru if the function is conservative. + + Conservative functions return always the same result for the same argument. + \throw nothrow +*/ +bool ParserCallback::IsOptimizable() const +{ + return m_bAllowOpti; +} + +//--------------------------------------------------------------------------- +/** \brief Get the callback address for the parser function. + + The type of the address is void. It needs to be recasted according to the + argument number to the right type. + + \throw nothrow + \return #pFun +*/ +void* ParserCallback::GetAddr() const +{ + return m_pFun; +} + +//--------------------------------------------------------------------------- +/** \brief Return the callback code. */ +ECmdCode ParserCallback::GetCode() const +{ + return m_iCode; +} + +//--------------------------------------------------------------------------- +ETypeCode ParserCallback::GetType() const +{ + return m_iType; +} + +//--------------------------------------------------------------------------- +/** \brief Return the operator precedence. + \throw nothrown + + Only valid if the callback token is an operator token (binary or infix). +*/ +int ParserCallback::GetPri() const +{ + return m_iPri; +} + +//--------------------------------------------------------------------------- +/** \brief Return the operators associativity. + \throw nothrown + + Only valid if the callback token is a binary operator token. +*/ +EOprtAssociativity ParserCallback::GetAssociativity() const +{ return m_eOprtAsct; - } - - //--------------------------------------------------------------------------- - /** \brief Returns the number of function Arguments. */ - int ParserCallback::GetArgc() const - { - return m_iArgc; - } +} + +//--------------------------------------------------------------------------- +/** \brief Returns the number of function Arguments. */ +int ParserCallback::GetArgc() const +{ + return m_iArgc; +} } // namespace mu diff --git a/ext_libs/muparser/muParserCallback.h b/ext_libs/muparser/muParserCallback.h old mode 100755 new mode 100644 index ef32b498..d7560991 --- a/ext_libs/muparser/muParserCallback.h +++ b/ext_libs/muparser/muParserCallback.h @@ -1,26 +1,26 @@ /* - __________ - _____ __ __\______ \_____ _______ ______ ____ _______ + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ - |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| - \/ \/ \/ \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ Copyright (C) 2004-2011 Ingo Berg - Permission is hereby granted, free of charge, to any person obtaining a copy of this + 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 + 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 + 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. + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MU_PARSER_CALLBACK_H @@ -34,45 +34,44 @@ namespace mu { - /** \brief Encapsulation of prototypes for a numerical parser function. Encapsulates the prototyp for numerical parser functions. The class stores the number of arguments for parser functions as well as additional flags indication the function is non optimizeable. - The pointer to the callback function pointer is stored as void* + The pointer to the callback function pointer is stored as void* and needs to be casted according to the argument count. Negative argument counts indicate a parser function with a variable number - of arguments. + of arguments. \author (C) 2004-2011 Ingo Berg */ class ParserCallback { public: - ParserCallback(fun_type0 a_pFun, bool a_bAllowOpti); - ParserCallback(fun_type1 a_pFun, bool a_bAllowOpti, int a_iPrec = -1, ECmdCode a_iCode=cmFUNC); - ParserCallback(fun_type2 a_pFun, bool a_bAllowOpti, int a_iPrec, EOprtAssociativity a_eAssociativity); - ParserCallback(fun_type2 a_pFun, bool a_bAllowOpti); - ParserCallback(fun_type3 a_pFun, bool a_bAllowOpti); - ParserCallback(fun_type4 a_pFun, bool a_bAllowOpti); - ParserCallback(fun_type5 a_pFun, bool a_bAllowOpti); - ParserCallback(fun_type6 a_pFun, bool a_bAllowOpti); - ParserCallback(fun_type7 a_pFun, bool a_bAllowOpti); - ParserCallback(fun_type8 a_pFun, bool a_bAllowOpti); - ParserCallback(fun_type9 a_pFun, bool a_bAllowOpti); + ParserCallback(fun_type0 a_pFun, bool a_bAllowOpti); + ParserCallback(fun_type1 a_pFun, bool a_bAllowOpti, int a_iPrec = -1, ECmdCode a_iCode = cmFUNC); + ParserCallback(fun_type2 a_pFun, bool a_bAllowOpti, int a_iPrec, EOprtAssociativity a_eAssociativity); + ParserCallback(fun_type2 a_pFun, bool a_bAllowOpti); + ParserCallback(fun_type3 a_pFun, bool a_bAllowOpti); + ParserCallback(fun_type4 a_pFun, bool a_bAllowOpti); + ParserCallback(fun_type5 a_pFun, bool a_bAllowOpti); + ParserCallback(fun_type6 a_pFun, bool a_bAllowOpti); + ParserCallback(fun_type7 a_pFun, bool a_bAllowOpti); + ParserCallback(fun_type8 a_pFun, bool a_bAllowOpti); + ParserCallback(fun_type9 a_pFun, bool a_bAllowOpti); ParserCallback(fun_type10 a_pFun, bool a_bAllowOpti); - ParserCallback(bulkfun_type0 a_pFun, bool a_bAllowOpti); - ParserCallback(bulkfun_type1 a_pFun, bool a_bAllowOpti); - ParserCallback(bulkfun_type2 a_pFun, bool a_bAllowOpti); - ParserCallback(bulkfun_type3 a_pFun, bool a_bAllowOpti); - ParserCallback(bulkfun_type4 a_pFun, bool a_bAllowOpti); - ParserCallback(bulkfun_type5 a_pFun, bool a_bAllowOpti); - ParserCallback(bulkfun_type6 a_pFun, bool a_bAllowOpti); - ParserCallback(bulkfun_type7 a_pFun, bool a_bAllowOpti); - ParserCallback(bulkfun_type8 a_pFun, bool a_bAllowOpti); - ParserCallback(bulkfun_type9 a_pFun, bool a_bAllowOpti); + ParserCallback(bulkfun_type0 a_pFun, bool a_bAllowOpti); + ParserCallback(bulkfun_type1 a_pFun, bool a_bAllowOpti); + ParserCallback(bulkfun_type2 a_pFun, bool a_bAllowOpti); + ParserCallback(bulkfun_type3 a_pFun, bool a_bAllowOpti); + ParserCallback(bulkfun_type4 a_pFun, bool a_bAllowOpti); + ParserCallback(bulkfun_type5 a_pFun, bool a_bAllowOpti); + ParserCallback(bulkfun_type6 a_pFun, bool a_bAllowOpti); + ParserCallback(bulkfun_type7 a_pFun, bool a_bAllowOpti); + ParserCallback(bulkfun_type8 a_pFun, bool a_bAllowOpti); + ParserCallback(bulkfun_type9 a_pFun, bool a_bAllowOpti); ParserCallback(bulkfun_type10 a_pFun, bool a_bAllowOpti); ParserCallback(multfun_type a_pFun, bool a_bAllowOpti); @@ -80,39 +79,38 @@ class ParserCallback ParserCallback(strfun_type2 a_pFun, bool a_bAllowOpti); ParserCallback(strfun_type3 a_pFun, bool a_bAllowOpti); ParserCallback(); - ParserCallback(const ParserCallback &a_Fun); - + ParserCallback(const ParserCallback& a_Fun); + ParserCallback* Clone() const; - bool IsOptimizable() const; + bool IsOptimizable() const; void* GetAddr() const; - ECmdCode GetCode() const; + ECmdCode GetCode() const; ETypeCode GetType() const; - int GetPri() const; + int GetPri() const; EOprtAssociativity GetAssociativity() const; int GetArgc() const; private: - void *m_pFun; ///< Pointer to the callback function, casted to void - + void* m_pFun; ///< Pointer to the callback function, casted to void + /** \brief Number of numeric function arguments - + This number is negative for functions with variable number of arguments. in this cases they represent the actual number of arguments found. */ - int m_iArgc; - int m_iPri; ///< Valid only for binary and infix operators; Operator precedence. - EOprtAssociativity m_eOprtAsct; ///< Operator associativity; Valid only for binary operators - ECmdCode m_iCode; + int m_iArgc; + int m_iPri; ///< Valid only for binary and infix operators; Operator precedence. + EOprtAssociativity m_eOprtAsct; ///< Operator associativity; Valid only for binary operators + ECmdCode m_iCode; ETypeCode m_iType; - bool m_bAllowOpti; ///< Flag indication optimizeability + bool m_bAllowOpti; ///< Flag indication optimizeability }; //------------------------------------------------------------------------------ /** \brief Container for Callback objects. */ -typedef std::map funmap_type; +typedef std::map funmap_type; } // namespace mu #endif - diff --git a/ext_libs/muparser/muParserDLL.cpp b/ext_libs/muparser/muParserDLL.cpp old mode 100755 new mode 100644 index 15c88003..3e2a8d51 --- a/ext_libs/muparser/muParserDLL.cpp +++ b/ext_libs/muparser/muParserDLL.cpp @@ -22,7 +22,7 @@ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#if defined(MUPARSER_DLL) +#if defined(MUPARSER_DLL) #if defined(_WIN32) #define WIN32_LEAN_AND_MEAN @@ -34,29 +34,27 @@ #include "muParserInt.h" #include "muParserError.h" - -#define MU_TRY \ - try \ - { - -#define MU_CATCH \ - } \ - catch (muError_t &e) \ - { \ - ParserTag *pTag = static_cast(a_hParser); \ - pTag->exc = e; \ - pTag->bError = true; \ -if (pTag->errHandler) \ - (pTag->errHandler)(a_hParser); \ - } \ - catch (...) \ - { \ - ParserTag *pTag = static_cast(a_hParser); \ - pTag->exc = muError_t(mu::ecINTERNAL_ERROR); \ - pTag->bError = true; \ -if (pTag->errHandler) \ - (pTag->errHandler)(a_hParser); \ - } +#define MU_TRY \ + try \ + { +#define MU_CATCH \ + } \ + catch (muError_t & e) \ + { \ + ParserTag* pTag = static_cast(a_hParser); \ + pTag->exc = e; \ + pTag->bError = true; \ + if (pTag->errHandler) \ + (pTag->errHandler)(a_hParser); \ + } \ + catch (...) \ + { \ + ParserTag* pTag = static_cast(a_hParser); \ + pTag->exc = muError_t(mu::ecINTERNAL_ERROR); \ + pTag->bError = true; \ + if (pTag->errHandler) \ + (pTag->errHandler)(a_hParser); \ + } /** \file \brief This file contains the implementation of the DLL interface of muparser. @@ -73,28 +71,26 @@ int g_nBulkSize; class ParserTag { public: - ParserTag(int nType) - :pParser((nType == muBASETYPE_FLOAT) ? (mu::ParserBase*)new mu::Parser() : - (nType == muBASETYPE_INT) ? (mu::ParserBase*)new mu::ParserInt() : NULL) - , exc() - , errHandler(NULL) - , bError(false) - , m_nParserType(nType) - {} - - ~ParserTag() + ParserTag(int nType) : + pParser((nType == muBASETYPE_FLOAT) ? (mu::ParserBase*)new mu::Parser() : + (nType == muBASETYPE_INT) ? (mu::ParserBase*)new mu::ParserInt() : NULL), + exc(), + errHandler(NULL), + bError(false), + m_nParserType(nType) { - delete pParser; } - mu::ParserBase *pParser; + ~ParserTag() { delete pParser; } + + mu::ParserBase* pParser; mu::ParserBase::exception_type exc; muErrorHandler_t errHandler; bool bError; private: - ParserTag(const ParserTag &ref); - ParserTag& operator=(const ParserTag &ref); + ParserTag(const ParserTag& ref); + ParserTag& operator=(const ParserTag& ref); int m_nParserType; }; @@ -125,19 +121,17 @@ ParserTag* AsParserTag(muParserHandle_t a_hParser) #if defined(_WIN32) #define _CRT_SECURE_NO_DEPRECATE -BOOL APIENTRY DllMain(HANDLE /*hModule*/, - DWORD ul_reason_for_call, - LPVOID /*lpReserved*/) +BOOL APIENTRY DllMain(HANDLE /*hModule*/, DWORD ul_reason_for_call, LPVOID /*lpReserved*/) { switch (ul_reason_for_call) { - case DLL_PROCESS_ATTACH: - break; + case DLL_PROCESS_ATTACH: + break; - case DLL_THREAD_ATTACH: - case DLL_THREAD_DETACH: - case DLL_PROCESS_DETACH: - break; + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; } return TRUE; @@ -153,34 +147,37 @@ BOOL APIENTRY DllMain(HANDLE /*hModule*/, // //--------------------------------------------------------------------------- -API_EXPORT(void) mupSetVarFactory(muParserHandle_t a_hParser, muFacFun_t a_pFactory, void *pUserData) +API_EXPORT(void) mupSetVarFactory(muParserHandle_t a_hParser, muFacFun_t a_pFactory, void* pUserData) { MU_TRY - muParser_t* p(AsParser(a_hParser)); + muParser_t* p(AsParser(a_hParser)); p->SetVarFactory(a_pFactory, pUserData); MU_CATCH } //--------------------------------------------------------------------------- /** \brief Create a new Parser instance and return its handle. -*/ + */ API_EXPORT(muParserHandle_t) mupCreate(int nBaseType) { switch (nBaseType) { - case muBASETYPE_FLOAT: return (void*)(new ParserTag(muBASETYPE_FLOAT)); - case muBASETYPE_INT: return (void*)(new ParserTag(muBASETYPE_INT)); - default: return NULL; + case muBASETYPE_FLOAT: + return (void*)(new ParserTag(muBASETYPE_FLOAT)); + case muBASETYPE_INT: + return (void*)(new ParserTag(muBASETYPE_INT)); + default: + return NULL; } } //--------------------------------------------------------------------------- /** \brief Release the parser instance related with a parser handle. -*/ + */ API_EXPORT(void) mupRelease(muParserHandle_t a_hParser) { MU_TRY - ParserTag* p = static_cast(a_hParser); + ParserTag* p = static_cast(a_hParser); delete p; MU_CATCH } @@ -189,7 +186,7 @@ API_EXPORT(void) mupRelease(muParserHandle_t a_hParser) API_EXPORT(const muChar_t*) mupGetVersion(muParserHandle_t a_hParser) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); #ifndef _UNICODE sprintf(s_tmpOutBuf, "%s", p->GetVersion().c_str()); @@ -200,40 +197,40 @@ API_EXPORT(const muChar_t*) mupGetVersion(muParserHandle_t a_hParser) return s_tmpOutBuf; MU_CATCH - return _T(""); + return _T(""); } //--------------------------------------------------------------------------- /** \brief Evaluate the expression. -*/ + */ API_EXPORT(muFloat_t) mupEval(muParserHandle_t a_hParser) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); return p->Eval(); MU_CATCH - return 0; + return 0; } //--------------------------------------------------------------------------- -API_EXPORT(muFloat_t*) mupEvalMulti(muParserHandle_t a_hParser, int *nNum) +API_EXPORT(muFloat_t*) mupEvalMulti(muParserHandle_t a_hParser, int* nNum) { MU_TRY - assert(nNum != NULL); + assert(nNum != NULL); muParser_t* const p(AsParser(a_hParser)); return p->Eval(*nNum); MU_CATCH - return 0; + return 0; } //--------------------------------------------------------------------------- -API_EXPORT(void) mupEvalBulk(muParserHandle_t a_hParser, muFloat_t *a_res, int nSize) +API_EXPORT(void) mupEvalBulk(muParserHandle_t a_hParser, muFloat_t* a_res, int nSize) { MU_TRY - muParser_t* p(AsParser(a_hParser)); + muParser_t* p(AsParser(a_hParser)); p->Eval(a_res, nSize); MU_CATCH } @@ -242,7 +239,7 @@ API_EXPORT(void) mupEvalBulk(muParserHandle_t a_hParser, muFloat_t *a_res, int n API_EXPORT(void) mupSetExpr(muParserHandle_t a_hParser, const muChar_t* a_szExpr) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->SetExpr(a_szExpr); MU_CATCH } @@ -251,7 +248,7 @@ API_EXPORT(void) mupSetExpr(muParserHandle_t a_hParser, const muChar_t* a_szExpr API_EXPORT(void) mupRemoveVar(muParserHandle_t a_hParser, const muChar_t* a_szName) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->RemoveVar(a_szName); MU_CATCH } @@ -263,7 +260,7 @@ API_EXPORT(void) mupRemoveVar(muParserHandle_t a_hParser, const muChar_t* a_szNa API_EXPORT(void) mupClearVar(muParserHandle_t a_hParser) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->ClearVar(); MU_CATCH } @@ -275,7 +272,7 @@ API_EXPORT(void) mupClearVar(muParserHandle_t a_hParser) API_EXPORT(void) mupClearConst(muParserHandle_t a_hParser) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->ClearConst(); MU_CATCH } @@ -287,7 +284,7 @@ API_EXPORT(void) mupClearConst(muParserHandle_t a_hParser) API_EXPORT(void) mupClearOprt(muParserHandle_t a_hParser) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->ClearOprt(); MU_CATCH } @@ -296,367 +293,304 @@ API_EXPORT(void) mupClearOprt(muParserHandle_t a_hParser) API_EXPORT(void) mupClearFun(muParserHandle_t a_hParser) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->ClearFun(); MU_CATCH } //--------------------------------------------------------------------------- -API_EXPORT(void) mupDefineFun0(muParserHandle_t a_hParser, - const muChar_t* a_szName, - muFun0_t a_pFun, - muBool_t a_bAllowOpt) +API_EXPORT(void) +mupDefineFun0(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun0_t a_pFun, muBool_t a_bAllowOpt) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, a_bAllowOpt != 0); MU_CATCH } //--------------------------------------------------------------------------- -API_EXPORT(void) mupDefineFun1(muParserHandle_t a_hParser, - const muChar_t* a_szName, - muFun1_t a_pFun, - muBool_t a_bAllowOpt) +API_EXPORT(void) +mupDefineFun1(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun1_t a_pFun, muBool_t a_bAllowOpt) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, a_bAllowOpt != 0); MU_CATCH } //--------------------------------------------------------------------------- -API_EXPORT(void) mupDefineFun2(muParserHandle_t a_hParser, - const muChar_t* a_szName, - muFun2_t a_pFun, - muBool_t a_bAllowOpt) +API_EXPORT(void) +mupDefineFun2(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun2_t a_pFun, muBool_t a_bAllowOpt) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, a_bAllowOpt != 0); MU_CATCH } //--------------------------------------------------------------------------- -API_EXPORT(void) mupDefineFun3(muParserHandle_t a_hParser, - const muChar_t *a_szName, - muFun3_t a_pFun, - muBool_t a_bAllowOpt) +API_EXPORT(void) +mupDefineFun3(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun3_t a_pFun, muBool_t a_bAllowOpt) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, a_bAllowOpt != 0); MU_CATCH } //--------------------------------------------------------------------------- -API_EXPORT(void) mupDefineFun4(muParserHandle_t a_hParser, - const muChar_t *a_szName, - muFun4_t a_pFun, - muBool_t a_bAllowOpt) +API_EXPORT(void) +mupDefineFun4(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun4_t a_pFun, muBool_t a_bAllowOpt) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, a_bAllowOpt != 0); MU_CATCH } //--------------------------------------------------------------------------- -API_EXPORT(void) mupDefineFun5(muParserHandle_t a_hParser, - const muChar_t *a_szName, - muFun5_t a_pFun, - muBool_t a_bAllowOpt) +API_EXPORT(void) +mupDefineFun5(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun5_t a_pFun, muBool_t a_bAllowOpt) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, a_bAllowOpt != 0); MU_CATCH } //--------------------------------------------------------------------------- -API_EXPORT(void) mupDefineFun6(muParserHandle_t a_hParser, - const muChar_t *a_szName, - muFun6_t a_pFun, - muBool_t a_bAllowOpt) +API_EXPORT(void) +mupDefineFun6(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun6_t a_pFun, muBool_t a_bAllowOpt) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, a_bAllowOpt != 0); MU_CATCH } //--------------------------------------------------------------------------- -API_EXPORT(void) mupDefineFun7(muParserHandle_t a_hParser, - const muChar_t *a_szName, - muFun7_t a_pFun, - muBool_t a_bAllowOpt) +API_EXPORT(void) +mupDefineFun7(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun7_t a_pFun, muBool_t a_bAllowOpt) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, a_bAllowOpt != 0); MU_CATCH } //--------------------------------------------------------------------------- -API_EXPORT(void) mupDefineFun8(muParserHandle_t a_hParser, - const muChar_t *a_szName, - muFun8_t a_pFun, - muBool_t a_bAllowOpt) +API_EXPORT(void) +mupDefineFun8(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun8_t a_pFun, muBool_t a_bAllowOpt) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, a_bAllowOpt != 0); MU_CATCH } //--------------------------------------------------------------------------- -API_EXPORT(void) mupDefineFun9(muParserHandle_t a_hParser, - const muChar_t *a_szName, - muFun9_t a_pFun, - muBool_t a_bAllowOpt) +API_EXPORT(void) +mupDefineFun9(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun9_t a_pFun, muBool_t a_bAllowOpt) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, a_bAllowOpt != 0); MU_CATCH } //--------------------------------------------------------------------------- -API_EXPORT(void) mupDefineFun10(muParserHandle_t a_hParser, - const muChar_t *a_szName, - muFun10_t a_pFun, - muBool_t a_bAllowOpt) +API_EXPORT(void) +mupDefineFun10(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun10_t a_pFun, muBool_t a_bAllowOpt) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, a_bAllowOpt != 0); MU_CATCH } //--------------------------------------------------------------------------- -API_EXPORT(void) mupDefineBulkFun0(muParserHandle_t a_hParser, - const muChar_t* a_szName, - muBulkFun0_t a_pFun) +API_EXPORT(void) mupDefineBulkFun0(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFun0_t a_pFun) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } //--------------------------------------------------------------------------- -API_EXPORT(void) mupDefineBulkFun1(muParserHandle_t a_hParser, - const muChar_t* a_szName, - muBulkFun1_t a_pFun) +API_EXPORT(void) mupDefineBulkFun1(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFun1_t a_pFun) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } //--------------------------------------------------------------------------- -API_EXPORT(void) mupDefineBulkFun2(muParserHandle_t a_hParser, - const muChar_t* a_szName, - muBulkFun2_t a_pFun) +API_EXPORT(void) mupDefineBulkFun2(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFun2_t a_pFun) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } //--------------------------------------------------------------------------- -API_EXPORT(void) mupDefineBulkFun3(muParserHandle_t a_hParser, - const muChar_t *a_szName, - muBulkFun3_t a_pFun) +API_EXPORT(void) mupDefineBulkFun3(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFun3_t a_pFun) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } //--------------------------------------------------------------------------- -API_EXPORT(void) mupDefineBulkFun4(muParserHandle_t a_hParser, - const muChar_t *a_szName, - muBulkFun4_t a_pFun) +API_EXPORT(void) mupDefineBulkFun4(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFun4_t a_pFun) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } //--------------------------------------------------------------------------- -API_EXPORT(void) mupDefineBulkFun5(muParserHandle_t a_hParser, - const muChar_t *a_szName, - muBulkFun5_t a_pFun) +API_EXPORT(void) mupDefineBulkFun5(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFun5_t a_pFun) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } //--------------------------------------------------------------------------- -API_EXPORT(void) mupDefineBulkFun6(muParserHandle_t a_hParser, - const muChar_t *a_szName, - muBulkFun6_t a_pFun) +API_EXPORT(void) mupDefineBulkFun6(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFun6_t a_pFun) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } //--------------------------------------------------------------------------- -API_EXPORT(void) mupDefineBulkFun7(muParserHandle_t a_hParser, - const muChar_t *a_szName, - muBulkFun7_t a_pFun) +API_EXPORT(void) mupDefineBulkFun7(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFun7_t a_pFun) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } //--------------------------------------------------------------------------- -API_EXPORT(void) mupDefineBulkFun8(muParserHandle_t a_hParser, - const muChar_t *a_szName, - muBulkFun8_t a_pFun) +API_EXPORT(void) mupDefineBulkFun8(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFun8_t a_pFun) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } //--------------------------------------------------------------------------- -API_EXPORT(void) mupDefineBulkFun9(muParserHandle_t a_hParser, - const muChar_t *a_szName, - muBulkFun9_t a_pFun) +API_EXPORT(void) mupDefineBulkFun9(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFun9_t a_pFun) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } //--------------------------------------------------------------------------- -API_EXPORT(void) mupDefineBulkFun10(muParserHandle_t a_hParser, - const muChar_t *a_szName, - muBulkFun10_t a_pFun) +API_EXPORT(void) mupDefineBulkFun10(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFun10_t a_pFun) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } //--------------------------------------------------------------------------- -API_EXPORT(void) mupDefineStrFun1(muParserHandle_t a_hParser, - const muChar_t *a_szName, - muStrFun1_t a_pFun) +API_EXPORT(void) mupDefineStrFun1(muParserHandle_t a_hParser, const muChar_t* a_szName, muStrFun1_t a_pFun) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } //--------------------------------------------------------------------------- -API_EXPORT(void) mupDefineStrFun2(muParserHandle_t a_hParser, - const muChar_t* a_szName, - muStrFun2_t a_pFun) +API_EXPORT(void) mupDefineStrFun2(muParserHandle_t a_hParser, const muChar_t* a_szName, muStrFun2_t a_pFun) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } //--------------------------------------------------------------------------- -API_EXPORT(void) mupDefineStrFun3(muParserHandle_t a_hParser, - const muChar_t* a_szName, - muStrFun3_t a_pFun) +API_EXPORT(void) mupDefineStrFun3(muParserHandle_t a_hParser, const muChar_t* a_szName, muStrFun3_t a_pFun) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } //--------------------------------------------------------------------------- -API_EXPORT(void) mupDefineMultFun(muParserHandle_t a_hParser, - const muChar_t *a_szName, - muMultFun_t a_pFun, - muBool_t a_bAllowOpt) +API_EXPORT(void) +mupDefineMultFun(muParserHandle_t a_hParser, const muChar_t* a_szName, muMultFun_t a_pFun, muBool_t a_bAllowOpt) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, a_bAllowOpt != 0); MU_CATCH } //--------------------------------------------------------------------------- -API_EXPORT(void) mupDefineOprt(muParserHandle_t a_hParser, - const muChar_t* a_szName, - muFun2_t a_pFun, - muInt_t a_nPrec, - muInt_t a_nOprtAsct, - muBool_t a_bAllowOpt) +API_EXPORT(void) +mupDefineOprt(muParserHandle_t a_hParser, + const muChar_t* a_szName, + muFun2_t a_pFun, + muInt_t a_nPrec, + muInt_t a_nOprtAsct, + muBool_t a_bAllowOpt) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); - p->DefineOprt(a_szName, - a_pFun, - a_nPrec, - (mu::EOprtAssociativity)a_nOprtAsct, - a_bAllowOpt != 0); + muParser_t* const p(AsParser(a_hParser)); + p->DefineOprt(a_szName, a_pFun, a_nPrec, (mu::EOprtAssociativity)a_nOprtAsct, a_bAllowOpt != 0); MU_CATCH } //--------------------------------------------------------------------------- -API_EXPORT(void) mupDefineVar(muParserHandle_t a_hParser, - const muChar_t *a_szName, - muFloat_t *a_pVar) +API_EXPORT(void) mupDefineVar(muParserHandle_t a_hParser, const muChar_t* a_szName, muFloat_t* a_pVar) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->DefineVar(a_szName, a_pVar); MU_CATCH } //--------------------------------------------------------------------------- -API_EXPORT(void) mupDefineBulkVar(muParserHandle_t a_hParser, - const muChar_t *a_szName, - muFloat_t *a_pVar) +API_EXPORT(void) mupDefineBulkVar(muParserHandle_t a_hParser, const muChar_t* a_szName, muFloat_t* a_pVar) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->DefineVar(a_szName, a_pVar); MU_CATCH } //--------------------------------------------------------------------------- -API_EXPORT(void) mupDefineConst(muParserHandle_t a_hParser, - const muChar_t *a_szName, - muFloat_t a_fVal) +API_EXPORT(void) mupDefineConst(muParserHandle_t a_hParser, const muChar_t* a_szName, muFloat_t a_fVal) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->DefineConst(a_szName, a_fVal); MU_CATCH } //--------------------------------------------------------------------------- -API_EXPORT(void) mupDefineStrConst(muParserHandle_t a_hParser, - const muChar_t *a_szName, - const muChar_t *a_szVal) +API_EXPORT(void) mupDefineStrConst(muParserHandle_t a_hParser, const muChar_t* a_szName, const muChar_t* a_szVal) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->DefineStrConst(a_szName, a_szVal); MU_CATCH } @@ -665,7 +599,7 @@ API_EXPORT(void) mupDefineStrConst(muParserHandle_t a_hParser, API_EXPORT(const muChar_t*) mupGetExpr(muParserHandle_t a_hParser) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); // C# explodes when pMsg is returned directly. For some reason it can't access // the memory where the message lies directly. @@ -679,53 +613,46 @@ API_EXPORT(const muChar_t*) mupGetExpr(muParserHandle_t a_hParser) MU_CATCH - return _T(""); + return _T(""); } //--------------------------------------------------------------------------- -API_EXPORT(void) mupDefinePostfixOprt(muParserHandle_t a_hParser, - const muChar_t* a_szName, - muFun1_t a_pOprt, - muBool_t a_bAllowOpt) +API_EXPORT(void) +mupDefinePostfixOprt(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun1_t a_pOprt, muBool_t a_bAllowOpt) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->DefinePostfixOprt(a_szName, a_pOprt, a_bAllowOpt != 0); MU_CATCH } //--------------------------------------------------------------------------- -API_EXPORT(void) mupDefineInfixOprt(muParserHandle_t a_hParser, - const muChar_t* a_szName, - muFun1_t a_pOprt, - muBool_t a_bAllowOpt) +API_EXPORT(void) +mupDefineInfixOprt(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun1_t a_pOprt, muBool_t a_bAllowOpt) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->DefineInfixOprt(a_szName, a_pOprt, a_bAllowOpt != 0); MU_CATCH } // Define character sets for identifiers //--------------------------------------------------------------------------- -API_EXPORT(void) mupDefineNameChars(muParserHandle_t a_hParser, - const muChar_t* a_szCharset) +API_EXPORT(void) mupDefineNameChars(muParserHandle_t a_hParser, const muChar_t* a_szCharset) { muParser_t* const p(AsParser(a_hParser)); p->DefineNameChars(a_szCharset); } //--------------------------------------------------------------------------- -API_EXPORT(void) mupDefineOprtChars(muParserHandle_t a_hParser, - const muChar_t* a_szCharset) +API_EXPORT(void) mupDefineOprtChars(muParserHandle_t a_hParser, const muChar_t* a_szCharset) { muParser_t* const p(AsParser(a_hParser)); p->DefineOprtChars(a_szCharset); } //--------------------------------------------------------------------------- -API_EXPORT(void) mupDefineInfixOprtChars(muParserHandle_t a_hParser, - const muChar_t *a_szCharset) +API_EXPORT(void) mupDefineInfixOprtChars(muParserHandle_t a_hParser, const muChar_t* a_szCharset) { muParser_t* const p(AsParser(a_hParser)); p->DefineInfixOprtChars(a_szCharset); @@ -740,12 +667,12 @@ API_EXPORT(void) mupDefineInfixOprtChars(muParserHandle_t a_hParser, API_EXPORT(int) mupGetVarNum(muParserHandle_t a_hParser) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); const mu::varmap_type VarMap = p->GetVar(); return (int)VarMap.size(); MU_CATCH - return 0; // never reached + return 0; // never reached } //--------------------------------------------------------------------------- @@ -764,17 +691,14 @@ API_EXPORT(int) mupGetVarNum(muParserHandle_t a_hParser) During the calculation user defined callback functions present in the expression will be called, this is unavoidable. */ -API_EXPORT(void) mupGetVar(muParserHandle_t a_hParser, - unsigned a_iVar, - const muChar_t **a_szName, - muFloat_t **a_pVar) +API_EXPORT(void) mupGetVar(muParserHandle_t a_hParser, unsigned a_iVar, const muChar_t** a_szName, muFloat_t** a_pVar) { // A static buffer is needed for the name since i cant return the // pointer from the map. - static muChar_t szName[1024]; + static muChar_t szName[1024]; MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); const mu::varmap_type VarMap = p->GetVar(); if (a_iVar >= VarMap.size()) @@ -795,7 +719,7 @@ API_EXPORT(void) mupGetVar(muParserHandle_t a_hParser, wcsncpy(szName, item->first.c_str(), sizeof(szName)); #endif - szName[sizeof(szName)-1] = 0; + szName[sizeof(szName) - 1] = 0; *a_szName = &szName[0]; *a_pVar = item->second; @@ -803,7 +727,7 @@ API_EXPORT(void) mupGetVar(muParserHandle_t a_hParser, MU_CATCH - *a_szName = 0; + *a_szName = 0; *a_pVar = 0; } @@ -816,12 +740,12 @@ API_EXPORT(void) mupGetVar(muParserHandle_t a_hParser, API_EXPORT(int) mupGetExprVarNum(muParserHandle_t a_hParser) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); const mu::varmap_type VarMap = p->GetUsedVar(); return (int)VarMap.size(); MU_CATCH - return 0; // never reached + return 0; // never reached } //--------------------------------------------------------------------------- @@ -841,17 +765,15 @@ API_EXPORT(int) mupGetExprVarNum(muParserHandle_t a_hParser) \param a_pVar [out] Pointer to the variable. \throw nothrow */ -API_EXPORT(void) mupGetExprVar(muParserHandle_t a_hParser, - unsigned a_iVar, - const muChar_t **a_szName, - muFloat_t **a_pVar) +API_EXPORT(void) +mupGetExprVar(muParserHandle_t a_hParser, unsigned a_iVar, const muChar_t** a_szName, muFloat_t** a_pVar) { // A static buffer is needed for the name since i cant return the // pointer from the map. - static muChar_t szName[1024]; + static muChar_t szName[1024]; MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); const mu::varmap_type VarMap = p->GetUsedVar(); if (a_iVar >= VarMap.size()) @@ -872,7 +794,7 @@ API_EXPORT(void) mupGetExprVar(muParserHandle_t a_hParser, wcsncpy(szName, item->first.c_str(), sizeof(szName)); #endif - szName[sizeof(szName)-1] = 0; + szName[sizeof(szName) - 1] = 0; *a_szName = &szName[0]; *a_pVar = item->second; @@ -880,7 +802,7 @@ API_EXPORT(void) mupGetExprVar(muParserHandle_t a_hParser, MU_CATCH - *a_szName = 0; + *a_szName = 0; *a_pVar = 0; } @@ -889,19 +811,19 @@ API_EXPORT(void) mupGetExprVar(muParserHandle_t a_hParser, API_EXPORT(int) mupGetConstNum(muParserHandle_t a_hParser) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); const mu::valmap_type ValMap = p->GetConst(); return (int)ValMap.size(); MU_CATCH - return 0; // never reached + return 0; // never reached } //----------------------------------------------------------------------------------------------------- API_EXPORT(void) mupSetArgSep(muParserHandle_t a_hParser, const muChar_t cArgSep) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->SetArgSep(cArgSep); MU_CATCH } @@ -910,7 +832,7 @@ API_EXPORT(void) mupSetArgSep(muParserHandle_t a_hParser, const muChar_t cArgSep API_EXPORT(void) mupResetLocale(muParserHandle_t a_hParser) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->ResetLocale(); MU_CATCH } @@ -919,7 +841,7 @@ API_EXPORT(void) mupResetLocale(muParserHandle_t a_hParser) API_EXPORT(void) mupSetDecSep(muParserHandle_t a_hParser, const muChar_t cDecSep) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->SetDecSep(cDecSep); MU_CATCH } @@ -928,7 +850,7 @@ API_EXPORT(void) mupSetDecSep(muParserHandle_t a_hParser, const muChar_t cDecSep API_EXPORT(void) mupSetThousandsSep(muParserHandle_t a_hParser, const muChar_t cThousandsSep) { MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); p->SetThousandsSep(cThousandsSep); MU_CATCH } @@ -940,17 +862,14 @@ API_EXPORT(void) mupSetThousandsSep(muParserHandle_t a_hParser, const muChar_t c \param a_pszName [out] pointer to a null terminated string with the constant name \param [out] The constant value */ -API_EXPORT(void) mupGetConst(muParserHandle_t a_hParser, - unsigned a_iVar, - const muChar_t **a_pszName, - muFloat_t *a_fVal) +API_EXPORT(void) mupGetConst(muParserHandle_t a_hParser, unsigned a_iVar, const muChar_t** a_pszName, muFloat_t* a_fVal) { // A static buffer is needed for the name since i cant return the // pointer from the map. static muChar_t szName[1024]; MU_TRY - muParser_t* const p(AsParser(a_hParser)); + muParser_t* const p(AsParser(a_hParser)); const mu::valmap_type ValMap = p->GetConst(); if (a_iVar >= ValMap.size()) @@ -971,7 +890,7 @@ API_EXPORT(void) mupGetConst(muParserHandle_t a_hParser, wcsncpy(szName, item->first.c_str(), sizeof(szName)); #endif - szName[sizeof(szName)-1] = 0; + szName[sizeof(szName) - 1] = 0; *a_pszName = &szName[0]; *a_fVal = item->second; @@ -979,18 +898,17 @@ API_EXPORT(void) mupGetConst(muParserHandle_t a_hParser, MU_CATCH - *a_pszName = 0; + *a_pszName = 0; *a_fVal = 0; } //--------------------------------------------------------------------------- /** \brief Add a custom value recognition function. -*/ -API_EXPORT(void) mupAddValIdent(muParserHandle_t a_hParser, - muIdentFun_t a_pFun) + */ +API_EXPORT(void) mupAddValIdent(muParserHandle_t a_hParser, muIdentFun_t a_pFun) { MU_TRY - muParser_t* p(AsParser(a_hParser)); + muParser_t* p(AsParser(a_hParser)); p->AddValIdent(a_pFun); MU_CATCH } @@ -1010,7 +928,7 @@ API_EXPORT(muBool_t) mupError(muParserHandle_t a_hParser) //--------------------------------------------------------------------------- /** \brief Reset the internal error flag. -*/ + */ API_EXPORT(void) mupErrorReset(muParserHandle_t a_hParser) { AsParserTag(a_hParser)->bError = false; @@ -1024,11 +942,11 @@ API_EXPORT(void) mupSetErrorHandler(muParserHandle_t a_hParser, muErrorHandler_t //--------------------------------------------------------------------------- /** \brief Return the message associated with the last error. -*/ + */ API_EXPORT(const muChar_t*) mupGetErrorMsg(muParserHandle_t a_hParser) { ParserTag* const p(AsParserTag(a_hParser)); - const muChar_t *pMsg = p->exc.GetMsg().c_str(); + const muChar_t* pMsg = p->exc.GetMsg().c_str(); // C# explodes when pMsg is returned directly. For some reason it can't access // the memory where the message lies directly. @@ -1043,11 +961,11 @@ API_EXPORT(const muChar_t*) mupGetErrorMsg(muParserHandle_t a_hParser) //--------------------------------------------------------------------------- /** \brief Return the message associated with the last error. -*/ + */ API_EXPORT(const muChar_t*) mupGetErrorToken(muParserHandle_t a_hParser) { ParserTag* const p(AsParserTag(a_hParser)); - const muChar_t *pToken = p->exc.GetToken().c_str(); + const muChar_t* pToken = p->exc.GetToken().c_str(); // C# explodes when pMsg is returned directly. For some reason it can't access // the memory where the message lies directly. @@ -1062,7 +980,7 @@ API_EXPORT(const muChar_t*) mupGetErrorToken(muParserHandle_t a_hParser) //--------------------------------------------------------------------------- /** \brief Return the code associated with the last error. -*/ + */ API_EXPORT(int) mupGetErrorCode(muParserHandle_t a_hParser) { return AsParserTag(a_hParser)->exc.GetCode(); @@ -1076,7 +994,7 @@ API_EXPORT(int) mupGetErrorPos(muParserHandle_t a_hParser) } ////----------------------------------------------------------------------------------------------------- -//API_EXPORT(const muChar_t*) mupGetErrorExpr(muParserHandle_t a_hParser) +// API_EXPORT(const muChar_t*) mupGetErrorExpr(muParserHandle_t a_hParser) //{ // return AsParserTag(a_hParser)->exc.GetExpr().c_str(); //} @@ -1088,9 +1006,9 @@ API_EXPORT(muFloat_t*) mupCreateVar() } //----------------------------------------------------------------------------------------------------- -API_EXPORT(void) mupReleaseVar(muFloat_t *ptr) +API_EXPORT(void) mupReleaseVar(muFloat_t* ptr) { delete ptr; } -#endif // MUPARSER_DLL +#endif // MUPARSER_DLL diff --git a/ext_libs/muparser/muParserDLL.h b/ext_libs/muparser/muParserDLL.h old mode 100755 new mode 100644 index 155ef8a0..ddb93da2 --- a/ext_libs/muparser/muParserDLL.h +++ b/ext_libs/muparser/muParserDLL.h @@ -1,238 +1,270 @@ /* - __________ - _____ __ __\______ \_____ _______ ______ ____ _______ + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ - |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| - \/ \/ \/ \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ Copyright (C) 2011 Ingo Berg - Permission is hereby granted, free of charge, to any person obtaining a copy of this + 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 + 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 + 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. + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MU_PARSER_DLL_H #define MU_PARSER_DLL_H #if defined(WIN32) || defined(_WIN32) - #ifdef MUPARSERLIB_EXPORTS - #define API_EXPORT(TYPE) __declspec(dllexport) TYPE __cdecl - #else - #define API_EXPORT(TYPE) __declspec(dllimport) TYPE __cdecl - #endif +#ifdef MUPARSERLIB_EXPORTS +#define API_EXPORT(TYPE) __declspec(dllexport) TYPE __cdecl #else - #define API_EXPORT(TYPE) TYPE +#define API_EXPORT(TYPE) __declspec(dllimport) TYPE __cdecl +#endif +#else +#define API_EXPORT(TYPE) TYPE #endif - #ifdef __cplusplus extern "C" { #endif -/** \file - \brief This file contains the DLL interface of muparser. -*/ + /** \file + \brief This file contains the DLL interface of muparser. + */ -// Basic types -typedef void* muParserHandle_t; // parser handle + // Basic types + typedef void* muParserHandle_t; // parser handle #ifndef _UNICODE - typedef char muChar_t; // character type + typedef char muChar_t; // character type #else - typedef wchar_t muChar_t; // character type +typedef wchar_t muChar_t; // character type #endif -typedef int muBool_t; // boolean type -typedef int muInt_t; // integer type -typedef double muFloat_t; // floating point type - -// function types for calculation -typedef muFloat_t (*muFun0_t )(); -typedef muFloat_t (*muFun1_t )(muFloat_t); -typedef muFloat_t (*muFun2_t )(muFloat_t, muFloat_t); -typedef muFloat_t (*muFun3_t )(muFloat_t, muFloat_t, muFloat_t); -typedef muFloat_t (*muFun4_t )(muFloat_t, muFloat_t, muFloat_t, muFloat_t); -typedef muFloat_t (*muFun5_t )(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); -typedef muFloat_t (*muFun6_t )(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); -typedef muFloat_t (*muFun7_t )(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); -typedef muFloat_t (*muFun8_t )(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); -typedef muFloat_t (*muFun9_t )(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); -typedef muFloat_t (*muFun10_t)(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); - -// Function prototypes for bulkmode functions -typedef muFloat_t (*muBulkFun0_t )(int, int); -typedef muFloat_t (*muBulkFun1_t )(int, int, muFloat_t); -typedef muFloat_t (*muBulkFun2_t )(int, int, muFloat_t, muFloat_t); -typedef muFloat_t (*muBulkFun3_t )(int, int, muFloat_t, muFloat_t, muFloat_t); -typedef muFloat_t (*muBulkFun4_t )(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t); -typedef muFloat_t (*muBulkFun5_t )(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); -typedef muFloat_t (*muBulkFun6_t )(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); -typedef muFloat_t (*muBulkFun7_t )(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); -typedef muFloat_t (*muBulkFun8_t )(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); -typedef muFloat_t (*muBulkFun9_t )(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); -typedef muFloat_t (*muBulkFun10_t)(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); - -typedef muFloat_t (*muMultFun_t)(const muFloat_t*, muInt_t); -typedef muFloat_t (*muStrFun1_t)(const muChar_t*); -typedef muFloat_t (*muStrFun2_t)(const muChar_t*, muFloat_t); -typedef muFloat_t (*muStrFun3_t)(const muChar_t*, muFloat_t, muFloat_t); - -// Functions for parser management -typedef void (*muErrorHandler_t)(muParserHandle_t a_hParser); // [optional] callback to an error handler -typedef muFloat_t* (*muFacFun_t)(const muChar_t*, void*); // [optional] callback for creating new variables -typedef muInt_t (*muIdentFun_t)(const muChar_t*, muInt_t*, muFloat_t*); // [optional] value identification callbacks - -//----------------------------------------------------------------------------------------------------- -// Constants -static const int muOPRT_ASCT_LEFT = 0; -static const int muOPRT_ASCT_RIGHT = 1; - -static const int muBASETYPE_FLOAT = 0; -static const int muBASETYPE_INT = 1; - -//----------------------------------------------------------------------------------------------------- -// -// -// muParser C compatible bindings -// -// -//----------------------------------------------------------------------------------------------------- - - -// Basic operations / initialization -API_EXPORT(muParserHandle_t) mupCreate(int nBaseType); -API_EXPORT(void) mupRelease(muParserHandle_t a_hParser); -API_EXPORT(const muChar_t*) mupGetExpr(muParserHandle_t a_hParser); -API_EXPORT(void) mupSetExpr(muParserHandle_t a_hParser, const muChar_t *a_szExpr); -API_EXPORT(void) mupSetVarFactory(muParserHandle_t a_hParser, muFacFun_t a_pFactory, void* pUserData); -API_EXPORT(const muChar_t*) mupGetVersion(muParserHandle_t a_hParser); -API_EXPORT(muFloat_t) mupEval(muParserHandle_t a_hParser); -API_EXPORT(muFloat_t*) mupEvalMulti(muParserHandle_t a_hParser, int *nNum); -API_EXPORT(void) mupEvalBulk(muParserHandle_t a_hParser, muFloat_t *a_fResult, int nSize); - -// Defining callbacks / variables / constants -API_EXPORT(void) mupDefineFun0(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun0_t a_pFun, muBool_t a_bOptimize); -API_EXPORT(void) mupDefineFun1(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun1_t a_pFun, muBool_t a_bOptimize); -API_EXPORT(void) mupDefineFun2(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun2_t a_pFun, muBool_t a_bOptimize); -API_EXPORT(void) mupDefineFun3(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun3_t a_pFun, muBool_t a_bOptimize); -API_EXPORT(void) mupDefineFun4(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun4_t a_pFun, muBool_t a_bOptimize); -API_EXPORT(void) mupDefineFun5(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun5_t a_pFun, muBool_t a_bOptimize); -API_EXPORT(void) mupDefineFun6(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun6_t a_pFun, muBool_t a_bOptimize); -API_EXPORT(void) mupDefineFun7(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun7_t a_pFun, muBool_t a_bOptimize); -API_EXPORT(void) mupDefineFun8(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun8_t a_pFun, muBool_t a_bOptimize); -API_EXPORT(void) mupDefineFun9(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun9_t a_pFun, muBool_t a_bOptimize); -API_EXPORT(void) mupDefineFun10(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun10_t a_pFun, muBool_t a_bOptimize); - -// Defining bulkmode functions -API_EXPORT(void) mupDefineBulkFun0(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun0_t a_pFun); -API_EXPORT(void) mupDefineBulkFun1(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun1_t a_pFun); -API_EXPORT(void) mupDefineBulkFun2(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun2_t a_pFun); -API_EXPORT(void) mupDefineBulkFun3(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun3_t a_pFun); -API_EXPORT(void) mupDefineBulkFun4(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun4_t a_pFun); -API_EXPORT(void) mupDefineBulkFun5(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun5_t a_pFun); -API_EXPORT(void) mupDefineBulkFun6(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun6_t a_pFun); -API_EXPORT(void) mupDefineBulkFun7(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun7_t a_pFun); -API_EXPORT(void) mupDefineBulkFun8(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun8_t a_pFun); -API_EXPORT(void) mupDefineBulkFun9(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun9_t a_pFun); -API_EXPORT(void) mupDefineBulkFun10(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun10_t a_pFun); - -// string functions -API_EXPORT(void) mupDefineStrFun1(muParserHandle_t a_hParser, const muChar_t *a_szName, muStrFun1_t a_pFun); -API_EXPORT(void) mupDefineStrFun2(muParserHandle_t a_hParser, const muChar_t *a_szName, muStrFun2_t a_pFun); -API_EXPORT(void) mupDefineStrFun3(muParserHandle_t a_hParser, const muChar_t *a_szName, muStrFun3_t a_pFun); - -API_EXPORT(void) mupDefineMultFun( muParserHandle_t a_hParser, - const muChar_t* a_szName, - muMultFun_t a_pFun, - muBool_t a_bOptimize); - -API_EXPORT(void) mupDefineOprt( muParserHandle_t a_hParser, - const muChar_t* a_szName, - muFun2_t a_pFun, - muInt_t a_nPrec, - muInt_t a_nOprtAsct, - muBool_t a_bOptimize); - -API_EXPORT(void) mupDefineConst( muParserHandle_t a_hParser, - const muChar_t* a_szName, - muFloat_t a_fVal ); - -API_EXPORT(void) mupDefineStrConst( muParserHandle_t a_hParser, - const muChar_t* a_szName, - const muChar_t *a_sVal ); - -API_EXPORT(void) mupDefineVar( muParserHandle_t a_hParser, - const muChar_t* a_szName, - muFloat_t *a_fVar); - -API_EXPORT(void) mupDefineBulkVar( muParserHandle_t a_hParser, - const muChar_t* a_szName, - muFloat_t *a_fVar); - -API_EXPORT(void) mupDefinePostfixOprt( muParserHandle_t a_hParser, - const muChar_t* a_szName, - muFun1_t a_pOprt, - muBool_t a_bOptimize); - - -API_EXPORT(void) mupDefineInfixOprt( muParserHandle_t a_hParser, - const muChar_t* a_szName, - muFun1_t a_pOprt, - muBool_t a_bOptimize); - -// Define character sets for identifiers -API_EXPORT(void) mupDefineNameChars(muParserHandle_t a_hParser, const muChar_t* a_szCharset); -API_EXPORT(void) mupDefineOprtChars(muParserHandle_t a_hParser, const muChar_t* a_szCharset); -API_EXPORT(void) mupDefineInfixOprtChars(muParserHandle_t a_hParser, const muChar_t* a_szCharset); - -// Remove all / single variables -API_EXPORT(void) mupRemoveVar(muParserHandle_t a_hParser, const muChar_t* a_szName); -API_EXPORT(void) mupClearVar(muParserHandle_t a_hParser); -API_EXPORT(void) mupClearConst(muParserHandle_t a_hParser); -API_EXPORT(void) mupClearOprt(muParserHandle_t a_hParser); -API_EXPORT(void) mupClearFun(muParserHandle_t a_hParser); - -// Querying variables / expression variables / constants -API_EXPORT(int) mupGetExprVarNum(muParserHandle_t a_hParser); -API_EXPORT(int) mupGetVarNum(muParserHandle_t a_hParser); -API_EXPORT(int) mupGetConstNum(muParserHandle_t a_hParser); -API_EXPORT(void) mupGetExprVar(muParserHandle_t a_hParser, unsigned a_iVar, const muChar_t** a_pszName, muFloat_t** a_pVar); -API_EXPORT(void) mupGetVar(muParserHandle_t a_hParser, unsigned a_iVar, const muChar_t** a_pszName, muFloat_t** a_pVar); -API_EXPORT(void) mupGetConst(muParserHandle_t a_hParser, unsigned a_iVar, const muChar_t** a_pszName, muFloat_t* a_pVar); -API_EXPORT(void) mupSetArgSep(muParserHandle_t a_hParser, const muChar_t cArgSep); -API_EXPORT(void) mupSetDecSep(muParserHandle_t a_hParser, const muChar_t cArgSep); -API_EXPORT(void) mupSetThousandsSep(muParserHandle_t a_hParser, const muChar_t cArgSep); -API_EXPORT(void) mupResetLocale(muParserHandle_t a_hParser); - -// Add value recognition callbacks -API_EXPORT(void) mupAddValIdent(muParserHandle_t a_hParser, muIdentFun_t); - -// Error handling -API_EXPORT(muBool_t) mupError(muParserHandle_t a_hParser); -API_EXPORT(void) mupErrorReset(muParserHandle_t a_hParser); -API_EXPORT(void) mupSetErrorHandler(muParserHandle_t a_hParser, muErrorHandler_t a_pErrHandler); -API_EXPORT(const muChar_t*) mupGetErrorMsg(muParserHandle_t a_hParser); -API_EXPORT(muInt_t) mupGetErrorCode(muParserHandle_t a_hParser); -API_EXPORT(muInt_t) mupGetErrorPos(muParserHandle_t a_hParser); -API_EXPORT(const muChar_t*) mupGetErrorToken(muParserHandle_t a_hParser); -//API_EXPORT(const muChar_t*) mupGetErrorExpr(muParserHandle_t a_hParser); - -// This is used for .NET only. It creates a new variable allowing the dll to -// manage the variable rather than the .NET garbage collector. -API_EXPORT(muFloat_t*) mupCreateVar(); -API_EXPORT(void) mupReleaseVar(muFloat_t*); + typedef int muBool_t; // boolean type + typedef int muInt_t; // integer type + typedef double muFloat_t; // floating point type + + // function types for calculation + typedef muFloat_t (*muFun0_t)(); + typedef muFloat_t (*muFun1_t)(muFloat_t); + typedef muFloat_t (*muFun2_t)(muFloat_t, muFloat_t); + typedef muFloat_t (*muFun3_t)(muFloat_t, muFloat_t, muFloat_t); + typedef muFloat_t (*muFun4_t)(muFloat_t, muFloat_t, muFloat_t, muFloat_t); + typedef muFloat_t (*muFun5_t)(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); + typedef muFloat_t (*muFun6_t)(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); + typedef muFloat_t (*muFun7_t)(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); + typedef muFloat_t ( + *muFun8_t)(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); + typedef muFloat_t ( + *muFun9_t)(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); + typedef muFloat_t (*muFun10_t)(muFloat_t, + muFloat_t, + muFloat_t, + muFloat_t, + muFloat_t, + muFloat_t, + muFloat_t, + muFloat_t, + muFloat_t, + muFloat_t); + + // Function prototypes for bulkmode functions + typedef muFloat_t (*muBulkFun0_t)(int, int); + typedef muFloat_t (*muBulkFun1_t)(int, int, muFloat_t); + typedef muFloat_t (*muBulkFun2_t)(int, int, muFloat_t, muFloat_t); + typedef muFloat_t (*muBulkFun3_t)(int, int, muFloat_t, muFloat_t, muFloat_t); + typedef muFloat_t (*muBulkFun4_t)(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t); + typedef muFloat_t (*muBulkFun5_t)(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); + typedef muFloat_t (*muBulkFun6_t)(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); + typedef muFloat_t ( + *muBulkFun7_t)(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); + typedef muFloat_t ( + *muBulkFun8_t)(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); + typedef muFloat_t (*muBulkFun9_t)(int, + int, + muFloat_t, + muFloat_t, + muFloat_t, + muFloat_t, + muFloat_t, + muFloat_t, + muFloat_t, + muFloat_t, + muFloat_t); + typedef muFloat_t (*muBulkFun10_t)(int, + int, + muFloat_t, + muFloat_t, + muFloat_t, + muFloat_t, + muFloat_t, + muFloat_t, + muFloat_t, + muFloat_t, + muFloat_t, + muFloat_t); + + typedef muFloat_t (*muMultFun_t)(const muFloat_t*, muInt_t); + typedef muFloat_t (*muStrFun1_t)(const muChar_t*); + typedef muFloat_t (*muStrFun2_t)(const muChar_t*, muFloat_t); + typedef muFloat_t (*muStrFun3_t)(const muChar_t*, muFloat_t, muFloat_t); + + // Functions for parser management + typedef void (*muErrorHandler_t)(muParserHandle_t a_hParser); // [optional] callback to an error handler + typedef muFloat_t* (*muFacFun_t)(const muChar_t*, void*); // [optional] callback for creating new variables + typedef muInt_t (*muIdentFun_t)(const muChar_t*, muInt_t*, muFloat_t*); // [optional] value identification callbacks + + //----------------------------------------------------------------------------------------------------- + // Constants + static const int muOPRT_ASCT_LEFT = 0; + static const int muOPRT_ASCT_RIGHT = 1; + + static const int muBASETYPE_FLOAT = 0; + static const int muBASETYPE_INT = 1; + + //----------------------------------------------------------------------------------------------------- + // + // + // muParser C compatible bindings + // + // + //----------------------------------------------------------------------------------------------------- + + // Basic operations / initialization + API_EXPORT(muParserHandle_t) mupCreate(int nBaseType); + API_EXPORT(void) mupRelease(muParserHandle_t a_hParser); + API_EXPORT(const muChar_t*) mupGetExpr(muParserHandle_t a_hParser); + API_EXPORT(void) mupSetExpr(muParserHandle_t a_hParser, const muChar_t* a_szExpr); + API_EXPORT(void) mupSetVarFactory(muParserHandle_t a_hParser, muFacFun_t a_pFactory, void* pUserData); + API_EXPORT(const muChar_t*) mupGetVersion(muParserHandle_t a_hParser); + API_EXPORT(muFloat_t) mupEval(muParserHandle_t a_hParser); + API_EXPORT(muFloat_t*) mupEvalMulti(muParserHandle_t a_hParser, int* nNum); + API_EXPORT(void) mupEvalBulk(muParserHandle_t a_hParser, muFloat_t* a_fResult, int nSize); + + // Defining callbacks / variables / constants + API_EXPORT(void) + mupDefineFun0(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun0_t a_pFun, muBool_t a_bOptimize); + API_EXPORT(void) + mupDefineFun1(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun1_t a_pFun, muBool_t a_bOptimize); + API_EXPORT(void) + mupDefineFun2(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun2_t a_pFun, muBool_t a_bOptimize); + API_EXPORT(void) + mupDefineFun3(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun3_t a_pFun, muBool_t a_bOptimize); + API_EXPORT(void) + mupDefineFun4(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun4_t a_pFun, muBool_t a_bOptimize); + API_EXPORT(void) + mupDefineFun5(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun5_t a_pFun, muBool_t a_bOptimize); + API_EXPORT(void) + mupDefineFun6(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun6_t a_pFun, muBool_t a_bOptimize); + API_EXPORT(void) + mupDefineFun7(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun7_t a_pFun, muBool_t a_bOptimize); + API_EXPORT(void) + mupDefineFun8(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun8_t a_pFun, muBool_t a_bOptimize); + API_EXPORT(void) + mupDefineFun9(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun9_t a_pFun, muBool_t a_bOptimize); + API_EXPORT(void) + mupDefineFun10(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun10_t a_pFun, muBool_t a_bOptimize); + + // Defining bulkmode functions + API_EXPORT(void) mupDefineBulkFun0(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFun0_t a_pFun); + API_EXPORT(void) mupDefineBulkFun1(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFun1_t a_pFun); + API_EXPORT(void) mupDefineBulkFun2(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFun2_t a_pFun); + API_EXPORT(void) mupDefineBulkFun3(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFun3_t a_pFun); + API_EXPORT(void) mupDefineBulkFun4(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFun4_t a_pFun); + API_EXPORT(void) mupDefineBulkFun5(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFun5_t a_pFun); + API_EXPORT(void) mupDefineBulkFun6(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFun6_t a_pFun); + API_EXPORT(void) mupDefineBulkFun7(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFun7_t a_pFun); + API_EXPORT(void) mupDefineBulkFun8(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFun8_t a_pFun); + API_EXPORT(void) mupDefineBulkFun9(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFun9_t a_pFun); + API_EXPORT(void) mupDefineBulkFun10(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFun10_t a_pFun); + + // string functions + API_EXPORT(void) mupDefineStrFun1(muParserHandle_t a_hParser, const muChar_t* a_szName, muStrFun1_t a_pFun); + API_EXPORT(void) mupDefineStrFun2(muParserHandle_t a_hParser, const muChar_t* a_szName, muStrFun2_t a_pFun); + API_EXPORT(void) mupDefineStrFun3(muParserHandle_t a_hParser, const muChar_t* a_szName, muStrFun3_t a_pFun); + + API_EXPORT(void) + mupDefineMultFun(muParserHandle_t a_hParser, const muChar_t* a_szName, muMultFun_t a_pFun, muBool_t a_bOptimize); + + API_EXPORT(void) + mupDefineOprt(muParserHandle_t a_hParser, + const muChar_t* a_szName, + muFun2_t a_pFun, + muInt_t a_nPrec, + muInt_t a_nOprtAsct, + muBool_t a_bOptimize); + + API_EXPORT(void) mupDefineConst(muParserHandle_t a_hParser, const muChar_t* a_szName, muFloat_t a_fVal); + + API_EXPORT(void) mupDefineStrConst(muParserHandle_t a_hParser, const muChar_t* a_szName, const muChar_t* a_sVal); + + API_EXPORT(void) mupDefineVar(muParserHandle_t a_hParser, const muChar_t* a_szName, muFloat_t* a_fVar); + + API_EXPORT(void) mupDefineBulkVar(muParserHandle_t a_hParser, const muChar_t* a_szName, muFloat_t* a_fVar); + + API_EXPORT(void) + mupDefinePostfixOprt(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun1_t a_pOprt, muBool_t a_bOptimize); + + API_EXPORT(void) + mupDefineInfixOprt(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun1_t a_pOprt, muBool_t a_bOptimize); + + // Define character sets for identifiers + API_EXPORT(void) mupDefineNameChars(muParserHandle_t a_hParser, const muChar_t* a_szCharset); + API_EXPORT(void) mupDefineOprtChars(muParserHandle_t a_hParser, const muChar_t* a_szCharset); + API_EXPORT(void) mupDefineInfixOprtChars(muParserHandle_t a_hParser, const muChar_t* a_szCharset); + + // Remove all / single variables + API_EXPORT(void) mupRemoveVar(muParserHandle_t a_hParser, const muChar_t* a_szName); + API_EXPORT(void) mupClearVar(muParserHandle_t a_hParser); + API_EXPORT(void) mupClearConst(muParserHandle_t a_hParser); + API_EXPORT(void) mupClearOprt(muParserHandle_t a_hParser); + API_EXPORT(void) mupClearFun(muParserHandle_t a_hParser); + + // Querying variables / expression variables / constants + API_EXPORT(int) mupGetExprVarNum(muParserHandle_t a_hParser); + API_EXPORT(int) mupGetVarNum(muParserHandle_t a_hParser); + API_EXPORT(int) mupGetConstNum(muParserHandle_t a_hParser); + API_EXPORT(void) + mupGetExprVar(muParserHandle_t a_hParser, unsigned a_iVar, const muChar_t** a_pszName, muFloat_t** a_pVar); + API_EXPORT(void) + mupGetVar(muParserHandle_t a_hParser, unsigned a_iVar, const muChar_t** a_pszName, muFloat_t** a_pVar); + API_EXPORT(void) + mupGetConst(muParserHandle_t a_hParser, unsigned a_iVar, const muChar_t** a_pszName, muFloat_t* a_pVar); + API_EXPORT(void) mupSetArgSep(muParserHandle_t a_hParser, const muChar_t cArgSep); + API_EXPORT(void) mupSetDecSep(muParserHandle_t a_hParser, const muChar_t cArgSep); + API_EXPORT(void) mupSetThousandsSep(muParserHandle_t a_hParser, const muChar_t cArgSep); + API_EXPORT(void) mupResetLocale(muParserHandle_t a_hParser); + + // Add value recognition callbacks + API_EXPORT(void) mupAddValIdent(muParserHandle_t a_hParser, muIdentFun_t); + + // Error handling + API_EXPORT(muBool_t) mupError(muParserHandle_t a_hParser); + API_EXPORT(void) mupErrorReset(muParserHandle_t a_hParser); + API_EXPORT(void) mupSetErrorHandler(muParserHandle_t a_hParser, muErrorHandler_t a_pErrHandler); + API_EXPORT(const muChar_t*) mupGetErrorMsg(muParserHandle_t a_hParser); + API_EXPORT(muInt_t) mupGetErrorCode(muParserHandle_t a_hParser); + API_EXPORT(muInt_t) mupGetErrorPos(muParserHandle_t a_hParser); + API_EXPORT(const muChar_t*) mupGetErrorToken(muParserHandle_t a_hParser); + // API_EXPORT(const muChar_t*) mupGetErrorExpr(muParserHandle_t a_hParser); + + // This is used for .NET only. It creates a new variable allowing the dll to + // manage the variable rather than the .NET garbage collector. + API_EXPORT(muFloat_t*) mupCreateVar(); + API_EXPORT(void) mupReleaseVar(muFloat_t*); #ifdef __cplusplus } diff --git a/ext_libs/muparser/muParserDef.h b/ext_libs/muparser/muParserDef.h old mode 100755 new mode 100644 index 437f2eaf..87d2510b --- a/ext_libs/muparser/muParserDef.h +++ b/ext_libs/muparser/muParserDef.h @@ -1,26 +1,26 @@ /* - __________ - _____ __ __\______ \_____ _______ ______ ____ _______ + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ - |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| - \/ \/ \/ \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ Copyright (C) 2014 Ingo Berg - Permission is hereby granted, free of charge, to any person obtaining a copy of this + 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 + 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 + 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. + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MUP_DEF_H #define MUP_DEF_H @@ -51,128 +51,125 @@ */ #define MUP_BASETYPE double -/** \brief Activate this option in order to compile with OpenMP support. +/** \brief Activate this option in order to compile with OpenMP support. - OpenMP is used only in the bulk mode it may increase the performance a bit. + OpenMP is used only in the bulk mode it may increase the performance a bit. */ //#define MUP_USE_OPENMP #if defined(_UNICODE) - /** \brief Definition of the basic parser string type. */ - #define MUP_STRING_TYPE std::wstring +/** \brief Definition of the basic parser string type. */ +#define MUP_STRING_TYPE std::wstring - #if !defined(_T) - #define _T(x) L##x - #endif // not defined _T +#if !defined(_T) +#define _T(x) L##x +#endif // not defined _T #else - #ifndef _T - #define _T(x) x - #endif - - /** \brief Definition of the basic parser string type. */ - #define MUP_STRING_TYPE std::string +#ifndef _T +#define _T(x) x +#endif + +/** \brief Definition of the basic parser string type. */ +#define MUP_STRING_TYPE std::string #endif #if defined(_DEBUG) - /** \brief Debug macro to force an abortion of the programm with a certain message. - */ - #define MUP_FAIL(MSG) \ - { \ - bool MSG=false; \ - assert(MSG); \ - } - - /** \brief An assertion that does not kill the program. - - This macro is neutralised in UNICODE builds. It's - too difficult to translate. - */ - #define MUP_ASSERT(COND) \ - if (!(COND)) \ - { \ - stringstream_type ss; \ - ss << _T("Assertion \"") _T(#COND) _T("\" failed: ") \ - << __FILE__ << _T(" line ") \ - << __LINE__ << _T("."); \ - throw ParserError( ss.str() ); \ - } +/** \brief Debug macro to force an abortion of the programm with a certain message. + */ +#define MUP_FAIL(MSG) \ + { \ + bool MSG = false; \ + assert(MSG); \ + } + +/** \brief An assertion that does not kill the program. + + This macro is neutralised in UNICODE builds. It's + too difficult to translate. +*/ +#define MUP_ASSERT(COND) \ + if (!(COND)) \ + { \ + stringstream_type ss; \ + ss << _T("Assertion \"") _T(#COND) _T("\" failed: ") << __FILE__ << _T(" line ") << __LINE__ << _T("."); \ + throw ParserError(ss.str()); \ + } #else - #define MUP_FAIL(MSG) - #define MUP_ASSERT(COND) +#define MUP_FAIL(MSG) +#define MUP_ASSERT(COND) #endif - namespace mu { #if defined(_UNICODE) - //------------------------------------------------------------------------------ - /** \brief Encapsulate wcout. */ - inline std::wostream& console() - { +//------------------------------------------------------------------------------ +/** \brief Encapsulate wcout. */ +inline std::wostream& console() +{ return std::wcout; - } +} - /** \brief Encapsulate cin. */ - inline std::wistream& console_in() - { +/** \brief Encapsulate cin. */ +inline std::wistream& console_in() +{ return std::wcin; - } +} #else - /** \brief Encapsulate cout. - - Used for supporting UNICODE more easily. - */ - inline std::ostream& console() - { +/** \brief Encapsulate cout. + + Used for supporting UNICODE more easily. +*/ +inline std::ostream& console() +{ return std::cout; - } +} - /** \brief Encapsulate cin. +/** \brief Encapsulate cin. - Used for supporting UNICODE more easily. - */ - inline std::istream& console_in() - { + Used for supporting UNICODE more easily. +*/ +inline std::istream& console_in() +{ return std::cin; - } +} #endif - //------------------------------------------------------------------------------ - /** \brief Bytecode values. +//------------------------------------------------------------------------------ +/** \brief Bytecode values. - \attention The order of the operator entries must match the order in ParserBase::c_DefaultOprt! - */ - enum ECmdCode - { + \attention The order of the operator entries must match the order in ParserBase::c_DefaultOprt! +*/ +enum ECmdCode +{ // The following are codes for built in binary operators // apart from built in operators the user has the opportunity to // add user defined operators. - cmLE = 0, ///< Operator item: less or equal - cmGE = 1, ///< Operator item: greater or equal - cmNEQ = 2, ///< Operator item: not equal - cmEQ = 3, ///< Operator item: equals - cmLT = 4, ///< Operator item: less than - cmGT = 5, ///< Operator item: greater than - cmADD = 6, ///< Operator item: add - cmSUB = 7, ///< Operator item: subtract - cmMUL = 8, ///< Operator item: multiply - cmDIV = 9, ///< Operator item: division - cmPOW = 10, ///< Operator item: y to the power of ... - cmLAND = 11, - cmLOR = 12, - cmASSIGN = 13, ///< Operator item: Assignment operator - cmBO = 14, ///< Operator item: opening bracket - cmBC = 15, ///< Operator item: closing bracket - cmIF = 16, ///< For use in the ternary if-then-else operator - cmELSE = 17, ///< For use in the ternary if-then-else operator - cmENDIF = 18, ///< For use in the ternary if-then-else operator - cmARG_SEP = 19, ///< function argument separator - cmVAR = 20, ///< variable item - cmVAL = 21, ///< value item + cmLE = 0, ///< Operator item: less or equal + cmGE = 1, ///< Operator item: greater or equal + cmNEQ = 2, ///< Operator item: not equal + cmEQ = 3, ///< Operator item: equals + cmLT = 4, ///< Operator item: less than + cmGT = 5, ///< Operator item: greater than + cmADD = 6, ///< Operator item: add + cmSUB = 7, ///< Operator item: subtract + cmMUL = 8, ///< Operator item: multiply + cmDIV = 9, ///< Operator item: division + cmPOW = 10, ///< Operator item: y to the power of ... + cmLAND = 11, + cmLOR = 12, + cmASSIGN = 13, ///< Operator item: Assignment operator + cmBO = 14, ///< Operator item: opening bracket + cmBC = 15, ///< Operator item: closing bracket + cmIF = 16, ///< For use in the ternary if-then-else operator + cmELSE = 17, ///< For use in the ternary if-then-else operator + cmENDIF = 18, ///< For use in the ternary if-then-else operator + cmARG_SEP = 19, ///< function argument separator + cmVAR = 20, ///< variable item + cmVAL = 21, ///< value item // For optimization purposes cmVARPOW2, @@ -182,187 +179,226 @@ namespace mu cmPOW2, // operators and functions - cmFUNC, ///< Code for a generic function item - cmFUNC_STR, ///< Code for a function with a string parameter - cmFUNC_BULK, ///< Special callbacks for Bulk mode with an additional parameter for the bulk index - cmSTRING, ///< Code for a string token - cmOPRT_BIN, ///< user defined binary operator - cmOPRT_POSTFIX, ///< code for postfix operators - cmOPRT_INFIX, ///< code for infix operators - cmEND, ///< end of formula - cmUNKNOWN ///< uninitialized item - }; - - //------------------------------------------------------------------------------ - /** \brief Types internally used by the parser. - */ - enum ETypeCode - { - tpSTR = 0, ///< String type (Function arguments and constants only, no string variables) - tpDBL = 1, ///< Floating point variables - tpVOID = 2 ///< Undefined type. - }; - - //------------------------------------------------------------------------------ - enum EParserVersionInfo - { + cmFUNC, ///< Code for a generic function item + cmFUNC_STR, ///< Code for a function with a string parameter + cmFUNC_BULK, ///< Special callbacks for Bulk mode with an additional parameter for the bulk index + cmSTRING, ///< Code for a string token + cmOPRT_BIN, ///< user defined binary operator + cmOPRT_POSTFIX, ///< code for postfix operators + cmOPRT_INFIX, ///< code for infix operators + cmEND, ///< end of formula + cmUNKNOWN ///< uninitialized item +}; + +//------------------------------------------------------------------------------ +/** \brief Types internally used by the parser. + */ +enum ETypeCode +{ + tpSTR = 0, ///< String type (Function arguments and constants only, no string variables) + tpDBL = 1, ///< Floating point variables + tpVOID = 2 ///< Undefined type. +}; + +//------------------------------------------------------------------------------ +enum EParserVersionInfo +{ pviBRIEF, pviFULL - }; +}; - //------------------------------------------------------------------------------ - /** \brief Parser operator precedence values. */ - enum EOprtAssociativity - { - oaLEFT = 0, +//------------------------------------------------------------------------------ +/** \brief Parser operator precedence values. */ +enum EOprtAssociativity +{ + oaLEFT = 0, oaRIGHT = 1, - oaNONE = 2 - }; + oaNONE = 2 +}; - //------------------------------------------------------------------------------ - /** \brief Parser operator precedence values. */ - enum EOprtPrecedence - { +//------------------------------------------------------------------------------ +/** \brief Parser operator precedence values. */ +enum EOprtPrecedence +{ // binary operators - prLOR = 1, - prLAND = 2, - prLOGIC = 3, ///< logic operators - prCMP = 4, ///< comparsion operators - prADD_SUB = 5, ///< addition - prMUL_DIV = 6, ///< multiplication/division - prPOW = 7, ///< power operator priority (highest) + prLOR = 1, + prLAND = 2, + prLOGIC = 3, ///< logic operators + prCMP = 4, ///< comparsion operators + prADD_SUB = 5, ///< addition + prMUL_DIV = 6, ///< multiplication/division + prPOW = 7, ///< power operator priority (highest) // infix operators - prINFIX = 6, ///< Signs have a higher priority than ADD_SUB, but lower than power operator - prPOSTFIX = 6 ///< Postfix operator priority (currently unused) - }; - - //------------------------------------------------------------------------------ - // basic types - - /** \brief The numeric datatype used by the parser. - - Normally this is a floating point type either single or double precision. - */ - typedef MUP_BASETYPE value_type; - - /** \brief The stringtype used by the parser. - - Depends on wether UNICODE is used or not. - */ - typedef MUP_STRING_TYPE string_type; + prINFIX = 6, ///< Signs have a higher priority than ADD_SUB, but lower than power operator + prPOSTFIX = 6 ///< Postfix operator priority (currently unused) +}; - /** \brief The character type used by the parser. - - Depends on wether UNICODE is used or not. - */ - typedef string_type::value_type char_type; +//------------------------------------------------------------------------------ +// basic types - /** \brief Typedef for easily using stringstream that respect the parser stringtype. */ - typedef std::basic_stringstream, - std::allocator > stringstream_type; +/** \brief The numeric datatype used by the parser. - // Data container types - - /** \brief Type used for storing variables. */ - typedef std::map varmap_type; - - /** \brief Type used for storing constants. */ - typedef std::map valmap_type; - - /** \brief Type for assigning a string name to an index in the internal string table. */ - typedef std::map strmap_type; - - // Parser callbacks - - /** \brief Callback type used for functions without arguments. */ - typedef value_type (*generic_fun_type)(); - - /** \brief Callback type used for functions without arguments. */ - typedef value_type (*fun_type0)(); - - /** \brief Callback type used for functions with a single arguments. */ - typedef value_type (*fun_type1)(value_type); - - /** \brief Callback type used for functions with two arguments. */ - typedef value_type (*fun_type2)(value_type, value_type); - - /** \brief Callback type used for functions with three arguments. */ - typedef value_type (*fun_type3)(value_type, value_type, value_type); - - /** \brief Callback type used for functions with four arguments. */ - typedef value_type (*fun_type4)(value_type, value_type, value_type, value_type); - - /** \brief Callback type used for functions with five arguments. */ - typedef value_type (*fun_type5)(value_type, value_type, value_type, value_type, value_type); - - /** \brief Callback type used for functions with five arguments. */ - typedef value_type (*fun_type6)(value_type, value_type, value_type, value_type, value_type, value_type); - - /** \brief Callback type used for functions with five arguments. */ - typedef value_type (*fun_type7)(value_type, value_type, value_type, value_type, value_type, value_type, value_type); - - /** \brief Callback type used for functions with five arguments. */ - typedef value_type (*fun_type8)(value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type); - - /** \brief Callback type used for functions with five arguments. */ - typedef value_type (*fun_type9)(value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type); - - /** \brief Callback type used for functions with five arguments. */ - typedef value_type (*fun_type10)(value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type); - - /** \brief Callback type used for functions without arguments. */ - typedef value_type (*bulkfun_type0)(int, int); - - /** \brief Callback type used for functions with a single arguments. */ - typedef value_type (*bulkfun_type1)(int, int, value_type); - - /** \brief Callback type used for functions with two arguments. */ - typedef value_type (*bulkfun_type2)(int, int, value_type, value_type); - - /** \brief Callback type used for functions with three arguments. */ - typedef value_type (*bulkfun_type3)(int, int, value_type, value_type, value_type); - - /** \brief Callback type used for functions with four arguments. */ - typedef value_type (*bulkfun_type4)(int, int, value_type, value_type, value_type, value_type); + Normally this is a floating point type either single or double precision. +*/ +typedef MUP_BASETYPE value_type; - /** \brief Callback type used for functions with five arguments. */ - typedef value_type (*bulkfun_type5)(int, int, value_type, value_type, value_type, value_type, value_type); +/** \brief The stringtype used by the parser. - /** \brief Callback type used for functions with five arguments. */ - typedef value_type (*bulkfun_type6)(int, int, value_type, value_type, value_type, value_type, value_type, value_type); + Depends on wether UNICODE is used or not. +*/ +typedef MUP_STRING_TYPE string_type; - /** \brief Callback type used for functions with five arguments. */ - typedef value_type (*bulkfun_type7)(int, int, value_type, value_type, value_type, value_type, value_type, value_type, value_type); +/** \brief The character type used by the parser. - /** \brief Callback type used for functions with five arguments. */ - typedef value_type (*bulkfun_type8)(int, int, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type); + Depends on wether UNICODE is used or not. +*/ +typedef string_type::value_type char_type; - /** \brief Callback type used for functions with five arguments. */ - typedef value_type (*bulkfun_type9)(int, int, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type); +/** \brief Typedef for easily using stringstream that respect the parser stringtype. */ +typedef std::basic_stringstream, std::allocator > stringstream_type; - /** \brief Callback type used for functions with five arguments. */ - typedef value_type (*bulkfun_type10)(int, int, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type); +// Data container types - /** \brief Callback type used for functions with a variable argument list. */ - typedef value_type (*multfun_type)(const value_type*, int); +/** \brief Type used for storing variables. */ +typedef std::map varmap_type; - /** \brief Callback type used for functions taking a string as an argument. */ - typedef value_type (*strfun_type1)(const char_type*); +/** \brief Type used for storing constants. */ +typedef std::map valmap_type; - /** \brief Callback type used for functions taking a string and a value as arguments. */ - typedef value_type (*strfun_type2)(const char_type*, value_type); +/** \brief Type for assigning a string name to an index in the internal string table. */ +typedef std::map strmap_type; - /** \brief Callback type used for functions taking a string and two values as arguments. */ - typedef value_type (*strfun_type3)(const char_type*, value_type, value_type); +// Parser callbacks - /** \brief Callback used for functions that identify values in a string. */ - typedef int (*identfun_type)(const char_type *sExpr, int *nPos, value_type *fVal); +/** \brief Callback type used for functions without arguments. */ +typedef value_type (*generic_fun_type)(); + +/** \brief Callback type used for functions without arguments. */ +typedef value_type (*fun_type0)(); + +/** \brief Callback type used for functions with a single arguments. */ +typedef value_type (*fun_type1)(value_type); + +/** \brief Callback type used for functions with two arguments. */ +typedef value_type (*fun_type2)(value_type, value_type); + +/** \brief Callback type used for functions with three arguments. */ +typedef value_type (*fun_type3)(value_type, value_type, value_type); + +/** \brief Callback type used for functions with four arguments. */ +typedef value_type (*fun_type4)(value_type, value_type, value_type, value_type); + +/** \brief Callback type used for functions with five arguments. */ +typedef value_type (*fun_type5)(value_type, value_type, value_type, value_type, value_type); + +/** \brief Callback type used for functions with five arguments. */ +typedef value_type (*fun_type6)(value_type, value_type, value_type, value_type, value_type, value_type); + +/** \brief Callback type used for functions with five arguments. */ +typedef value_type (*fun_type7)(value_type, value_type, value_type, value_type, value_type, value_type, value_type); + +/** \brief Callback type used for functions with five arguments. */ +typedef value_type ( + *fun_type8)(value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type); + +/** \brief Callback type used for functions with five arguments. */ +typedef value_type ( + *fun_type9)(value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type); + +/** \brief Callback type used for functions with five arguments. */ +typedef value_type (*fun_type10)(value_type, + value_type, + value_type, + value_type, + value_type, + value_type, + value_type, + value_type, + value_type, + value_type); + +/** \brief Callback type used for functions without arguments. */ +typedef value_type (*bulkfun_type0)(int, int); + +/** \brief Callback type used for functions with a single arguments. */ +typedef value_type (*bulkfun_type1)(int, int, value_type); + +/** \brief Callback type used for functions with two arguments. */ +typedef value_type (*bulkfun_type2)(int, int, value_type, value_type); + +/** \brief Callback type used for functions with three arguments. */ +typedef value_type (*bulkfun_type3)(int, int, value_type, value_type, value_type); + +/** \brief Callback type used for functions with four arguments. */ +typedef value_type (*bulkfun_type4)(int, int, value_type, value_type, value_type, value_type); + +/** \brief Callback type used for functions with five arguments. */ +typedef value_type (*bulkfun_type5)(int, int, value_type, value_type, value_type, value_type, value_type); + +/** \brief Callback type used for functions with five arguments. */ +typedef value_type (*bulkfun_type6)(int, int, value_type, value_type, value_type, value_type, value_type, value_type); + +/** \brief Callback type used for functions with five arguments. */ +typedef value_type ( + *bulkfun_type7)(int, int, value_type, value_type, value_type, value_type, value_type, value_type, value_type); + +/** \brief Callback type used for functions with five arguments. */ +typedef value_type (*bulkfun_type8)(int, + int, + value_type, + value_type, + value_type, + value_type, + value_type, + value_type, + value_type, + value_type); - /** \brief Callback used for variable creation factory functions. */ - typedef value_type* (*facfun_type)(const char_type*, void*); -} // end of namespace +/** \brief Callback type used for functions with five arguments. */ +typedef value_type (*bulkfun_type9)(int, + int, + value_type, + value_type, + value_type, + value_type, + value_type, + value_type, + value_type, + value_type, + value_type); + +/** \brief Callback type used for functions with five arguments. */ +typedef value_type (*bulkfun_type10)(int, + int, + value_type, + value_type, + value_type, + value_type, + value_type, + value_type, + value_type, + value_type, + value_type, + value_type); + +/** \brief Callback type used for functions with a variable argument list. */ +typedef value_type (*multfun_type)(const value_type*, int); + +/** \brief Callback type used for functions taking a string as an argument. */ +typedef value_type (*strfun_type1)(const char_type*); + +/** \brief Callback type used for functions taking a string and a value as arguments. */ +typedef value_type (*strfun_type2)(const char_type*, value_type); + +/** \brief Callback type used for functions taking a string and two values as arguments. */ +typedef value_type (*strfun_type3)(const char_type*, value_type, value_type); + +/** \brief Callback used for functions that identify values in a string. */ +typedef int (*identfun_type)(const char_type* sExpr, int* nPos, value_type* fVal); + +/** \brief Callback used for variable creation factory functions. */ +typedef value_type* (*facfun_type)(const char_type*, void*); +} // namespace mu #endif - diff --git a/ext_libs/muparser/muParserError.cpp b/ext_libs/muparser/muParserError.cpp old mode 100755 new mode 100644 index 6fe4e1d2..2a932e75 --- a/ext_libs/muparser/muParserError.cpp +++ b/ext_libs/muparser/muParserError.cpp @@ -1,244 +1,217 @@ /* - __________ - _____ __ __\______ \_____ _______ ______ ____ _______ + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ - |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| - \/ \/ \/ \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ Copyright (C) 2011 Ingo Berg - Permission is hereby granted, free of charge, to any person obtaining a copy of this + 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 + 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 + 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. + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "muParserError.h" - namespace mu { - const ParserErrorMsg ParserErrorMsg::m_Instance; +const ParserErrorMsg ParserErrorMsg::m_Instance; - //------------------------------------------------------------------------------ - const ParserErrorMsg& ParserErrorMsg::Instance() - { +//------------------------------------------------------------------------------ +const ParserErrorMsg& ParserErrorMsg::Instance() +{ return m_Instance; - } - - //------------------------------------------------------------------------------ - string_type ParserErrorMsg::operator[](unsigned a_iIdx) const - { - return (a_iIdx \___ >|__| - \/ \/ \/ \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ Copyright (C) 2004-2011 Ingo Berg - Permission is hereby granted, free of charge, to any person obtaining a copy of this + 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 + 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 + 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. + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MU_PARSER_ERROR_H @@ -35,92 +35,91 @@ #include "muParserDef.h" -/** \file +/** \file \brief This file defines the error class used by the parser. */ namespace mu { - /** \brief Error codes. */ enum EErrorCodes { - // Formula syntax errors - ecUNEXPECTED_OPERATOR = 0, ///< Unexpected binary operator found - ecUNASSIGNABLE_TOKEN = 1, ///< Token cant be identified. - ecUNEXPECTED_EOF = 2, ///< Unexpected end of formula. (Example: "2+sin(") - ecUNEXPECTED_ARG_SEP = 3, ///< An unexpected comma has been found. (Example: "1,23") - ecUNEXPECTED_ARG = 4, ///< An unexpected argument has been found - ecUNEXPECTED_VAL = 5, ///< An unexpected value token has been found - ecUNEXPECTED_VAR = 6, ///< An unexpected variable token has been found - ecUNEXPECTED_PARENS = 7, ///< Unexpected Parenthesis, opening or closing - ecUNEXPECTED_STR = 8, ///< A string has been found at an inapropriate position - ecSTRING_EXPECTED = 9, ///< A string function has been called with a different type of argument - ecVAL_EXPECTED = 10, ///< A numerical function has been called with a non value type of argument - ecMISSING_PARENS = 11, ///< Missing parens. (Example: "3*sin(3") - ecUNEXPECTED_FUN = 12, ///< Unexpected function found. (Example: "sin(8)cos(9)") - ecUNTERMINATED_STRING = 13, ///< unterminated string constant. (Example: "3*valueof("hello)") - ecTOO_MANY_PARAMS = 14, ///< Too many function parameters - ecTOO_FEW_PARAMS = 15, ///< Too few function parameters. (Example: "ite(1<2,2)") - ecOPRT_TYPE_CONFLICT = 16, ///< binary operators may only be applied to value items of the same type - ecSTR_RESULT = 17, ///< result is a string - - // Invalid Parser input Parameters - ecINVALID_NAME = 18, ///< Invalid function, variable or constant name. - ecINVALID_BINOP_IDENT = 19, ///< Invalid binary operator identifier - ecINVALID_INFIX_IDENT = 20, ///< Invalid function, variable or constant name. - ecINVALID_POSTFIX_IDENT = 21, ///< Invalid function, variable or constant name. - - ecBUILTIN_OVERLOAD = 22, ///< Trying to overload builtin operator - ecINVALID_FUN_PTR = 23, ///< Invalid callback function pointer - ecINVALID_VAR_PTR = 24, ///< Invalid variable pointer - ecEMPTY_EXPRESSION = 25, ///< The Expression is empty - ecNAME_CONFLICT = 26, ///< Name conflict - ecOPT_PRI = 27, ///< Invalid operator priority - // - ecDOMAIN_ERROR = 28, ///< catch division by zero, sqrt(-1), log(0) (currently unused) - ecDIV_BY_ZERO = 29, ///< Division by zero (currently unused) - ecGENERIC = 30, ///< Generic error - ecLOCALE = 31, ///< Conflict with current locale - - ecUNEXPECTED_CONDITIONAL = 32, - ecMISSING_ELSE_CLAUSE = 33, - ecMISPLACED_COLON = 34, - - ecUNREASONABLE_NUMBER_OF_COMPUTATIONS = 35, - - // internal errors - ecINTERNAL_ERROR = 36, ///< Internal error of any kind. - - // The last two are special entries - ecCOUNT, ///< This is no error code, It just stores just the total number of error codes - ecUNDEFINED = -1 ///< Undefined message, placeholder to detect unassigned error messages + // Formula syntax errors + ecUNEXPECTED_OPERATOR = 0, ///< Unexpected binary operator found + ecUNASSIGNABLE_TOKEN = 1, ///< Token cant be identified. + ecUNEXPECTED_EOF = 2, ///< Unexpected end of formula. (Example: "2+sin(") + ecUNEXPECTED_ARG_SEP = 3, ///< An unexpected comma has been found. (Example: "1,23") + ecUNEXPECTED_ARG = 4, ///< An unexpected argument has been found + ecUNEXPECTED_VAL = 5, ///< An unexpected value token has been found + ecUNEXPECTED_VAR = 6, ///< An unexpected variable token has been found + ecUNEXPECTED_PARENS = 7, ///< Unexpected Parenthesis, opening or closing + ecUNEXPECTED_STR = 8, ///< A string has been found at an inapropriate position + ecSTRING_EXPECTED = 9, ///< A string function has been called with a different type of argument + ecVAL_EXPECTED = 10, ///< A numerical function has been called with a non value type of argument + ecMISSING_PARENS = 11, ///< Missing parens. (Example: "3*sin(3") + ecUNEXPECTED_FUN = 12, ///< Unexpected function found. (Example: "sin(8)cos(9)") + ecUNTERMINATED_STRING = 13, ///< unterminated string constant. (Example: "3*valueof("hello)") + ecTOO_MANY_PARAMS = 14, ///< Too many function parameters + ecTOO_FEW_PARAMS = 15, ///< Too few function parameters. (Example: "ite(1<2,2)") + ecOPRT_TYPE_CONFLICT = 16, ///< binary operators may only be applied to value items of the same type + ecSTR_RESULT = 17, ///< result is a string + + // Invalid Parser input Parameters + ecINVALID_NAME = 18, ///< Invalid function, variable or constant name. + ecINVALID_BINOP_IDENT = 19, ///< Invalid binary operator identifier + ecINVALID_INFIX_IDENT = 20, ///< Invalid function, variable or constant name. + ecINVALID_POSTFIX_IDENT = 21, ///< Invalid function, variable or constant name. + + ecBUILTIN_OVERLOAD = 22, ///< Trying to overload builtin operator + ecINVALID_FUN_PTR = 23, ///< Invalid callback function pointer + ecINVALID_VAR_PTR = 24, ///< Invalid variable pointer + ecEMPTY_EXPRESSION = 25, ///< The Expression is empty + ecNAME_CONFLICT = 26, ///< Name conflict + ecOPT_PRI = 27, ///< Invalid operator priority + // + ecDOMAIN_ERROR = 28, ///< catch division by zero, sqrt(-1), log(0) (currently unused) + ecDIV_BY_ZERO = 29, ///< Division by zero (currently unused) + ecGENERIC = 30, ///< Generic error + ecLOCALE = 31, ///< Conflict with current locale + + ecUNEXPECTED_CONDITIONAL = 32, + ecMISSING_ELSE_CLAUSE = 33, + ecMISPLACED_COLON = 34, + + ecUNREASONABLE_NUMBER_OF_COMPUTATIONS = 35, + + // internal errors + ecINTERNAL_ERROR = 36, ///< Internal error of any kind. + + // The last two are special entries + ecCOUNT, ///< This is no error code, It just stores just the total number of error codes + ecUNDEFINED = -1 ///< Undefined message, placeholder to detect unassigned error messages }; //--------------------------------------------------------------------------- /** \brief A class that handles the error messages. -*/ + */ class ParserErrorMsg { public: typedef ParserErrorMsg self_type; - ParserErrorMsg& operator=(const ParserErrorMsg &); + ParserErrorMsg& operator=(const ParserErrorMsg&); ParserErrorMsg(const ParserErrorMsg&); ParserErrorMsg(); - ~ParserErrorMsg(); + ~ParserErrorMsg(); static const ParserErrorMsg& Instance(); string_type operator[](unsigned a_iIdx) const; private: - std::vector m_vErrMsg; ///< A vector with the predefined error messages - static const self_type m_Instance; ///< The instance pointer + std::vector m_vErrMsg; ///< A vector with the predefined error messages + static const self_type m_Instance; ///< The instance pointer }; //--------------------------------------------------------------------------- -/** \brief Error class of the parser. +/** \brief Error class of the parser. \author Ingo Berg Part of the math parser package. @@ -128,33 +127,25 @@ class ParserErrorMsg class ParserError { private: - /** \brief Replace all ocuurences of a substring with another string. */ - void ReplaceSubString( string_type &strSource, - const string_type &strFind, - const string_type &strReplaceWith); + void ReplaceSubString(string_type& strSource, const string_type& strFind, const string_type& strReplaceWith); void Reset(); public: - ParserError(); explicit ParserError(EErrorCodes a_iErrc); - explicit ParserError(const string_type &sMsg); - ParserError( EErrorCodes a_iErrc, - const string_type &sTok, - const string_type &sFormula = string_type(), - int a_iPos = -1); - ParserError( EErrorCodes a_iErrc, - int a_iPos, - const string_type &sTok); - ParserError( const char_type *a_szMsg, - int a_iPos = -1, - const string_type &sTok = string_type()); - ParserError(const ParserError &a_Obj); - ParserError& operator=(const ParserError &a_Obj); - ~ParserError(); - - void SetFormula(const string_type &a_strFormula); + explicit ParserError(const string_type& sMsg); + ParserError(EErrorCodes a_iErrc, + const string_type& sTok, + const string_type& sFormula = string_type(), + int a_iPos = -1); + ParserError(EErrorCodes a_iErrc, int a_iPos, const string_type& sTok); + ParserError(const char_type* a_szMsg, int a_iPos = -1, const string_type& sTok = string_type()); + ParserError(const ParserError& a_Obj); + ParserError& operator=(const ParserError& a_Obj); + ~ParserError(); + + void SetFormula(const string_type& a_strFormula); const string_type& GetExpr() const; const string_type& GetMsg() const; int GetPos() const; @@ -165,12 +156,11 @@ class ParserError string_type m_strMsg; ///< The message string string_type m_strFormula; ///< Formula string string_type m_strTok; ///< Token related with the error - int m_iPos; ///< Formula position related to the error + int m_iPos; ///< Formula position related to the error EErrorCodes m_iErrc; ///< Error code - const ParserErrorMsg &m_ErrMsg; -}; + const ParserErrorMsg& m_ErrMsg; +}; } // namespace mu #endif - diff --git a/ext_libs/muparser/muParserFixes.h b/ext_libs/muparser/muParserFixes.h old mode 100755 new mode 100644 index 1cd15e02..74a54828 --- a/ext_libs/muparser/muParserFixes.h +++ b/ext_libs/muparser/muParserFixes.h @@ -1,26 +1,26 @@ /* - __________ - _____ __ __\______ \_____ _______ ______ ____ _______ + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ - |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| - \/ \/ \/ \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ Copyright (C) 2013 Ingo Berg - Permission is hereby granted, free of charge, to any person obtaining a copy of this + 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 + 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 + 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. + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MU_PARSER_FIXES_H @@ -45,18 +45,16 @@ // remark #981: operands are evaluated in unspecified order // disabled -> completely pointless if the functions do not have side effects // -#pragma warning(disable:981) +#pragma warning(disable : 981) // remark #383: value copied to temporary, reference to temporary used -#pragma warning(disable:383) +#pragma warning(disable : 383) // remark #1572: floating-point equality and inequality comparisons are unreliable // disabled -> everyone knows it, the parser passes this problem // deliberately to the user -#pragma warning(disable:1572) +#pragma warning(disable : 1572) #endif #endif // include guard - - diff --git a/ext_libs/muparser/muParserInt.cpp b/ext_libs/muparser/muParserInt.cpp old mode 100755 new mode 100644 index 8b5aae60..44c3e6ed --- a/ext_libs/muparser/muParserInt.cpp +++ b/ext_libs/muparser/muParserInt.cpp @@ -1,26 +1,26 @@ /* - __________ - _____ __ __\______ \_____ _______ ______ ____ _______ + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ - |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| - \/ \/ \/ \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ Copyright (C) 2011 Ingo Berg - Permission is hereby granted, free of charge, to any person obtaining a copy of this + 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 + 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 + 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. + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "muParserInt.h" @@ -38,243 +38,299 @@ using namespace std; /** \brief Namespace for mathematical applications. */ namespace mu { -value_type ParserInt::Abs(value_type v) { return (value_type)Round(fabs((double)v)); } -value_type ParserInt::Sign(value_type v) { return (Round(v)<0) ? -1 : (Round(v)>0) ? 1 : 0; } -value_type ParserInt::Ite(value_type v1, - value_type v2, - value_type v3) { return (Round(v1)==1) ? Round(v2) : Round(v3); } -value_type ParserInt::Add(value_type v1, value_type v2) { return Round(v1) + Round(v2); } -value_type ParserInt::Sub(value_type v1, value_type v2) { return Round(v1) - Round(v2); } -value_type ParserInt::Mul(value_type v1, value_type v2) { return Round(v1) * Round(v2); } -value_type ParserInt::Div(value_type v1, value_type v2) { return Round(v1) / Round(v2); } -value_type ParserInt::Mod(value_type v1, value_type v2) { return Round(v1) % Round(v2); } -value_type ParserInt::Shr(value_type v1, value_type v2) { return Round(v1) >> Round(v2); } -value_type ParserInt::Shl(value_type v1, value_type v2) { return Round(v1) << Round(v2); } -value_type ParserInt::LogAnd(value_type v1, value_type v2) { return Round(v1) & Round(v2); } -value_type ParserInt::LogOr(value_type v1, value_type v2) { return Round(v1) | Round(v2); } -value_type ParserInt::And(value_type v1, value_type v2) { return Round(v1) && Round(v2); } -value_type ParserInt::Or(value_type v1, value_type v2) { return Round(v1) || Round(v2); } -value_type ParserInt::Less(value_type v1, value_type v2) { return Round(v1) < Round(v2); } -value_type ParserInt::Greater(value_type v1, value_type v2) { return Round(v1) > Round(v2); } -value_type ParserInt::LessEq(value_type v1, value_type v2) { return Round(v1) <= Round(v2); } -value_type ParserInt::GreaterEq(value_type v1, value_type v2) { return Round(v1) >= Round(v2); } -value_type ParserInt::Equal(value_type v1, value_type v2) { return Round(v1) == Round(v2); } -value_type ParserInt::NotEqual(value_type v1, value_type v2) { return Round(v1) != Round(v2); } -value_type ParserInt::Not(value_type v) { return !Round(v); } - -value_type ParserInt::Pow(value_type v1, value_type v2) -{ - return std::pow((double)Round(v1), (double)Round(v2)); +value_type ParserInt::Abs(value_type v) +{ + return (value_type)Round(fabs((double)v)); +} +value_type ParserInt::Sign(value_type v) +{ + return (Round(v) < 0) ? -1 : (Round(v) > 0) ? 1 : 0; +} +value_type ParserInt::Ite(value_type v1, value_type v2, value_type v3) +{ + return (Round(v1) == 1) ? Round(v2) : Round(v3); +} +value_type ParserInt::Add(value_type v1, value_type v2) +{ + return Round(v1) + Round(v2); +} +value_type ParserInt::Sub(value_type v1, value_type v2) +{ + return Round(v1) - Round(v2); +} +value_type ParserInt::Mul(value_type v1, value_type v2) +{ + return Round(v1) * Round(v2); +} +value_type ParserInt::Div(value_type v1, value_type v2) +{ + return Round(v1) / Round(v2); +} +value_type ParserInt::Mod(value_type v1, value_type v2) +{ + return Round(v1) % Round(v2); +} +value_type ParserInt::Shr(value_type v1, value_type v2) +{ + return Round(v1) >> Round(v2); +} +value_type ParserInt::Shl(value_type v1, value_type v2) +{ + return Round(v1) << Round(v2); +} +value_type ParserInt::LogAnd(value_type v1, value_type v2) +{ + return Round(v1) & Round(v2); +} +value_type ParserInt::LogOr(value_type v1, value_type v2) +{ + return Round(v1) | Round(v2); +} +value_type ParserInt::And(value_type v1, value_type v2) +{ + return Round(v1) && Round(v2); +} +value_type ParserInt::Or(value_type v1, value_type v2) +{ + return Round(v1) || Round(v2); +} +value_type ParserInt::Less(value_type v1, value_type v2) +{ + return Round(v1) < Round(v2); +} +value_type ParserInt::Greater(value_type v1, value_type v2) +{ + return Round(v1) > Round(v2); +} +value_type ParserInt::LessEq(value_type v1, value_type v2) +{ + return Round(v1) <= Round(v2); +} +value_type ParserInt::GreaterEq(value_type v1, value_type v2) +{ + return Round(v1) >= Round(v2); +} +value_type ParserInt::Equal(value_type v1, value_type v2) +{ + return Round(v1) == Round(v2); +} +value_type ParserInt::NotEqual(value_type v1, value_type v2) +{ + return Round(v1) != Round(v2); +} +value_type ParserInt::Not(value_type v) +{ + return !Round(v); +} + +value_type ParserInt::Pow(value_type v1, value_type v2) +{ + return std::pow((double)Round(v1), (double)Round(v2)); } //--------------------------------------------------------------------------- // Unary operator Callbacks: Infix operators -value_type ParserInt::UnaryMinus(value_type v) -{ - return -Round(v); +value_type ParserInt::UnaryMinus(value_type v) +{ + return -Round(v); } //--------------------------------------------------------------------------- value_type ParserInt::Sum(const value_type* a_afArg, int a_iArgc) -{ - if (!a_iArgc) - throw ParserError(_T("too few arguments for function sum.")); +{ + if (!a_iArgc) + throw ParserError(_T("too few arguments for function sum.")); - value_type fRes=0; - for (int i=0; i> iVal; + if (stream.fail()) + return 0; - stream >> iVal; - if (stream.fail()) - return 0; - - stringstream_type::pos_type iEnd = stream.tellg(); // Position after reading - if (stream.fail()) - iEnd = stream.str().length(); + stringstream_type::pos_type iEnd = stream.tellg(); // Position after reading + if (stream.fail()) + iEnd = stream.str().length(); - if (iEnd==(stringstream_type::pos_type)-1) - return 0; + if (iEnd == (stringstream_type::pos_type)-1) + return 0; - *a_iPos += (int)iEnd; - *a_fVal = (value_type)iVal; - return 1; + *a_iPos += (int)iEnd; + *a_fVal = (value_type)iVal; + return 1; } //--------------------------------------------------------------------------- -/** \brief Check a given position in the expression for the presence of - a hex value. +/** \brief Check a given position in the expression for the presence of + a hex value. \param a_szExpr Pointer to the expression string - \param [in/out] a_iPos Pointer to an integer value holding the current parsing + \param [in/out] a_iPos Pointer to an integer value holding the current parsing position in the expression. \param [out] a_fVal Pointer to the position where the detected value shall be stored. Hey values must be prefixed with "0x" in order to be detected properly. */ -int ParserInt::IsHexVal(const char_type *a_szExpr, int *a_iPos, value_type *a_fVal) +int ParserInt::IsHexVal(const char_type* a_szExpr, int* a_iPos, value_type* a_fVal) { - if (a_szExpr[1]==0 || (a_szExpr[0]!='0' || a_szExpr[1]!='x') ) - return 0; + if (a_szExpr[1] == 0 || (a_szExpr[0] != '0' || a_szExpr[1] != 'x')) + return 0; - unsigned iVal(0); + unsigned iVal(0); - // New code based on streams for UNICODE compliance: - stringstream_type::pos_type nPos(0); - stringstream_type ss(a_szExpr + 2); - ss >> std::hex >> iVal; - nPos = ss.tellg(); + // New code based on streams for UNICODE compliance: + stringstream_type::pos_type nPos(0); + stringstream_type ss(a_szExpr + 2); + ss >> std::hex >> iVal; + nPos = ss.tellg(); - if (nPos==(stringstream_type::pos_type)0) - return 1; + if (nPos == (stringstream_type::pos_type)0) + return 1; - *a_iPos += (int)(2 + nPos); - *a_fVal = (value_type)iVal; - return 1; + *a_iPos += (int)(2 + nPos); + *a_fVal = (value_type)iVal; + return 1; } //--------------------------------------------------------------------------- -int ParserInt::IsBinVal(const char_type *a_szExpr, int *a_iPos, value_type *a_fVal) +int ParserInt::IsBinVal(const char_type* a_szExpr, int* a_iPos, value_type* a_fVal) { - if (a_szExpr[0]!='#') - return 0; + if (a_szExpr[0] != '#') + return 0; - unsigned iVal(0), - iBits(sizeof(iVal)*8), - i(0); + unsigned iVal(0), iBits(sizeof(iVal) * 8), i(0); - for (i=0; (a_szExpr[i+1]=='0' || a_szExpr[i+1]=='1') && i> (iBits-i) ); - *a_iPos += i+1; + *a_fVal = (unsigned)(iVal >> (iBits - i)); + *a_iPos += i + 1; - return 1; + return 1; } //--------------------------------------------------------------------------- -/** \brief Constructor. +/** \brief Constructor. Call ParserBase class constructor and trigger Function, Operator and Constant initialization. */ -ParserInt::ParserInt() - :ParserBase() +ParserInt::ParserInt() : ParserBase() { - AddValIdent(IsVal); // lowest priority - AddValIdent(IsBinVal); - AddValIdent(IsHexVal); // highest priority + AddValIdent(IsVal); // lowest priority + AddValIdent(IsBinVal); + AddValIdent(IsHexVal); // highest priority - InitCharSets(); - InitFun(); - InitOprt(); + InitCharSets(); + InitFun(); + InitOprt(); } //--------------------------------------------------------------------------- -void ParserInt::InitConst() -{ -} +void ParserInt::InitConst() {} //--------------------------------------------------------------------------- void ParserInt::InitCharSets() { - DefineNameChars( _T("0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") ); - DefineOprtChars( _T("+-*^/?<>=!%&|~'_") ); - DefineInfixOprtChars( _T("/+-*^?<>=!%&|~'_") ); + DefineNameChars(_T("0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")); + DefineOprtChars(_T("+-*^/?<>=!%&|~'_")); + DefineInfixOprtChars(_T("/+-*^?<>=!%&|~'_")); } //--------------------------------------------------------------------------- /** \brief Initialize the default functions. */ void ParserInt::InitFun() { - DefineFun( _T("sign"), Sign); - DefineFun( _T("abs"), Abs); - DefineFun( _T("if"), Ite); - DefineFun( _T("sum"), Sum); - DefineFun( _T("min"), Min); - DefineFun( _T("max"), Max); + DefineFun(_T("sign"), Sign); + DefineFun(_T("abs"), Abs); + DefineFun(_T("if"), Ite); + DefineFun(_T("sum"), Sum); + DefineFun(_T("min"), Min); + DefineFun(_T("max"), Max); } //--------------------------------------------------------------------------- /** \brief Initialize operators. */ void ParserInt::InitOprt() { - // disable all built in operators, not all of them useful for integer numbers - // (they don't do rounding of values) - EnableBuiltInOprt(false); - - // Disable all built in operators, they wont work with integer numbers - // since they are designed for floating point numbers - DefineInfixOprt( _T("-"), UnaryMinus); - DefineInfixOprt( _T("!"), Not); - - DefineOprt( _T("&"), LogAnd, prLOGIC); - DefineOprt( _T("|"), LogOr, prLOGIC); - DefineOprt( _T("&&"), And, prLOGIC); - DefineOprt( _T("||"), Or, prLOGIC); - - DefineOprt( _T("<"), Less, prCMP); - DefineOprt( _T(">"), Greater, prCMP); - DefineOprt( _T("<="), LessEq, prCMP); - DefineOprt( _T(">="), GreaterEq, prCMP); - DefineOprt( _T("=="), Equal, prCMP); - DefineOprt( _T("!="), NotEqual, prCMP); - - DefineOprt( _T("+"), Add, prADD_SUB); - DefineOprt( _T("-"), Sub, prADD_SUB); - - DefineOprt( _T("*"), Mul, prMUL_DIV); - DefineOprt( _T("/"), Div, prMUL_DIV); - DefineOprt( _T("%"), Mod, prMUL_DIV); - - DefineOprt( _T("^"), Pow, prPOW, oaRIGHT); - DefineOprt( _T(">>"), Shr, prMUL_DIV+1); - DefineOprt( _T("<<"), Shl, prMUL_DIV+1); + // disable all built in operators, not all of them useful for integer numbers + // (they don't do rounding of values) + EnableBuiltInOprt(false); + + // Disable all built in operators, they wont work with integer numbers + // since they are designed for floating point numbers + DefineInfixOprt(_T("-"), UnaryMinus); + DefineInfixOprt(_T("!"), Not); + + DefineOprt(_T("&"), LogAnd, prLOGIC); + DefineOprt(_T("|"), LogOr, prLOGIC); + DefineOprt(_T("&&"), And, prLOGIC); + DefineOprt(_T("||"), Or, prLOGIC); + + DefineOprt(_T("<"), Less, prCMP); + DefineOprt(_T(">"), Greater, prCMP); + DefineOprt(_T("<="), LessEq, prCMP); + DefineOprt(_T(">="), GreaterEq, prCMP); + DefineOprt(_T("=="), Equal, prCMP); + DefineOprt(_T("!="), NotEqual, prCMP); + + DefineOprt(_T("+"), Add, prADD_SUB); + DefineOprt(_T("-"), Sub, prADD_SUB); + + DefineOprt(_T("*"), Mul, prMUL_DIV); + DefineOprt(_T("/"), Div, prMUL_DIV); + DefineOprt(_T("%"), Mod, prMUL_DIV); + + DefineOprt(_T("^"), Pow, prPOW, oaRIGHT); + DefineOprt(_T(">>"), Shr, prMUL_DIV + 1); + DefineOprt(_T("<<"), Shl, prMUL_DIV + 1); } } // namespace mu diff --git a/ext_libs/muparser/muParserInt.h b/ext_libs/muparser/muParserInt.h old mode 100755 new mode 100644 index 136de339..bb6176d1 --- a/ext_libs/muparser/muParserInt.h +++ b/ext_libs/muparser/muParserInt.h @@ -1,26 +1,26 @@ /* - __________ - _____ __ __\______ \_____ _______ ______ ____ _______ + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ - |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| - \/ \/ \/ \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ Copyright (C) 2004-2013 Ingo Berg - Permission is hereby granted, free of charge, to any person obtaining a copy of this + 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 + 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 + 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. + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MU_PARSER_INT_H @@ -29,100 +29,86 @@ #include "muParserBase.h" #include - /** \file \brief Definition of a parser using integer value. */ - namespace mu { - /** \brief Mathematical expressions parser. - - This version of the parser handles only integer numbers. It disables the built in operators thus it is + + This version of the parser handles only integer numbers. It disables the built in operators thus it is slower than muParser. Integer values are stored in the double value_type and converted if needed. */ class ParserInt : public ParserBase { private: - static int Round(value_type v) { return (int)(v + ((v>=0) ? 0.5 : -0.5) ); }; - - static value_type Abs(value_type); - static value_type Sign(value_type); - static value_type Ite(value_type, value_type, value_type); + static int Round(value_type v) { return (int)(v + ((v >= 0) ? 0.5 : -0.5)); }; + + static value_type Abs(value_type); + static value_type Sign(value_type); + static value_type Ite(value_type, value_type, value_type); // !! The unary Minus is a MUST, otherwise you cant use negative signs !! - static value_type UnaryMinus(value_type); + static value_type UnaryMinus(value_type); // Functions with variable number of arguments - static value_type Sum(const value_type* a_afArg, int a_iArgc); // sum - static value_type Min(const value_type* a_afArg, int a_iArgc); // minimum - static value_type Max(const value_type* a_afArg, int a_iArgc); // maximum + static value_type Sum(const value_type* a_afArg, int a_iArgc); // sum + static value_type Min(const value_type* a_afArg, int a_iArgc); // minimum + static value_type Max(const value_type* a_afArg, int a_iArgc); // maximum // binary operator callbacks - static value_type Add(value_type v1, value_type v2); - static value_type Sub(value_type v1, value_type v2); - static value_type Mul(value_type v1, value_type v2); - static value_type Div(value_type v1, value_type v2); - static value_type Mod(value_type v1, value_type v2); - static value_type Pow(value_type v1, value_type v2); - static value_type Shr(value_type v1, value_type v2); - static value_type Shl(value_type v1, value_type v2); - static value_type LogAnd(value_type v1, value_type v2); - static value_type LogOr(value_type v1, value_type v2); - static value_type And(value_type v1, value_type v2); - static value_type Or(value_type v1, value_type v2); - static value_type Xor(value_type v1, value_type v2); - static value_type Less(value_type v1, value_type v2); - static value_type Greater(value_type v1, value_type v2); - static value_type LessEq(value_type v1, value_type v2); - static value_type GreaterEq(value_type v1, value_type v2); - static value_type Equal(value_type v1, value_type v2); - static value_type NotEqual(value_type v1, value_type v2); - static value_type Not(value_type v1); - - static int IsHexVal(const char_type* a_szExpr, int *a_iPos, value_type *a_iVal); - static int IsBinVal(const char_type* a_szExpr, int *a_iPos, value_type *a_iVal); - static int IsVal (const char_type* a_szExpr, int *a_iPos, value_type *a_iVal); + static value_type Add(value_type v1, value_type v2); + static value_type Sub(value_type v1, value_type v2); + static value_type Mul(value_type v1, value_type v2); + static value_type Div(value_type v1, value_type v2); + static value_type Mod(value_type v1, value_type v2); + static value_type Pow(value_type v1, value_type v2); + static value_type Shr(value_type v1, value_type v2); + static value_type Shl(value_type v1, value_type v2); + static value_type LogAnd(value_type v1, value_type v2); + static value_type LogOr(value_type v1, value_type v2); + static value_type And(value_type v1, value_type v2); + static value_type Or(value_type v1, value_type v2); + static value_type Xor(value_type v1, value_type v2); + static value_type Less(value_type v1, value_type v2); + static value_type Greater(value_type v1, value_type v2); + static value_type LessEq(value_type v1, value_type v2); + static value_type GreaterEq(value_type v1, value_type v2); + static value_type Equal(value_type v1, value_type v2); + static value_type NotEqual(value_type v1, value_type v2); + static value_type Not(value_type v1); + + static int IsHexVal(const char_type* a_szExpr, int* a_iPos, value_type* a_iVal); + static int IsBinVal(const char_type* a_szExpr, int* a_iPos, value_type* a_iVal); + static int IsVal(const char_type* a_szExpr, int* a_iPos, value_type* a_iVal); /** \brief A facet class used to change decimal and thousands separator. */ template class change_dec_sep : public std::numpunct { public: - - explicit change_dec_sep(char_type cDecSep, char_type cThousandsSep = 0, int nGroup = 3) - :std::numpunct() - ,m_cDecPoint(cDecSep) - ,m_cThousandsSep(cThousandsSep) - ,m_nGroup(nGroup) - {} - + explicit change_dec_sep(char_type cDecSep, char_type cThousandsSep = 0, int nGroup = 3) : + std::numpunct(), m_cDecPoint(cDecSep), m_cThousandsSep(cThousandsSep), m_nGroup(nGroup) + { + } + protected: - - virtual char_type do_decimal_point() const - { - return m_cDecPoint; - } - - virtual char_type do_thousands_sep() const - { - return m_cThousandsSep; - } - - virtual std::string do_grouping() const - { - // fix for issue 4: https://code.google.com/p/muparser/issues/detail?id=4 - // courtesy of Jens Bartsch - // original code: - // return std::string(1, (char)m_nGroup); - // new code: - return std::string(1, (char)(m_cThousandsSep > 0 ? m_nGroup : CHAR_MAX)); - } + virtual char_type do_decimal_point() const { return m_cDecPoint; } - private: + virtual char_type do_thousands_sep() const { return m_cThousandsSep; } + + virtual std::string do_grouping() const + { + // fix for issue 4: https://code.google.com/p/muparser/issues/detail?id=4 + // courtesy of Jens Bartsch + // original code: + // return std::string(1, (char)m_nGroup); + // new code: + return std::string(1, (char)(m_cThousandsSep > 0 ? m_nGroup : CHAR_MAX)); + } - int m_nGroup; - char_type m_cDecPoint; - char_type m_cThousandsSep; + private: + int m_nGroup; + char_type m_cDecPoint; + char_type m_cThousandsSep; }; public: @@ -137,4 +123,3 @@ class ParserInt : public ParserBase } // namespace mu #endif - diff --git a/ext_libs/muparser/muParserStack.h b/ext_libs/muparser/muParserStack.h old mode 100755 new mode 100644 index f8437e30..ce675189 --- a/ext_libs/muparser/muParserStack.h +++ b/ext_libs/muparser/muParserStack.h @@ -1,26 +1,26 @@ /* - __________ - _____ __ __\______ \_____ _______ ______ ____ _______ + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ - |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| - \/ \/ \/ \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ Copyright (C) 2004-2011 Ingo Berg - Permission is hereby granted, free of charge, to any person obtaining a copy of this + 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 + 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 + 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. + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MU_PARSER_STACK_H @@ -34,92 +34,74 @@ #include "muParserError.h" #include "muParserToken.h" -/** \file +/** \file \brief This file defines the stack used by muparser. */ namespace mu { +/** \brief Parser stack implementation. - /** \brief Parser stack implementation. - - Stack implementation based on a std::stack. The behaviour of pop() had been - slightly changed in order to get an error code if the stack is empty. - The stack is used within the Parser both as a value stack and as an operator stack. - - \author (C) 2004-2011 Ingo Berg - */ - template - class ParserStack - { - private: - - /** \brief Type of the underlying stack implementation. */ - typedef std::stack > impl_type; - - impl_type m_Stack; ///< This is the actual stack. - - public: - - //--------------------------------------------------------------------------- - ParserStack() - :m_Stack() - {} - - //--------------------------------------------------------------------------- - virtual ~ParserStack() - {} - - //--------------------------------------------------------------------------- - /** \brief Pop a value from the stack. - - Unlike the standard implementation this function will return the value that - is going to be taken from the stack. - - \throw ParserException in case the stack is empty. - \sa pop(int &a_iErrc) - */ - TValueType pop() - { + Stack implementation based on a std::stack. The behaviour of pop() had been + slightly changed in order to get an error code if the stack is empty. + The stack is used within the Parser both as a value stack and as an operator stack. + + \author (C) 2004-2011 Ingo Berg +*/ +template +class ParserStack +{ +private: + /** \brief Type of the underlying stack implementation. */ + typedef std::stack > impl_type; + + impl_type m_Stack; ///< This is the actual stack. + +public: + //--------------------------------------------------------------------------- + ParserStack() : m_Stack() {} + + //--------------------------------------------------------------------------- + virtual ~ParserStack() {} + + //--------------------------------------------------------------------------- + /** \brief Pop a value from the stack. + + Unlike the standard implementation this function will return the value that + is going to be taken from the stack. + + \throw ParserException in case the stack is empty. + \sa pop(int &a_iErrc) + */ + TValueType pop() + { if (empty()) - throw ParserError( _T("stack is empty.") ); + throw ParserError(_T("stack is empty.")); TValueType el = top(); m_Stack.pop(); return el; - } - - /** \brief Push an object into the stack. - - \param a_Val object to push into the stack. - \throw nothrow - */ - void push(const TValueType& a_Val) - { - m_Stack.push(a_Val); - } - - /** \brief Return the number of stored elements. */ - unsigned size() const - { - return (unsigned)m_Stack.size(); - } - - /** \brief Returns true if stack is empty false otherwise. */ - bool empty() const - { - return m_Stack.empty(); - } - - /** \brief Return reference to the top object in the stack. - - The top object is the one pushed most recently. - */ - TValueType& top() - { - return m_Stack.top(); - } - }; -} // namespace MathUtils + } + + /** \brief Push an object into the stack. + + \param a_Val object to push into the stack. + \throw nothrow + */ + void push(const TValueType& a_Val) { m_Stack.push(a_Val); } + + /** \brief Return the number of stored elements. */ + unsigned size() const { return (unsigned)m_Stack.size(); } + + /** \brief Returns true if stack is empty false otherwise. */ + bool empty() const { return m_Stack.empty(); } + + /** \brief Return reference to the top object in the stack. + + The top object is the one pushed most recently. + */ + TValueType& top() { return m_Stack.top(); } +}; +} // namespace mu #endif diff --git a/ext_libs/muparser/muParserTemplateMagic.h b/ext_libs/muparser/muParserTemplateMagic.h old mode 100755 new mode 100644 index 1626caea..42dd0522 --- a/ext_libs/muparser/muParserTemplateMagic.h +++ b/ext_libs/muparser/muParserTemplateMagic.h @@ -4,110 +4,108 @@ #include #include "muParserError.h" - namespace mu { - //----------------------------------------------------------------------------------------------- - // - // Compile time type detection - // - //----------------------------------------------------------------------------------------------- - - /** \brief A class singling out integer types at compile time using - template meta programming. - */ - template - struct TypeInfo - { +//----------------------------------------------------------------------------------------------- +// +// Compile time type detection +// +//----------------------------------------------------------------------------------------------- + +/** \brief A class singling out integer types at compile time using + template meta programming. +*/ +template +struct TypeInfo +{ static bool IsInteger() { return false; } - }; - - template<> - struct TypeInfo - { - static bool IsInteger() { return true; } - }; +}; - template<> - struct TypeInfo - { - static bool IsInteger() { return true; } - }; - - template<> - struct TypeInfo - { - static bool IsInteger() { return true; } - }; - - template<> - struct TypeInfo - { - static bool IsInteger() { return true; } - }; - - template<> - struct TypeInfo - { - static bool IsInteger() { return true; } - }; +template<> +struct TypeInfo +{ + static bool IsInteger() { return true; } +}; - template<> - struct TypeInfo - { - static bool IsInteger() { return true; } - }; +template<> +struct TypeInfo +{ + static bool IsInteger() { return true; } +}; - template<> - struct TypeInfo - { - static bool IsInteger() { return true; } - }; +template<> +struct TypeInfo +{ + static bool IsInteger() { return true; } +}; - template<> - struct TypeInfo - { - static bool IsInteger() { return true; } - }; +template<> +struct TypeInfo +{ + static bool IsInteger() { return true; } +}; +template<> +struct TypeInfo +{ + static bool IsInteger() { return true; } +}; - //----------------------------------------------------------------------------------------------- - // - // Standard math functions with dummy overload for integer types - // - //----------------------------------------------------------------------------------------------- +template<> +struct TypeInfo +{ + static bool IsInteger() { return true; } +}; - /** \brief A template class for providing wrappers for essential math functions. +template<> +struct TypeInfo +{ + static bool IsInteger() { return true; } +}; - This template is spezialized for several types in order to provide a unified interface - for parser internal math function calls regardless of the data type. - */ - template - struct MathImpl - { - static T Sin(T v) { return sin(v); } - static T Cos(T v) { return cos(v); } - static T Tan(T v) { return tan(v); } - static T ASin(T v) { return asin(v); } - static T ACos(T v) { return acos(v); } - static T ATan(T v) { return atan(v); } +template<> +struct TypeInfo +{ + static bool IsInteger() { return true; } +}; + +//----------------------------------------------------------------------------------------------- +// +// Standard math functions with dummy overload for integer types +// +//----------------------------------------------------------------------------------------------- + +/** \brief A template class for providing wrappers for essential math functions. + + This template is spezialized for several types in order to provide a unified interface + for parser internal math function calls regardless of the data type. +*/ +template +struct MathImpl +{ + static T Sin(T v) { return sin(v); } + static T Cos(T v) { return cos(v); } + static T Tan(T v) { return tan(v); } + static T ASin(T v) { return asin(v); } + static T ACos(T v) { return acos(v); } + static T ATan(T v) { return atan(v); } static T ATan2(T v1, T v2) { return atan2(v1, v2); } - static T Sinh(T v) { return sinh(v); } - static T Cosh(T v) { return cosh(v); } - static T Tanh(T v) { return tanh(v); } + static T Sinh(T v) { return sinh(v); } + static T Cosh(T v) { return cosh(v); } + static T Tanh(T v) { return tanh(v); } static T ASinh(T v) { return log(v + sqrt(v * v + 1)); } static T ACosh(T v) { return log(v + sqrt(v * v - 1)); } static T ATanh(T v) { return ((T)0.5 * log((1 + v) / (1 - v))); } - static T Log(T v) { return log(v); } - static T Log2(T v) { return log(v)/log((T)2); } // Logarithm base 2 - static T Log10(T v) { return log10(v); } // Logarithm base 10 - static T Exp(T v) { return exp(v); } - static T Abs(T v) { return (v>=0) ? v : -v; } - static T Sqrt(T v) { return sqrt(v); } - static T Rint(T v) { return floor(v + (T)0.5); } - static T Sign(T v) { return (T)((v<0) ? -1 : (v>0) ? 1 : 0); } + static T Log(T v) { return log(v); } + static T Log2(T v) { return log(v) / log((T)2); } // Logarithm base 2 + static T Log10(T v) { return log10(v); } // Logarithm base 10 + static T Exp(T v) { return exp(v); } + static T Abs(T v) { return (v >= 0) ? v : -v; } + static T Sqrt(T v) { return sqrt(v); } + static T Rint(T v) { return floor(v + (T)0.5); } + static T Sign(T v) { return (T)((v < 0) ? -1 : (v > 0) ? 1 : 0); } static T Pow(T v1, T v2) { return std::pow(v1, v2); } - }; -} +}; +} // namespace mu #endif diff --git a/ext_libs/muparser/muParserTest.cpp b/ext_libs/muparser/muParserTest.cpp old mode 100755 new mode 100644 index e8dd2b7d..77050a03 --- a/ext_libs/muparser/muParserTest.cpp +++ b/ext_libs/muparser/muParserTest.cpp @@ -1,26 +1,26 @@ /* - __________ - _____ __ __\______ \_____ _______ ______ ____ _______ + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ - |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| - \/ \/ \/ \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ Copyright (C) 2013 Ingo Berg - Permission is hereby granted, free of charge, to any person obtaining a copy of this + 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 + 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 + 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. + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "muParserTest.h" @@ -30,8 +30,8 @@ #include #include -#define PARSER_CONST_PI 3.141592653589793238462643 -#define PARSER_CONST_E 2.718281828459045235360287 +#define PARSER_CONST_PI 3.141592653589793238462643 +#define PARSER_CONST_E 2.718281828459045235360287 using namespace std; @@ -41,1177 +41,1170 @@ using namespace std; namespace mu { - namespace Test - { - int ParserTester::c_iCount = 0; - - //--------------------------------------------------------------------------------------------- - ParserTester::ParserTester() - :m_vTestFun() - { - AddTest(&ParserTester::TestNames); - AddTest(&ParserTester::TestSyntax); - AddTest(&ParserTester::TestPostFix); - AddTest(&ParserTester::TestInfixOprt); - AddTest(&ParserTester::TestVarConst); - AddTest(&ParserTester::TestMultiArg); - AddTest(&ParserTester::TestExpression); - AddTest(&ParserTester::TestIfThenElse); - AddTest(&ParserTester::TestInterface); - AddTest(&ParserTester::TestBinOprt); - AddTest(&ParserTester::TestException); - AddTest(&ParserTester::TestStrArg); - AddTest(&ParserTester::TestBulkMode); - - ParserTester::c_iCount = 0; - } +namespace Test +{ +int ParserTester::c_iCount = 0; - //--------------------------------------------------------------------------------------------- - int ParserTester::IsHexVal(const char_type *a_szExpr, int *a_iPos, value_type *a_fVal) - { - if (a_szExpr[1]==0 || (a_szExpr[0]!='0' || a_szExpr[1]!='x') ) +//--------------------------------------------------------------------------------------------- +ParserTester::ParserTester() : m_vTestFun() +{ + AddTest(&ParserTester::TestNames); + AddTest(&ParserTester::TestSyntax); + AddTest(&ParserTester::TestPostFix); + AddTest(&ParserTester::TestInfixOprt); + AddTest(&ParserTester::TestVarConst); + AddTest(&ParserTester::TestMultiArg); + AddTest(&ParserTester::TestExpression); + AddTest(&ParserTester::TestIfThenElse); + AddTest(&ParserTester::TestInterface); + AddTest(&ParserTester::TestBinOprt); + AddTest(&ParserTester::TestException); + AddTest(&ParserTester::TestStrArg); + AddTest(&ParserTester::TestBulkMode); + + ParserTester::c_iCount = 0; +} + +//--------------------------------------------------------------------------------------------- +int ParserTester::IsHexVal(const char_type* a_szExpr, int* a_iPos, value_type* a_fVal) +{ + if (a_szExpr[1] == 0 || (a_szExpr[0] != '0' || a_szExpr[1] != 'x')) return 0; - unsigned iVal(0); + unsigned iVal(0); - // New code based on streams for UNICODE compliance: - stringstream_type::pos_type nPos(0); - stringstream_type ss(a_szExpr + 2); - ss >> std::hex >> iVal; - nPos = ss.tellg(); + // New code based on streams for UNICODE compliance: + stringstream_type::pos_type nPos(0); + stringstream_type ss(a_szExpr + 2); + ss >> std::hex >> iVal; + nPos = ss.tellg(); - if (nPos==(stringstream_type::pos_type)0) + if (nPos == (stringstream_type::pos_type)0) return 1; - *a_iPos += (int)(2 + nPos); - *a_fVal = (value_type)iVal; - return 1; - } + *a_iPos += (int)(2 + nPos); + *a_fVal = (value_type)iVal; + return 1; +} + +//--------------------------------------------------------------------------------------------- +int ParserTester::TestInterface() +{ + int iStat = 0; + mu::console() << _T("testing member functions..."); - //--------------------------------------------------------------------------------------------- - int ParserTester::TestInterface() + // Test RemoveVar + value_type afVal[3] = {1, 2, 3}; + Parser p; + + try { - int iStat = 0; - mu::console() << _T("testing member functions..."); - - // Test RemoveVar - value_type afVal[3] = {1,2,3}; - Parser p; - - try - { - p.DefineVar( _T("a"), &afVal[0]); - p.DefineVar( _T("b"), &afVal[1]); - p.DefineVar( _T("c"), &afVal[2]); - p.SetExpr( _T("a+b+c") ); + p.DefineVar(_T("a"), &afVal[0]); + p.DefineVar(_T("b"), &afVal[1]); + p.DefineVar(_T("c"), &afVal[2]); + p.SetExpr(_T("a+b+c")); p.Eval(); - } - catch(...) - { - iStat += 1; // this is not supposed to happen - } - - try - { - p.RemoveVar( _T("c") ); + } + catch (...) + { + iStat += 1; // this is not supposed to happen + } + + try + { + p.RemoveVar(_T("c")); p.Eval(); - iStat += 1; // not supposed to reach this, nonexisting variable "c" deleted... - } - catch(...) - { + iStat += 1; // not supposed to reach this, nonexisting variable "c" deleted... + } + catch (...) + { // failure is expected... - } + } - if (iStat==0) + if (iStat == 0) mu::console() << _T("passed") << endl; - else + else mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; - return iStat; - } + return iStat; +} - //--------------------------------------------------------------------------------------------- - int ParserTester::TestStrArg() - { - int iStat = 0; - mu::console() << _T("testing string arguments..."); - - iStat += EqnTest(_T("valueof(\"\")"), 123, true); // empty string arguments caused a crash - iStat += EqnTest(_T("valueof(\"aaa\")+valueof(\"bbb\") "), 246, true); - iStat += EqnTest(_T("2*(valueof(\"aaa\")-23)+valueof(\"bbb\")"), 323, true); - // use in expressions with variables - iStat += EqnTest(_T("a*(atof(\"10\")-b)"), 8, true); - iStat += EqnTest(_T("a-(atof(\"10\")*b)"), -19, true); - // string + numeric arguments - iStat += EqnTest(_T("strfun1(\"100\")"), 100, true); - iStat += EqnTest(_T("strfun2(\"100\",1)"), 101, true); - iStat += EqnTest(_T("strfun3(\"99\",1,2)"), 102, true); - // string constants - iStat += EqnTest(_T("atof(str1)+atof(str2)"), 3.33, true); - - if (iStat==0) +//--------------------------------------------------------------------------------------------- +int ParserTester::TestStrArg() +{ + int iStat = 0; + mu::console() << _T("testing string arguments..."); + + iStat += EqnTest(_T("valueof(\"\")"), 123, true); // empty string arguments caused a crash + iStat += EqnTest(_T("valueof(\"aaa\")+valueof(\"bbb\") "), 246, true); + iStat += EqnTest(_T("2*(valueof(\"aaa\")-23)+valueof(\"bbb\")"), 323, true); + // use in expressions with variables + iStat += EqnTest(_T("a*(atof(\"10\")-b)"), 8, true); + iStat += EqnTest(_T("a-(atof(\"10\")*b)"), -19, true); + // string + numeric arguments + iStat += EqnTest(_T("strfun1(\"100\")"), 100, true); + iStat += EqnTest(_T("strfun2(\"100\",1)"), 101, true); + iStat += EqnTest(_T("strfun3(\"99\",1,2)"), 102, true); + // string constants + iStat += EqnTest(_T("atof(str1)+atof(str2)"), 3.33, true); + + if (iStat == 0) mu::console() << _T("passed") << endl; - else + else mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; - return iStat; - } + return iStat; +} - //--------------------------------------------------------------------------------------------- - int ParserTester::TestBulkMode() - { - int iStat = 0; - mu::console() << _T("testing bulkmode..."); +//--------------------------------------------------------------------------------------------- +int ParserTester::TestBulkMode() +{ + int iStat = 0; + mu::console() << _T("testing bulkmode..."); -#define EQN_TEST_BULK(EXPR, R1, R2, R3, R4, PASS) \ - { \ - double res[] = { R1, R2, R3, R4 }; \ - iStat += EqnTestBulk(_T(EXPR), res, (PASS)); \ - } +#define EQN_TEST_BULK(EXPR, R1, R2, R3, R4, PASS) \ + { \ + double res[] = {R1, R2, R3, R4}; \ + iStat += EqnTestBulk(_T(EXPR), res, (PASS)); \ + } - // Bulk Variables for the test: - // a: 1,2,3,4 - // b: 2,2,2,2 - // c: 3,3,3,3 - // d: 5,4,3,2 - EQN_TEST_BULK("a", 1, 1, 1, 1, false) - EQN_TEST_BULK("a", 1, 2, 3, 4, true) - EQN_TEST_BULK("b=a", 1, 2, 3, 4, true) - EQN_TEST_BULK("b=a, b*10", 10, 20, 30, 40, true) - EQN_TEST_BULK("b=a, b*10, a", 1, 2, 3, 4, true) - EQN_TEST_BULK("a+b", 3, 4, 5, 6, true) - EQN_TEST_BULK("c*(a+b)", 9, 12, 15, 18, true) + // Bulk Variables for the test: + // a: 1,2,3,4 + // b: 2,2,2,2 + // c: 3,3,3,3 + // d: 5,4,3,2 + EQN_TEST_BULK("a", 1, 1, 1, 1, false) + EQN_TEST_BULK("a", 1, 2, 3, 4, true) + EQN_TEST_BULK("b=a", 1, 2, 3, 4, true) + EQN_TEST_BULK("b=a, b*10", 10, 20, 30, 40, true) + EQN_TEST_BULK("b=a, b*10, a", 1, 2, 3, 4, true) + EQN_TEST_BULK("a+b", 3, 4, 5, 6, true) + EQN_TEST_BULK("c*(a+b)", 9, 12, 15, 18, true) #undef EQN_TEST_BULK - if (iStat == 0) - mu::console() << _T("passed") << endl; - else - mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; + if (iStat == 0) + mu::console() << _T("passed") << endl; + else + mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; - return iStat; - } + return iStat; +} - //--------------------------------------------------------------------------------------------- - int ParserTester::TestBinOprt() - { - int iStat = 0; - mu::console() << _T("testing binary operators..."); - - // built in operators - // xor operator - - iStat += EqnTest(_T("a++b"), 3, true); - iStat += EqnTest(_T("a ++ b"), 3, true); - iStat += EqnTest(_T("1++2"), 3, true); - iStat += EqnTest(_T("1 ++ 2"), 3, true); - iStat += EqnTest(_T("a add b"), 3, true); - iStat += EqnTest(_T("1 add 2"), 3, true); - iStat += EqnTest(_T("aa"), 1, true); - iStat += EqnTest(_T("a>a"), 0, true); - iStat += EqnTest(_T("aa"), 0, true); - iStat += EqnTest(_T("a<=a"), 1, true); - iStat += EqnTest(_T("a<=b"), 1, true); - iStat += EqnTest(_T("b<=a"), 0, true); - iStat += EqnTest(_T("a>=a"), 1, true); - iStat += EqnTest(_T("b>=a"), 1, true); - iStat += EqnTest(_T("a>=b"), 0, true); - - // Test logical operators, especially if user defined "&" and the internal "&&" collide - iStat += EqnTest(_T("1 && 1"), 1, true); - iStat += EqnTest(_T("1 && 0"), 0, true); - iStat += EqnTest(_T("(aa)"), 1, true); - iStat += EqnTest(_T("(ab)"), 0, true); - //iStat += EqnTest(_T("12 and 255"), 12, true); - //iStat += EqnTest(_T("12 and 0"), 0, true); - iStat += EqnTest(_T("12 & 255"), 12, true); - iStat += EqnTest(_T("12 & 0"), 0, true); - iStat += EqnTest(_T("12&255"), 12, true); - iStat += EqnTest(_T("12&0"), 0, true); - - // Assignment operator - iStat += EqnTest(_T("a = b"), 2, true); - iStat += EqnTest(_T("a = sin(b)"), 0.909297, true); - iStat += EqnTest(_T("a = 1+sin(b)"), 1.909297, true); - iStat += EqnTest(_T("(a=b)*2"), 4, true); - iStat += EqnTest(_T("2*(a=b)"), 4, true); - iStat += EqnTest(_T("2*(a=b+1)"), 6, true); - iStat += EqnTest(_T("(a=b+1)*2"), 6, true); - iStat += EqnTest(_T("a=c, a*10"), 30, true); - - iStat += EqnTest(_T("2^2^3"), 256, true); - iStat += EqnTest(_T("1/2/3"), 1.0/6.0, true); - - // reference: http://www.wolframalpha.com/input/?i=3%2B4*2%2F%281-5%29^2^3 - iStat += EqnTest(_T("3+4*2/(1-5)^2^3"), 3.0001220703125, true); - - // Test user defined binary operators - iStat += EqnTestInt(_T("1 | 2"), 3, true); - iStat += EqnTestInt(_T("1 || 2"), 1, true); - iStat += EqnTestInt(_T("123 & 456"), 72, true); - iStat += EqnTestInt(_T("(123 & 456) % 10"), 2, true); - iStat += EqnTestInt(_T("1 && 0"), 0, true); - iStat += EqnTestInt(_T("123 && 456"), 1, true); - iStat += EqnTestInt(_T("1 << 3"), 8, true); - iStat += EqnTestInt(_T("8 >> 3"), 1, true); - iStat += EqnTestInt(_T("9 / 4"), 2, true); - iStat += EqnTestInt(_T("9 % 4"), 1, true); - iStat += EqnTestInt(_T("if(5%2,1,0)"), 1, true); - iStat += EqnTestInt(_T("if(4%2,1,0)"), 0, true); - iStat += EqnTestInt(_T("-10+1"), -9, true); - iStat += EqnTestInt(_T("1+2*3"), 7, true); - iStat += EqnTestInt(_T("const1 != const2"), 1, true); - iStat += EqnTestInt(_T("const1 != const2"), 0, false); - iStat += EqnTestInt(_T("const1 == const2"), 0, true); - iStat += EqnTestInt(_T("const1 == 1"), 1, true); - iStat += EqnTestInt(_T("10*(const1 == 1)"), 10, true); - iStat += EqnTestInt(_T("2*(const1 | const2)"), 6, true); - iStat += EqnTestInt(_T("2*(const1 | const2)"), 7, false); - iStat += EqnTestInt(_T("const1 < const2"), 1, true); - iStat += EqnTestInt(_T("const2 > const1"), 1, true); - iStat += EqnTestInt(_T("const1 <= 1"), 1, true); - iStat += EqnTestInt(_T("const2 >= 2"), 1, true); - iStat += EqnTestInt(_T("2*(const1 + const2)"), 6, true); - iStat += EqnTestInt(_T("2*(const1 - const2)"), -2, true); - iStat += EqnTestInt(_T("a != b"), 1, true); - iStat += EqnTestInt(_T("a != b"), 0, false); - iStat += EqnTestInt(_T("a == b"), 0, true); - iStat += EqnTestInt(_T("a == 1"), 1, true); - iStat += EqnTestInt(_T("10*(a == 1)"), 10, true); - iStat += EqnTestInt(_T("2*(a | b)"), 6, true); - iStat += EqnTestInt(_T("2*(a | b)"), 7, false); - iStat += EqnTestInt(_T("a < b"), 1, true); - iStat += EqnTestInt(_T("b > a"), 1, true); - iStat += EqnTestInt(_T("a <= 1"), 1, true); - iStat += EqnTestInt(_T("b >= 2"), 1, true); - iStat += EqnTestInt(_T("2*(a + b)"), 6, true); - iStat += EqnTestInt(_T("2*(a - b)"), -2, true); - iStat += EqnTestInt(_T("a + (a << b)"), 5, true); - iStat += EqnTestInt(_T("-2^2"), -4, true); - iStat += EqnTestInt(_T("3--a"), 4, true); - iStat += EqnTestInt(_T("3+-3^2"), -6, true); - - // Test reading of hex values: - iStat += EqnTestInt(_T("0xff"), 255, true); - iStat += EqnTestInt(_T("10+0xff"), 265, true); - iStat += EqnTestInt(_T("0xff+10"), 265, true); - iStat += EqnTestInt(_T("10*0xff"), 2550, true); - iStat += EqnTestInt(_T("0xff*10"), 2550, true); - iStat += EqnTestInt(_T("10+0xff+1"), 266, true); - iStat += EqnTestInt(_T("1+0xff+10"), 266, true); - -// incorrect: '^' is yor here, not power -// iStat += EqnTestInt("-(1+2)^2", -9, true); -// iStat += EqnTestInt("-1^3", -1, true); - - // Test precedence - // a=1, b=2, c=3 - iStat += EqnTestInt(_T("a + b * c"), 7, true); - iStat += EqnTestInt(_T("a * b + c"), 5, true); - iStat += EqnTestInt(_T("a10"), 0, true); - iStat += EqnTestInt(_T("aa"), 1, true); + iStat += EqnTest(_T("a>a"), 0, true); + iStat += EqnTest(_T("aa"), 0, true); + iStat += EqnTest(_T("a<=a"), 1, true); + iStat += EqnTest(_T("a<=b"), 1, true); + iStat += EqnTest(_T("b<=a"), 0, true); + iStat += EqnTest(_T("a>=a"), 1, true); + iStat += EqnTest(_T("b>=a"), 1, true); + iStat += EqnTest(_T("a>=b"), 0, true); + + // Test logical operators, especially if user defined "&" and the internal "&&" collide + iStat += EqnTest(_T("1 && 1"), 1, true); + iStat += EqnTest(_T("1 && 0"), 0, true); + iStat += EqnTest(_T("(aa)"), 1, true); + iStat += EqnTest(_T("(ab)"), 0, true); + // iStat += EqnTest(_T("12 and 255"), 12, true); + // iStat += EqnTest(_T("12 and 0"), 0, true); + iStat += EqnTest(_T("12 & 255"), 12, true); + iStat += EqnTest(_T("12 & 0"), 0, true); + iStat += EqnTest(_T("12&255"), 12, true); + iStat += EqnTest(_T("12&0"), 0, true); + + // Assignment operator + iStat += EqnTest(_T("a = b"), 2, true); + iStat += EqnTest(_T("a = sin(b)"), 0.909297, true); + iStat += EqnTest(_T("a = 1+sin(b)"), 1.909297, true); + iStat += EqnTest(_T("(a=b)*2"), 4, true); + iStat += EqnTest(_T("2*(a=b)"), 4, true); + iStat += EqnTest(_T("2*(a=b+1)"), 6, true); + iStat += EqnTest(_T("(a=b+1)*2"), 6, true); + iStat += EqnTest(_T("a=c, a*10"), 30, true); + + iStat += EqnTest(_T("2^2^3"), 256, true); + iStat += EqnTest(_T("1/2/3"), 1.0 / 6.0, true); + + // reference: http://www.wolframalpha.com/input/?i=3%2B4*2%2F%281-5%29^2^3 + iStat += EqnTest(_T("3+4*2/(1-5)^2^3"), 3.0001220703125, true); + + // Test user defined binary operators + iStat += EqnTestInt(_T("1 | 2"), 3, true); + iStat += EqnTestInt(_T("1 || 2"), 1, true); + iStat += EqnTestInt(_T("123 & 456"), 72, true); + iStat += EqnTestInt(_T("(123 & 456) % 10"), 2, true); + iStat += EqnTestInt(_T("1 && 0"), 0, true); + iStat += EqnTestInt(_T("123 && 456"), 1, true); + iStat += EqnTestInt(_T("1 << 3"), 8, true); + iStat += EqnTestInt(_T("8 >> 3"), 1, true); + iStat += EqnTestInt(_T("9 / 4"), 2, true); + iStat += EqnTestInt(_T("9 % 4"), 1, true); + iStat += EqnTestInt(_T("if(5%2,1,0)"), 1, true); + iStat += EqnTestInt(_T("if(4%2,1,0)"), 0, true); + iStat += EqnTestInt(_T("-10+1"), -9, true); + iStat += EqnTestInt(_T("1+2*3"), 7, true); + iStat += EqnTestInt(_T("const1 != const2"), 1, true); + iStat += EqnTestInt(_T("const1 != const2"), 0, false); + iStat += EqnTestInt(_T("const1 == const2"), 0, true); + iStat += EqnTestInt(_T("const1 == 1"), 1, true); + iStat += EqnTestInt(_T("10*(const1 == 1)"), 10, true); + iStat += EqnTestInt(_T("2*(const1 | const2)"), 6, true); + iStat += EqnTestInt(_T("2*(const1 | const2)"), 7, false); + iStat += EqnTestInt(_T("const1 < const2"), 1, true); + iStat += EqnTestInt(_T("const2 > const1"), 1, true); + iStat += EqnTestInt(_T("const1 <= 1"), 1, true); + iStat += EqnTestInt(_T("const2 >= 2"), 1, true); + iStat += EqnTestInt(_T("2*(const1 + const2)"), 6, true); + iStat += EqnTestInt(_T("2*(const1 - const2)"), -2, true); + iStat += EqnTestInt(_T("a != b"), 1, true); + iStat += EqnTestInt(_T("a != b"), 0, false); + iStat += EqnTestInt(_T("a == b"), 0, true); + iStat += EqnTestInt(_T("a == 1"), 1, true); + iStat += EqnTestInt(_T("10*(a == 1)"), 10, true); + iStat += EqnTestInt(_T("2*(a | b)"), 6, true); + iStat += EqnTestInt(_T("2*(a | b)"), 7, false); + iStat += EqnTestInt(_T("a < b"), 1, true); + iStat += EqnTestInt(_T("b > a"), 1, true); + iStat += EqnTestInt(_T("a <= 1"), 1, true); + iStat += EqnTestInt(_T("b >= 2"), 1, true); + iStat += EqnTestInt(_T("2*(a + b)"), 6, true); + iStat += EqnTestInt(_T("2*(a - b)"), -2, true); + iStat += EqnTestInt(_T("a + (a << b)"), 5, true); + iStat += EqnTestInt(_T("-2^2"), -4, true); + iStat += EqnTestInt(_T("3--a"), 4, true); + iStat += EqnTestInt(_T("3+-3^2"), -6, true); + + // Test reading of hex values: + iStat += EqnTestInt(_T("0xff"), 255, true); + iStat += EqnTestInt(_T("10+0xff"), 265, true); + iStat += EqnTestInt(_T("0xff+10"), 265, true); + iStat += EqnTestInt(_T("10*0xff"), 2550, true); + iStat += EqnTestInt(_T("0xff*10"), 2550, true); + iStat += EqnTestInt(_T("10+0xff+1"), 266, true); + iStat += EqnTestInt(_T("1+0xff+10"), 266, true); + + // incorrect: '^' is yor here, not power + // iStat += EqnTestInt("-(1+2)^2", -9, true); + // iStat += EqnTestInt("-1^3", -1, true); + + // Test precedence + // a=1, b=2, c=3 + iStat += EqnTestInt(_T("a + b * c"), 7, true); + iStat += EqnTestInt(_T("a * b + c"), 5, true); + iStat += EqnTestInt(_T("a10"), 0, true); + iStat += EqnTestInt(_T("a"), f1of1) - PARSER_THROWCHECK(PostfixOprt, true, _T("?<"), f1of1) - PARSER_THROWCHECK(PostfixOprt, true, _T("**"), f1of1) - PARSER_THROWCHECK(PostfixOprt, true, _T("xor"), f1of1) - PARSER_THROWCHECK(PostfixOprt, true, _T("and"), f1of1) - PARSER_THROWCHECK(PostfixOprt, true, _T("or"), f1of1) - PARSER_THROWCHECK(PostfixOprt, true, _T("not"), f1of1) - PARSER_THROWCHECK(PostfixOprt, true, _T("!"), f1of1) - // Binary operator - // The following must fail with builtin operators activated - // p.EnableBuiltInOp(true); -> this is the default - p.ClearPostfixOprt(); - PARSER_THROWCHECK(Oprt, false, _T("+"), f1of2) - PARSER_THROWCHECK(Oprt, false, _T("-"), f1of2) - PARSER_THROWCHECK(Oprt, false, _T("*"), f1of2) - PARSER_THROWCHECK(Oprt, false, _T("/"), f1of2) - PARSER_THROWCHECK(Oprt, false, _T("^"), f1of2) - PARSER_THROWCHECK(Oprt, false, _T("&&"), f1of2) - PARSER_THROWCHECK(Oprt, false, _T("||"), f1of2) - // without activated built in operators it should work - p.EnableBuiltInOprt(false); - PARSER_THROWCHECK(Oprt, true, _T("+"), f1of2) - PARSER_THROWCHECK(Oprt, true, _T("-"), f1of2) - PARSER_THROWCHECK(Oprt, true, _T("*"), f1of2) - PARSER_THROWCHECK(Oprt, true, _T("/"), f1of2) - PARSER_THROWCHECK(Oprt, true, _T("^"), f1of2) - PARSER_THROWCHECK(Oprt, true, _T("&&"), f1of2) - PARSER_THROWCHECK(Oprt, true, _T("||"), f1of2) - #undef PARSER_THROWCHECK - - if (iStat==0) +//--------------------------------------------------------------------------------------------- +/** \brief Check muParser name restriction enforcement. */ +int ParserTester::TestNames() +{ + int iStat = 0, iErr = 0; + + mu::console() << "testing name restriction enforcement..."; + + Parser p; + +#define PARSER_THROWCHECK(DOMAIN, FAIL, EXPR, ARG) \ + iErr = 0; \ + ParserTester::c_iCount++; \ + try \ + { \ + p.Define##DOMAIN(EXPR, ARG); \ + } \ + catch (Parser::exception_type&) \ + { \ + iErr = (FAIL == false) ? 0 : 1; \ + } \ + iStat += iErr; + + // constant names + PARSER_THROWCHECK(Const, false, _T("0a"), 1) + PARSER_THROWCHECK(Const, false, _T("9a"), 1) + PARSER_THROWCHECK(Const, false, _T("+a"), 1) + PARSER_THROWCHECK(Const, false, _T("-a"), 1) + PARSER_THROWCHECK(Const, false, _T("a-"), 1) + PARSER_THROWCHECK(Const, false, _T("a*"), 1) + PARSER_THROWCHECK(Const, false, _T("a?"), 1) + PARSER_THROWCHECK(Const, true, _T("a"), 1) + PARSER_THROWCHECK(Const, true, _T("a_min"), 1) + PARSER_THROWCHECK(Const, true, _T("a_min0"), 1) + PARSER_THROWCHECK(Const, true, _T("a_min9"), 1) + // variable names + value_type a; + p.ClearConst(); + PARSER_THROWCHECK(Var, false, _T("123abc"), &a) + PARSER_THROWCHECK(Var, false, _T("9a"), &a) + PARSER_THROWCHECK(Var, false, _T("0a"), &a) + PARSER_THROWCHECK(Var, false, _T("+a"), &a) + PARSER_THROWCHECK(Var, false, _T("-a"), &a) + PARSER_THROWCHECK(Var, false, _T("?a"), &a) + PARSER_THROWCHECK(Var, false, _T("!a"), &a) + PARSER_THROWCHECK(Var, false, _T("a+"), &a) + PARSER_THROWCHECK(Var, false, _T("a-"), &a) + PARSER_THROWCHECK(Var, false, _T("a*"), &a) + PARSER_THROWCHECK(Var, false, _T("a?"), &a) + PARSER_THROWCHECK(Var, true, _T("a"), &a) + PARSER_THROWCHECK(Var, true, _T("a_min"), &a) + PARSER_THROWCHECK(Var, true, _T("a_min0"), &a) + PARSER_THROWCHECK(Var, true, _T("a_min9"), &a) + PARSER_THROWCHECK(Var, false, _T("a_min9"), 0) + // Postfix operators + // fail + PARSER_THROWCHECK(PostfixOprt, false, _T("(k"), f1of1) + PARSER_THROWCHECK(PostfixOprt, false, _T("9+"), f1of1) + PARSER_THROWCHECK(PostfixOprt, false, _T("+"), 0) + // pass + PARSER_THROWCHECK(PostfixOprt, true, _T("-a"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("?a"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("_"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("#"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("&&"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("||"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("&"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("|"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("++"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("--"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("?>"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("?<"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("**"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("xor"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("and"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("or"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("not"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("!"), f1of1) + // Binary operator + // The following must fail with builtin operators activated + // p.EnableBuiltInOp(true); -> this is the default + p.ClearPostfixOprt(); + PARSER_THROWCHECK(Oprt, false, _T("+"), f1of2) + PARSER_THROWCHECK(Oprt, false, _T("-"), f1of2) + PARSER_THROWCHECK(Oprt, false, _T("*"), f1of2) + PARSER_THROWCHECK(Oprt, false, _T("/"), f1of2) + PARSER_THROWCHECK(Oprt, false, _T("^"), f1of2) + PARSER_THROWCHECK(Oprt, false, _T("&&"), f1of2) + PARSER_THROWCHECK(Oprt, false, _T("||"), f1of2) + // without activated built in operators it should work + p.EnableBuiltInOprt(false); + PARSER_THROWCHECK(Oprt, true, _T("+"), f1of2) + PARSER_THROWCHECK(Oprt, true, _T("-"), f1of2) + PARSER_THROWCHECK(Oprt, true, _T("*"), f1of2) + PARSER_THROWCHECK(Oprt, true, _T("/"), f1of2) + PARSER_THROWCHECK(Oprt, true, _T("^"), f1of2) + PARSER_THROWCHECK(Oprt, true, _T("&&"), f1of2) + PARSER_THROWCHECK(Oprt, true, _T("||"), f1of2) +#undef PARSER_THROWCHECK + + if (iStat == 0) mu::console() << _T("passed") << endl; - else + else mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; - return iStat; - } + return iStat; +} - //--------------------------------------------------------------------------- - int ParserTester::TestSyntax() - { - int iStat = 0; - mu::console() << _T("testing syntax engine..."); - - iStat += ThrowTest(_T("1,"), ecUNEXPECTED_EOF); // incomplete hex definition - iStat += ThrowTest(_T("a,"), ecUNEXPECTED_EOF); // incomplete hex definition - iStat += ThrowTest(_T("sin(8),"), ecUNEXPECTED_EOF); // incomplete hex definition - iStat += ThrowTest(_T("(sin(8)),"), ecUNEXPECTED_EOF); // incomplete hex definition - iStat += ThrowTest(_T("a{m},"), ecUNEXPECTED_EOF); // incomplete hex definition - - iStat += EqnTest(_T("(1+ 2*a)"), 3, true); // Spaces within formula - iStat += EqnTest(_T("sqrt((4))"), 2, true); // Multiple brackets - iStat += EqnTest(_T("sqrt((2)+2)"), 2, true);// Multiple brackets - iStat += EqnTest(_T("sqrt(2+(2))"), 2, true);// Multiple brackets - iStat += EqnTest(_T("sqrt(a+(3))"), 2, true);// Multiple brackets - iStat += EqnTest(_T("sqrt((3)+a)"), 2, true);// Multiple brackets - iStat += EqnTest(_T("order(1,2)"), 1, true); // May not cause name collision with operator "or" - iStat += EqnTest(_T("(2+"), 0, false); // missing closing bracket - iStat += EqnTest(_T("2++4"), 0, false); // unexpected operator - iStat += EqnTest(_T("2+-4"), 0, false); // unexpected operator - iStat += EqnTest(_T("(2+)"), 0, false); // unexpected closing bracket - iStat += EqnTest(_T("--2"), 0, false); // double sign - iStat += EqnTest(_T("ksdfj"), 0, false); // unknown token - iStat += EqnTest(_T("()"), 0, false); // empty bracket without a function - iStat += EqnTest(_T("5+()"), 0, false); // empty bracket without a function - iStat += EqnTest(_T("sin(cos)"), 0, false); // unexpected function - iStat += EqnTest(_T("5t6"), 0, false); // unknown token - iStat += EqnTest(_T("5 t 6"), 0, false); // unknown token - iStat += EqnTest(_T("8*"), 0, false); // unexpected end of formula - iStat += EqnTest(_T(",3"), 0, false); // unexpected comma - iStat += EqnTest(_T("3,5"), 0, false); // unexpected comma - iStat += EqnTest(_T("sin(8,8)"), 0, false); // too many function args - iStat += EqnTest(_T("(7,8)"), 0, false); // too many function args - iStat += EqnTest(_T("sin)"), 0, false); // unexpected closing bracket - iStat += EqnTest(_T("a)"), 0, false); // unexpected closing bracket - iStat += EqnTest(_T("pi)"), 0, false); // unexpected closing bracket - iStat += EqnTest(_T("sin(())"), 0, false); // unexpected closing bracket - iStat += EqnTest(_T("sin()"), 0, false); // unexpected closing bracket - - if (iStat==0) +//--------------------------------------------------------------------------- +int ParserTester::TestSyntax() +{ + int iStat = 0; + mu::console() << _T("testing syntax engine..."); + + iStat += ThrowTest(_T("1,"), ecUNEXPECTED_EOF); // incomplete hex definition + iStat += ThrowTest(_T("a,"), ecUNEXPECTED_EOF); // incomplete hex definition + iStat += ThrowTest(_T("sin(8),"), ecUNEXPECTED_EOF); // incomplete hex definition + iStat += ThrowTest(_T("(sin(8)),"), ecUNEXPECTED_EOF); // incomplete hex definition + iStat += ThrowTest(_T("a{m},"), ecUNEXPECTED_EOF); // incomplete hex definition + + iStat += EqnTest(_T("(1+ 2*a)"), 3, true); // Spaces within formula + iStat += EqnTest(_T("sqrt((4))"), 2, true); // Multiple brackets + iStat += EqnTest(_T("sqrt((2)+2)"), 2, true); // Multiple brackets + iStat += EqnTest(_T("sqrt(2+(2))"), 2, true); // Multiple brackets + iStat += EqnTest(_T("sqrt(a+(3))"), 2, true); // Multiple brackets + iStat += EqnTest(_T("sqrt((3)+a)"), 2, true); // Multiple brackets + iStat += EqnTest(_T("order(1,2)"), 1, true); // May not cause name collision with operator "or" + iStat += EqnTest(_T("(2+"), 0, false); // missing closing bracket + iStat += EqnTest(_T("2++4"), 0, false); // unexpected operator + iStat += EqnTest(_T("2+-4"), 0, false); // unexpected operator + iStat += EqnTest(_T("(2+)"), 0, false); // unexpected closing bracket + iStat += EqnTest(_T("--2"), 0, false); // double sign + iStat += EqnTest(_T("ksdfj"), 0, false); // unknown token + iStat += EqnTest(_T("()"), 0, false); // empty bracket without a function + iStat += EqnTest(_T("5+()"), 0, false); // empty bracket without a function + iStat += EqnTest(_T("sin(cos)"), 0, false); // unexpected function + iStat += EqnTest(_T("5t6"), 0, false); // unknown token + iStat += EqnTest(_T("5 t 6"), 0, false); // unknown token + iStat += EqnTest(_T("8*"), 0, false); // unexpected end of formula + iStat += EqnTest(_T(",3"), 0, false); // unexpected comma + iStat += EqnTest(_T("3,5"), 0, false); // unexpected comma + iStat += EqnTest(_T("sin(8,8)"), 0, false); // too many function args + iStat += EqnTest(_T("(7,8)"), 0, false); // too many function args + iStat += EqnTest(_T("sin)"), 0, false); // unexpected closing bracket + iStat += EqnTest(_T("a)"), 0, false); // unexpected closing bracket + iStat += EqnTest(_T("pi)"), 0, false); // unexpected closing bracket + iStat += EqnTest(_T("sin(())"), 0, false); // unexpected closing bracket + iStat += EqnTest(_T("sin()"), 0, false); // unexpected closing bracket + + if (iStat == 0) mu::console() << _T("passed") << endl; - else + else mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; - return iStat; - } + return iStat; +} - //--------------------------------------------------------------------------- - int ParserTester::TestVarConst() +//--------------------------------------------------------------------------- +int ParserTester::TestVarConst() +{ + int iStat = 0; + mu::console() << _T("testing variable/constant detection..."); + + // Test if the result changes when a variable changes + iStat += EqnTestWithVarChange(_T("a"), 1, 1, 2, 2); + iStat += EqnTestWithVarChange(_T("2*a"), 2, 4, 3, 6); + + // distinguish constants with same basename + iStat += EqnTest(_T("const"), 1, true); + iStat += EqnTest(_T("const1"), 2, true); + iStat += EqnTest(_T("const2"), 3, true); + iStat += EqnTest(_T("2*const"), 2, true); + iStat += EqnTest(_T("2*const1"), 4, true); + iStat += EqnTest(_T("2*const2"), 6, true); + iStat += EqnTest(_T("2*const+1"), 3, true); + iStat += EqnTest(_T("2*const1+1"), 5, true); + iStat += EqnTest(_T("2*const2+1"), 7, true); + iStat += EqnTest(_T("const"), 0, false); + iStat += EqnTest(_T("const1"), 0, false); + iStat += EqnTest(_T("const2"), 0, false); + + // distinguish variables with same basename + iStat += EqnTest(_T("a"), 1, true); + iStat += EqnTest(_T("aa"), 2, true); + iStat += EqnTest(_T("2*a"), 2, true); + iStat += EqnTest(_T("2*aa"), 4, true); + iStat += EqnTest(_T("2*a-1"), 1, true); + iStat += EqnTest(_T("2*aa-1"), 3, true); + + // custom value recognition + iStat += EqnTest(_T("0xff"), 255, true); + iStat += EqnTest(_T("0x97 + 0xff"), 406, true); + + // Finally test querying of used variables + try { - int iStat = 0; - mu::console() << _T("testing variable/constant detection..."); - - // Test if the result changes when a variable changes - iStat += EqnTestWithVarChange( _T("a"), 1, 1, 2, 2 ); - iStat += EqnTestWithVarChange( _T("2*a"), 2, 4, 3, 6 ); - - // distinguish constants with same basename - iStat += EqnTest( _T("const"), 1, true); - iStat += EqnTest( _T("const1"), 2, true); - iStat += EqnTest( _T("const2"), 3, true); - iStat += EqnTest( _T("2*const"), 2, true); - iStat += EqnTest( _T("2*const1"), 4, true); - iStat += EqnTest( _T("2*const2"), 6, true); - iStat += EqnTest( _T("2*const+1"), 3, true); - iStat += EqnTest( _T("2*const1+1"), 5, true); - iStat += EqnTest( _T("2*const2+1"), 7, true); - iStat += EqnTest( _T("const"), 0, false); - iStat += EqnTest( _T("const1"), 0, false); - iStat += EqnTest( _T("const2"), 0, false); - - // distinguish variables with same basename - iStat += EqnTest( _T("a"), 1, true); - iStat += EqnTest( _T("aa"), 2, true); - iStat += EqnTest( _T("2*a"), 2, true); - iStat += EqnTest( _T("2*aa"), 4, true); - iStat += EqnTest( _T("2*a-1"), 1, true); - iStat += EqnTest( _T("2*aa-1"), 3, true); - - // custom value recognition - iStat += EqnTest( _T("0xff"), 255, true); - iStat += EqnTest( _T("0x97 + 0xff"), 406, true); - - // Finally test querying of used variables - try - { int idx; mu::Parser p; - mu::value_type vVarVal[] = { 1, 2, 3, 4, 5}; - p.DefineVar( _T("a"), &vVarVal[0]); - p.DefineVar( _T("b"), &vVarVal[1]); - p.DefineVar( _T("c"), &vVarVal[2]); - p.DefineVar( _T("d"), &vVarVal[3]); - p.DefineVar( _T("e"), &vVarVal[4]); + mu::value_type vVarVal[] = {1, 2, 3, 4, 5}; + p.DefineVar(_T("a"), &vVarVal[0]); + p.DefineVar(_T("b"), &vVarVal[1]); + p.DefineVar(_T("c"), &vVarVal[2]); + p.DefineVar(_T("d"), &vVarVal[3]); + p.DefineVar(_T("e"), &vVarVal[4]); // Test lookup of defined variables // 4 used variables - p.SetExpr( _T("a+b+c+d") ); + p.SetExpr(_T("a+b+c+d")); mu::varmap_type UsedVar = p.GetUsedVar(); int iCount = (int)UsedVar.size(); - if (iCount!=4) - throw false; - - // the next check will fail if the parser + if (iCount != 4) + throw false; + + // the next check will fail if the parser // erroneously creates new variables internally - if (p.GetVar().size()!=5) - throw false; + if (p.GetVar().size() != 5) + throw false; mu::varmap_type::const_iterator item = UsedVar.begin(); - for (idx=0; item!=UsedVar.end(); ++item) + for (idx = 0; item != UsedVar.end(); ++item) { - if (&vVarVal[idx++]!=item->second) - throw false; + if (&vVarVal[idx++] != item->second) + throw false; } // Test lookup of undefined variables - p.SetExpr( _T("undef1+undef2+undef3") ); + p.SetExpr(_T("undef1+undef2+undef3")); UsedVar = p.GetUsedVar(); iCount = (int)UsedVar.size(); - if (iCount!=3) - throw false; + if (iCount != 3) + throw false; - // the next check will fail if the parser + // the next check will fail if the parser // erroneously creates new variables internally - if (p.GetVar().size()!=5) - throw false; + if (p.GetVar().size() != 5) + throw false; - for (item = UsedVar.begin(); item!=UsedVar.end(); ++item) + for (item = UsedVar.begin(); item != UsedVar.end(); ++item) { - if (item->second!=0) - throw false; // all pointers to undefined variables must be null + if (item->second != 0) + throw false; // all pointers to undefined variables must be null } // 1 used variables - p.SetExpr( _T("a+b") ); + p.SetExpr(_T("a+b")); UsedVar = p.GetUsedVar(); iCount = (int)UsedVar.size(); - if (iCount!=2) throw false; + if (iCount != 2) + throw false; item = UsedVar.begin(); - for (idx=0; item!=UsedVar.end(); ++item) - if (&vVarVal[idx++]!=item->second) throw false; - - } - catch(...) - { + for (idx = 0; item != UsedVar.end(); ++item) + if (&vVarVal[idx++] != item->second) + throw false; + } + catch (...) + { iStat += 1; - } + } - if (iStat==0) + if (iStat == 0) mu::console() << _T("passed") << endl; - else + else mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; - return iStat; - } + return iStat; +} - //--------------------------------------------------------------------------- - int ParserTester::TestMultiArg() - { - int iStat = 0; - mu::console() << _T("testing multiarg functions..."); - - // Compound expressions - iStat += EqnTest( _T("1,2,3"), 3, true); - iStat += EqnTest( _T("a,b,c"), 3, true); - iStat += EqnTest( _T("a=10,b=20,c=a*b"), 200, true); - iStat += EqnTest( _T("1,\n2,\n3"), 3, true); - iStat += EqnTest( _T("a,\nb,\nc"), 3, true); - iStat += EqnTest( _T("a=10,\nb=20,\nc=a*b"), 200, true); - iStat += EqnTest( _T("1,\r\n2,\r\n3"), 3, true); - iStat += EqnTest( _T("a,\r\nb,\r\nc"), 3, true); - iStat += EqnTest( _T("a=10,\r\nb=20,\r\nc=a*b"), 200, true); - - // picking the right argument - iStat += EqnTest( _T("f1of1(1)"), 1, true); - iStat += EqnTest( _T("f1of2(1, 2)"), 1, true); - iStat += EqnTest( _T("f2of2(1, 2)"), 2, true); - iStat += EqnTest( _T("f1of3(1, 2, 3)"), 1, true); - iStat += EqnTest( _T("f2of3(1, 2, 3)"), 2, true); - iStat += EqnTest( _T("f3of3(1, 2, 3)"), 3, true); - iStat += EqnTest( _T("f1of4(1, 2, 3, 4)"), 1, true); - iStat += EqnTest( _T("f2of4(1, 2, 3, 4)"), 2, true); - iStat += EqnTest( _T("f3of4(1, 2, 3, 4)"), 3, true); - iStat += EqnTest( _T("f4of4(1, 2, 3, 4)"), 4, true); - iStat += EqnTest( _T("f1of5(1, 2, 3, 4, 5)"), 1, true); - iStat += EqnTest( _T("f2of5(1, 2, 3, 4, 5)"), 2, true); - iStat += EqnTest( _T("f3of5(1, 2, 3, 4, 5)"), 3, true); - iStat += EqnTest( _T("f4of5(1, 2, 3, 4, 5)"), 4, true); - iStat += EqnTest( _T("f5of5(1, 2, 3, 4, 5)"), 5, true); - // Too few arguments / Too many arguments - iStat += EqnTest( _T("1+ping()"), 11, true); - iStat += EqnTest( _T("ping()+1"), 11, true); - iStat += EqnTest( _T("2*ping()"), 20, true); - iStat += EqnTest( _T("ping()*2"), 20, true); - iStat += EqnTest( _T("ping(1,2)"), 0, false); - iStat += EqnTest( _T("1+ping(1,2)"), 0, false); - iStat += EqnTest( _T("f1of1(1,2)"), 0, false); - iStat += EqnTest( _T("f1of1()"), 0, false); - iStat += EqnTest( _T("f1of2(1, 2, 3)"), 0, false); - iStat += EqnTest( _T("f1of2(1)"), 0, false); - iStat += EqnTest( _T("f1of3(1, 2, 3, 4)"), 0, false); - iStat += EqnTest( _T("f1of3(1)"), 0, false); - iStat += EqnTest( _T("f1of4(1, 2, 3, 4, 5)"), 0, false); - iStat += EqnTest( _T("f1of4(1)"), 0, false); - iStat += EqnTest( _T("(1,2,3)"), 0, false); - iStat += EqnTest( _T("1,2,3"), 0, false); - iStat += EqnTest( _T("(1*a,2,3)"), 0, false); - iStat += EqnTest( _T("1,2*a,3"), 0, false); - - // correct calculation of arguments - iStat += EqnTest( _T("min(a, 1)"), 1, true); - iStat += EqnTest( _T("min(3*2, 1)"), 1, true); - iStat += EqnTest( _T("min(3*2, 1)"), 6, false); - iStat += EqnTest( _T("firstArg(2,3,4)"), 2, true); - iStat += EqnTest( _T("lastArg(2,3,4)"), 4, true); - iStat += EqnTest( _T("min(3*a+1, 1)"), 1, true); - iStat += EqnTest( _T("max(3*a+1, 1)"), 4, true); - iStat += EqnTest( _T("max(3*a+1, 1)*2"), 8, true); - iStat += EqnTest( _T("2*max(3*a+1, 1)+2"), 10, true); - - // functions with Variable argument count - iStat += EqnTest( _T("sum(a)"), 1, true); - iStat += EqnTest( _T("sum(1,2,3)"), 6, true); - iStat += EqnTest( _T("sum(a,b,c)"), 6, true); - iStat += EqnTest( _T("sum(1,-max(1,2),3)*2"), 4, true); - iStat += EqnTest( _T("2*sum(1,2,3)"), 12, true); - iStat += EqnTest( _T("2*sum(1,2,3)+2"), 14, true); - iStat += EqnTest( _T("2*sum(-1,2,3)+2"), 10, true); - iStat += EqnTest( _T("2*sum(-1,2,-(-a))+2"), 6, true); - iStat += EqnTest( _T("2*sum(-1,10,-a)+2"), 18, true); - iStat += EqnTest( _T("2*sum(1,2,3)*2"), 24, true); - iStat += EqnTest( _T("sum(1,-max(1,2),3)*2"), 4, true); - iStat += EqnTest( _T("sum(1*3, 4, a+2)"), 10, true); - iStat += EqnTest( _T("sum(1*3, 2*sum(1,2,2), a+2)"), 16, true); - iStat += EqnTest( _T("sum(1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2)"), 24, true); - - // some failures - iStat += EqnTest( _T("sum()"), 0, false); - iStat += EqnTest( _T("sum(,)"), 0, false); - iStat += EqnTest( _T("sum(1,2,)"), 0, false); - iStat += EqnTest( _T("sum(,1,2)"), 0, false); - - if (iStat==0) +//--------------------------------------------------------------------------- +int ParserTester::TestMultiArg() +{ + int iStat = 0; + mu::console() << _T("testing multiarg functions..."); + + // Compound expressions + iStat += EqnTest(_T("1,2,3"), 3, true); + iStat += EqnTest(_T("a,b,c"), 3, true); + iStat += EqnTest(_T("a=10,b=20,c=a*b"), 200, true); + iStat += EqnTest(_T("1,\n2,\n3"), 3, true); + iStat += EqnTest(_T("a,\nb,\nc"), 3, true); + iStat += EqnTest(_T("a=10,\nb=20,\nc=a*b"), 200, true); + iStat += EqnTest(_T("1,\r\n2,\r\n3"), 3, true); + iStat += EqnTest(_T("a,\r\nb,\r\nc"), 3, true); + iStat += EqnTest(_T("a=10,\r\nb=20,\r\nc=a*b"), 200, true); + + // picking the right argument + iStat += EqnTest(_T("f1of1(1)"), 1, true); + iStat += EqnTest(_T("f1of2(1, 2)"), 1, true); + iStat += EqnTest(_T("f2of2(1, 2)"), 2, true); + iStat += EqnTest(_T("f1of3(1, 2, 3)"), 1, true); + iStat += EqnTest(_T("f2of3(1, 2, 3)"), 2, true); + iStat += EqnTest(_T("f3of3(1, 2, 3)"), 3, true); + iStat += EqnTest(_T("f1of4(1, 2, 3, 4)"), 1, true); + iStat += EqnTest(_T("f2of4(1, 2, 3, 4)"), 2, true); + iStat += EqnTest(_T("f3of4(1, 2, 3, 4)"), 3, true); + iStat += EqnTest(_T("f4of4(1, 2, 3, 4)"), 4, true); + iStat += EqnTest(_T("f1of5(1, 2, 3, 4, 5)"), 1, true); + iStat += EqnTest(_T("f2of5(1, 2, 3, 4, 5)"), 2, true); + iStat += EqnTest(_T("f3of5(1, 2, 3, 4, 5)"), 3, true); + iStat += EqnTest(_T("f4of5(1, 2, 3, 4, 5)"), 4, true); + iStat += EqnTest(_T("f5of5(1, 2, 3, 4, 5)"), 5, true); + // Too few arguments / Too many arguments + iStat += EqnTest(_T("1+ping()"), 11, true); + iStat += EqnTest(_T("ping()+1"), 11, true); + iStat += EqnTest(_T("2*ping()"), 20, true); + iStat += EqnTest(_T("ping()*2"), 20, true); + iStat += EqnTest(_T("ping(1,2)"), 0, false); + iStat += EqnTest(_T("1+ping(1,2)"), 0, false); + iStat += EqnTest(_T("f1of1(1,2)"), 0, false); + iStat += EqnTest(_T("f1of1()"), 0, false); + iStat += EqnTest(_T("f1of2(1, 2, 3)"), 0, false); + iStat += EqnTest(_T("f1of2(1)"), 0, false); + iStat += EqnTest(_T("f1of3(1, 2, 3, 4)"), 0, false); + iStat += EqnTest(_T("f1of3(1)"), 0, false); + iStat += EqnTest(_T("f1of4(1, 2, 3, 4, 5)"), 0, false); + iStat += EqnTest(_T("f1of4(1)"), 0, false); + iStat += EqnTest(_T("(1,2,3)"), 0, false); + iStat += EqnTest(_T("1,2,3"), 0, false); + iStat += EqnTest(_T("(1*a,2,3)"), 0, false); + iStat += EqnTest(_T("1,2*a,3"), 0, false); + + // correct calculation of arguments + iStat += EqnTest(_T("min(a, 1)"), 1, true); + iStat += EqnTest(_T("min(3*2, 1)"), 1, true); + iStat += EqnTest(_T("min(3*2, 1)"), 6, false); + iStat += EqnTest(_T("firstArg(2,3,4)"), 2, true); + iStat += EqnTest(_T("lastArg(2,3,4)"), 4, true); + iStat += EqnTest(_T("min(3*a+1, 1)"), 1, true); + iStat += EqnTest(_T("max(3*a+1, 1)"), 4, true); + iStat += EqnTest(_T("max(3*a+1, 1)*2"), 8, true); + iStat += EqnTest(_T("2*max(3*a+1, 1)+2"), 10, true); + + // functions with Variable argument count + iStat += EqnTest(_T("sum(a)"), 1, true); + iStat += EqnTest(_T("sum(1,2,3)"), 6, true); + iStat += EqnTest(_T("sum(a,b,c)"), 6, true); + iStat += EqnTest(_T("sum(1,-max(1,2),3)*2"), 4, true); + iStat += EqnTest(_T("2*sum(1,2,3)"), 12, true); + iStat += EqnTest(_T("2*sum(1,2,3)+2"), 14, true); + iStat += EqnTest(_T("2*sum(-1,2,3)+2"), 10, true); + iStat += EqnTest(_T("2*sum(-1,2,-(-a))+2"), 6, true); + iStat += EqnTest(_T("2*sum(-1,10,-a)+2"), 18, true); + iStat += EqnTest(_T("2*sum(1,2,3)*2"), 24, true); + iStat += EqnTest(_T("sum(1,-max(1,2),3)*2"), 4, true); + iStat += EqnTest(_T("sum(1*3, 4, a+2)"), 10, true); + iStat += EqnTest(_T("sum(1*3, 2*sum(1,2,2), a+2)"), 16, true); + iStat += EqnTest(_T("sum(1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2)"), 24, true); + + // some failures + iStat += EqnTest(_T("sum()"), 0, false); + iStat += EqnTest(_T("sum(,)"), 0, false); + iStat += EqnTest(_T("sum(1,2,)"), 0, false); + iStat += EqnTest(_T("sum(,1,2)"), 0, false); + + if (iStat == 0) mu::console() << _T("passed") << endl; - else + else mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; - - return iStat; - } + return iStat; +} - //--------------------------------------------------------------------------- - int ParserTester::TestInfixOprt() - { - int iStat(0); - mu::console() << "testing infix operators..."; - - iStat += EqnTest( _T("+1"), +1, true); - iStat += EqnTest( _T("-(+1)"), -1, true); - iStat += EqnTest( _T("-(+1)*2"), -2, true); - iStat += EqnTest( _T("-(+2)*sqrt(4)"), -4, true); - iStat += EqnTest( _T("3-+a"), 2, true); - iStat += EqnTest( _T("+1*3"), 3, true); - - iStat += EqnTest( _T("-1"), -1, true); - iStat += EqnTest( _T("-(-1)"), 1, true); - iStat += EqnTest( _T("-(-1)*2"), 2, true); - iStat += EqnTest( _T("-(-2)*sqrt(4)"), 4, true); - iStat += EqnTest( _T("-_pi"), -PARSER_CONST_PI, true); - iStat += EqnTest( _T("-a"), -1, true); - iStat += EqnTest( _T("-(a)"), -1, true); - iStat += EqnTest( _T("-(-a)"), 1, true); - iStat += EqnTest( _T("-(-a)*2"), 2, true); - iStat += EqnTest( _T("-(8)"), -8, true); - iStat += EqnTest( _T("-8"), -8, true); - iStat += EqnTest( _T("-(2+1)"), -3, true); - iStat += EqnTest( _T("-(f1of1(1+2*3)+1*2)"), -9, true); - iStat += EqnTest( _T("-(-f1of1(1+2*3)+1*2)"), 5, true); - iStat += EqnTest( _T("-sin(8)"), -0.989358, true); - iStat += EqnTest( _T("3-(-a)"), 4, true); - iStat += EqnTest( _T("3--a"), 4, true); - iStat += EqnTest( _T("-1*3"), -3, true); - - // Postfix / infix priorities - iStat += EqnTest( _T("~2#"), 8, true); - iStat += EqnTest( _T("~f1of1(2)#"), 8, true); - iStat += EqnTest( _T("~(b)#"), 8, true); - iStat += EqnTest( _T("(~b)#"), 12, true); - iStat += EqnTest( _T("~(2#)"), 8, true); - iStat += EqnTest( _T("~(f1of1(2)#)"), 8, true); - // - iStat += EqnTest( _T("-2^2"),-4, true); - iStat += EqnTest( _T("-(a+b)^2"),-9, true); - iStat += EqnTest( _T("(-3)^2"),9, true); - iStat += EqnTest( _T("-(-2^2)"),4, true); - iStat += EqnTest( _T("3+-3^2"),-6, true); - // The following assumes use of sqr as postfix operator ("§") together - // with a sign operator of low priority: - iStat += EqnTest( _T("-2'"), -4, true); - iStat += EqnTest( _T("-(1+1)'"),-4, true); - iStat += EqnTest( _T("2+-(1+1)'"),-2, true); - iStat += EqnTest( _T("2+-2'"), -2, true); - // This is the classic behaviour of the infix sign operator (here: "$") which is - // now deprecated: - iStat += EqnTest( _T("$2^2"),4, true); - iStat += EqnTest( _T("$(a+b)^2"),9, true); - iStat += EqnTest( _T("($3)^2"),9, true); - iStat += EqnTest( _T("$($2^2)"),-4, true); - iStat += EqnTest( _T("3+$3^2"),12, true); - - // infix operators sharing the first few characters - iStat += EqnTest( _T("~ 123"), 123+2, true); - iStat += EqnTest( _T("~~ 123"), 123+2, true); - - if (iStat==0) +//--------------------------------------------------------------------------- +int ParserTester::TestInfixOprt() +{ + int iStat(0); + mu::console() << "testing infix operators..."; + + iStat += EqnTest(_T("+1"), +1, true); + iStat += EqnTest(_T("-(+1)"), -1, true); + iStat += EqnTest(_T("-(+1)*2"), -2, true); + iStat += EqnTest(_T("-(+2)*sqrt(4)"), -4, true); + iStat += EqnTest(_T("3-+a"), 2, true); + iStat += EqnTest(_T("+1*3"), 3, true); + + iStat += EqnTest(_T("-1"), -1, true); + iStat += EqnTest(_T("-(-1)"), 1, true); + iStat += EqnTest(_T("-(-1)*2"), 2, true); + iStat += EqnTest(_T("-(-2)*sqrt(4)"), 4, true); + iStat += EqnTest(_T("-_pi"), -PARSER_CONST_PI, true); + iStat += EqnTest(_T("-a"), -1, true); + iStat += EqnTest(_T("-(a)"), -1, true); + iStat += EqnTest(_T("-(-a)"), 1, true); + iStat += EqnTest(_T("-(-a)*2"), 2, true); + iStat += EqnTest(_T("-(8)"), -8, true); + iStat += EqnTest(_T("-8"), -8, true); + iStat += EqnTest(_T("-(2+1)"), -3, true); + iStat += EqnTest(_T("-(f1of1(1+2*3)+1*2)"), -9, true); + iStat += EqnTest(_T("-(-f1of1(1+2*3)+1*2)"), 5, true); + iStat += EqnTest(_T("-sin(8)"), -0.989358, true); + iStat += EqnTest(_T("3-(-a)"), 4, true); + iStat += EqnTest(_T("3--a"), 4, true); + iStat += EqnTest(_T("-1*3"), -3, true); + + // Postfix / infix priorities + iStat += EqnTest(_T("~2#"), 8, true); + iStat += EqnTest(_T("~f1of1(2)#"), 8, true); + iStat += EqnTest(_T("~(b)#"), 8, true); + iStat += EqnTest(_T("(~b)#"), 12, true); + iStat += EqnTest(_T("~(2#)"), 8, true); + iStat += EqnTest(_T("~(f1of1(2)#)"), 8, true); + // + iStat += EqnTest(_T("-2^2"), -4, true); + iStat += EqnTest(_T("-(a+b)^2"), -9, true); + iStat += EqnTest(_T("(-3)^2"), 9, true); + iStat += EqnTest(_T("-(-2^2)"), 4, true); + iStat += EqnTest(_T("3+-3^2"), -6, true); + // The following assumes use of sqr as postfix operator ("§") together + // with a sign operator of low priority: + iStat += EqnTest(_T("-2'"), -4, true); + iStat += EqnTest(_T("-(1+1)'"), -4, true); + iStat += EqnTest(_T("2+-(1+1)'"), -2, true); + iStat += EqnTest(_T("2+-2'"), -2, true); + // This is the classic behaviour of the infix sign operator (here: "$") which is + // now deprecated: + iStat += EqnTest(_T("$2^2"), 4, true); + iStat += EqnTest(_T("$(a+b)^2"), 9, true); + iStat += EqnTest(_T("($3)^2"), 9, true); + iStat += EqnTest(_T("$($2^2)"), -4, true); + iStat += EqnTest(_T("3+$3^2"), 12, true); + + // infix operators sharing the first few characters + iStat += EqnTest(_T("~ 123"), 123 + 2, true); + iStat += EqnTest(_T("~~ 123"), 123 + 2, true); + + if (iStat == 0) mu::console() << _T("passed") << endl; - else + else mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; - return iStat; - } + return iStat; +} - - //--------------------------------------------------------------------------- - int ParserTester::TestPostFix() - { - int iStat = 0; - mu::console() << _T("testing postfix operators..."); - - // application - iStat += EqnTest( _T("3{m}+5"), 5.003, true); - iStat += EqnTest( _T("1000{m}"), 1, true); - iStat += EqnTest( _T("1000 {m}"), 1, true); - iStat += EqnTest( _T("(a){m}"), 1e-3, true); - iStat += EqnTest( _T("a{m}"), 1e-3, true); - iStat += EqnTest( _T("a {m}"), 1e-3, true); - iStat += EqnTest( _T("-(a){m}"), -1e-3, true); - iStat += EqnTest( _T("-2{m}"), -2e-3, true); - iStat += EqnTest( _T("-2 {m}"), -2e-3, true); - iStat += EqnTest( _T("f1of1(1000){m}"), 1, true); - iStat += EqnTest( _T("-f1of1(1000){m}"), -1, true); - iStat += EqnTest( _T("-f1of1(-1000){m}"), 1, true); - iStat += EqnTest( _T("f4of4(0,0,0,1000){m}"), 1, true); - iStat += EqnTest( _T("2+(a*1000){m}"), 3, true); - - // can postfix operators "m" und "meg" be told apart properly? - iStat += EqnTest( _T("2*3000meg+2"), 2*3e9+2, true); - - // some incorrect results - iStat += EqnTest( _T("1000{m}"), 0.1, false); - iStat += EqnTest( _T("(a){m}"), 2, false); - // failure due to syntax checking - iStat += ThrowTest(_T("0x"), ecUNASSIGNABLE_TOKEN); // incomplete hex definition - iStat += ThrowTest(_T("3+"), ecUNEXPECTED_EOF); - iStat += ThrowTest( _T("4 + {m}"), ecUNASSIGNABLE_TOKEN); - iStat += ThrowTest( _T("{m}4"), ecUNASSIGNABLE_TOKEN); - iStat += ThrowTest( _T("sin({m})"), ecUNASSIGNABLE_TOKEN); - iStat += ThrowTest( _T("{m} {m}"), ecUNASSIGNABLE_TOKEN); - iStat += ThrowTest( _T("{m}(8)"), ecUNASSIGNABLE_TOKEN); - iStat += ThrowTest( _T("4,{m}"), ecUNASSIGNABLE_TOKEN); - iStat += ThrowTest( _T("-{m}"), ecUNASSIGNABLE_TOKEN); - iStat += ThrowTest( _T("2(-{m})"), ecUNEXPECTED_PARENS); - iStat += ThrowTest( _T("2({m})"), ecUNEXPECTED_PARENS); - - iStat += ThrowTest( _T("multi*1.0"), ecUNASSIGNABLE_TOKEN); - - if (iStat==0) +//--------------------------------------------------------------------------- +int ParserTester::TestPostFix() +{ + int iStat = 0; + mu::console() << _T("testing postfix operators..."); + + // application + iStat += EqnTest(_T("3{m}+5"), 5.003, true); + iStat += EqnTest(_T("1000{m}"), 1, true); + iStat += EqnTest(_T("1000 {m}"), 1, true); + iStat += EqnTest(_T("(a){m}"), 1e-3, true); + iStat += EqnTest(_T("a{m}"), 1e-3, true); + iStat += EqnTest(_T("a {m}"), 1e-3, true); + iStat += EqnTest(_T("-(a){m}"), -1e-3, true); + iStat += EqnTest(_T("-2{m}"), -2e-3, true); + iStat += EqnTest(_T("-2 {m}"), -2e-3, true); + iStat += EqnTest(_T("f1of1(1000){m}"), 1, true); + iStat += EqnTest(_T("-f1of1(1000){m}"), -1, true); + iStat += EqnTest(_T("-f1of1(-1000){m}"), 1, true); + iStat += EqnTest(_T("f4of4(0,0,0,1000){m}"), 1, true); + iStat += EqnTest(_T("2+(a*1000){m}"), 3, true); + + // can postfix operators "m" und "meg" be told apart properly? + iStat += EqnTest(_T("2*3000meg+2"), 2 * 3e9 + 2, true); + + // some incorrect results + iStat += EqnTest(_T("1000{m}"), 0.1, false); + iStat += EqnTest(_T("(a){m}"), 2, false); + // failure due to syntax checking + iStat += ThrowTest(_T("0x"), ecUNASSIGNABLE_TOKEN); // incomplete hex definition + iStat += ThrowTest(_T("3+"), ecUNEXPECTED_EOF); + iStat += ThrowTest(_T("4 + {m}"), ecUNASSIGNABLE_TOKEN); + iStat += ThrowTest(_T("{m}4"), ecUNASSIGNABLE_TOKEN); + iStat += ThrowTest(_T("sin({m})"), ecUNASSIGNABLE_TOKEN); + iStat += ThrowTest(_T("{m} {m}"), ecUNASSIGNABLE_TOKEN); + iStat += ThrowTest(_T("{m}(8)"), ecUNASSIGNABLE_TOKEN); + iStat += ThrowTest(_T("4,{m}"), ecUNASSIGNABLE_TOKEN); + iStat += ThrowTest(_T("-{m}"), ecUNASSIGNABLE_TOKEN); + iStat += ThrowTest(_T("2(-{m})"), ecUNEXPECTED_PARENS); + iStat += ThrowTest(_T("2({m})"), ecUNEXPECTED_PARENS); + + iStat += ThrowTest(_T("multi*1.0"), ecUNASSIGNABLE_TOKEN); + + if (iStat == 0) mu::console() << _T("passed") << endl; - else + else mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; - return iStat; - } + return iStat; +} - //--------------------------------------------------------------------------- - int ParserTester::TestExpression() - { - int iStat = 0; - mu::console() << _T("testing expression samples..."); - - value_type b = 2; - - // Optimization - iStat += EqnTest( _T("2*b*5"), 20, true); - iStat += EqnTest( _T("2*b*5 + 4*b"), 28, true); - iStat += EqnTest( _T("2*a/3"), 2.0/3.0, true); - - // Addition auf cmVARMUL - iStat += EqnTest( _T("3+b"), b+3, true); - iStat += EqnTest( _T("b+3"), b+3, true); - iStat += EqnTest( _T("b*3+2"), b*3+2, true); - iStat += EqnTest( _T("3*b+2"), b*3+2, true); - iStat += EqnTest( _T("2+b*3"), b*3+2, true); - iStat += EqnTest( _T("2+3*b"), b*3+2, true); - iStat += EqnTest( _T("b+3*b"), b+3*b, true); - iStat += EqnTest( _T("3*b+b"), b+3*b, true); - - iStat += EqnTest( _T("2+b*3+b"), 2+b*3+b, true); - iStat += EqnTest( _T("b+2+b*3"), b+2+b*3, true); - - iStat += EqnTest( _T("(2*b+1)*4"), (2*b+1)*4, true); - iStat += EqnTest( _T("4*(2*b+1)"), (2*b+1)*4, true); - - // operator precedences - iStat += EqnTest( _T("1+2-3*4/5^6"), 2.99923, true); - iStat += EqnTest( _T("1^2/3*4-5+6"), 2.33333333, true); - iStat += EqnTest( _T("1+2*3"), 7, true); - iStat += EqnTest( _T("1+2*3"), 7, true); - iStat += EqnTest( _T("(1+2)*3"), 9, true); - iStat += EqnTest( _T("(1+2)*(-3)"), -9, true); - iStat += EqnTest( _T("2/4"), 0.5, true); - - iStat += EqnTest( _T("exp(ln(7))"), 7, true); - iStat += EqnTest( _T("e^ln(7)"), 7, true); - iStat += EqnTest( _T("e^(ln(7))"), 7, true); - iStat += EqnTest( _T("(e^(ln(7)))"), 7, true); - iStat += EqnTest( _T("1-(e^(ln(7)))"), -6, true); - iStat += EqnTest( _T("2*(e^(ln(7)))"), 14, true); - iStat += EqnTest( _T("10^log(5)"), pow(10.0, log(5.0)), true); - iStat += EqnTest( _T("10^log10(5)"), 5, true); - iStat += EqnTest( _T("2^log2(4)"), 4, true); - iStat += EqnTest( _T("-(sin(0)+1)"), -1, true); - iStat += EqnTest( _T("-(2^1.1)"), -2.14354692, true); - - iStat += EqnTest( _T("(cos(2.41)/b)"), -0.372056, true); - iStat += EqnTest( _T("(1*(2*(3*(4*(5*(6*(a+b)))))))"), 2160, true); - iStat += EqnTest( _T("(1*(2*(3*(4*(5*(6*(7*(a+b))))))))"), 15120, true); - iStat += EqnTest( _T("(a/((((b+(((e*(((((pi*((((3.45*((pi+a)+pi))+b)+b)*a))+0.68)+e)+a)/a))+a)+b))+b)*a)-pi))"), 0.00377999, true); - - // long formula (Reference: Matlab) - iStat += EqnTest( - _T("(((-9))-e/(((((((pi-(((-7)+(-3)/4/e))))/(((-5))-2)-((pi+(-0))*(sqrt((e+e))*(-8))*(((-pi)+(-pi)-(-9)*(6*5))") - _T("/(-e)-e))/2)/((((sqrt(2/(-e)+6)-(4-2))+((5/(-2))/(1*(-pi)+3))/8)*pi*((pi/((-2)/(-6)*1*(-1))*(-6)+(-e)))))/") - _T("((e+(-2)+(-e)*((((-3)*9+(-e)))+(-9)))))))-((((e-7+(((5/pi-(3/1+pi)))))/e)/(-5))/(sqrt((((((1+(-7))))+((((-") - _T("e)*(-e)))-8))*(-5)/((-e)))*(-6)-((((((-2)-(-9)-(-e)-1)/3))))/(sqrt((8+(e-((-6))+(9*(-9))))*(((3+2-8))*(7+6") - _T("+(-5))+((0/(-e)*(-pi))+7)))+(((((-e)/e/e)+((-6)*5)*e+(3+(-5)/pi))))+pi))/sqrt((((9))+((((pi))-8+2))+pi))/e") - _T("*4)*((-5)/(((-pi))*(sqrt(e)))))-(((((((-e)*(e)-pi))/4+(pi)*(-9)))))))+(-pi)"), -12.23016549, true); - - // long formula (Reference: Matlab) - iStat += EqnTest( - _T("(atan(sin((((((((((((((((pi/cos((a/((((0.53-b)-pi)*e)/b))))+2.51)+a)-0.54)/0.98)+b)*b)+e)/a)+b)+a)+b)+pi)/e") - _T(")+a)))*2.77)"), -2.16995656, true); - - // long formula (Reference: Matlab) - iStat += EqnTest( _T("1+2-3*4/5^6*(2*(1-5+(3*7^9)*(4+6*7-3)))+12"), -7995810.09926, true); - - if (iStat==0) - mu::console() << _T("passed") << endl; - else +//--------------------------------------------------------------------------- +int ParserTester::TestExpression() +{ + int iStat = 0; + mu::console() << _T("testing expression samples..."); + + value_type b = 2; + + // Optimization + iStat += EqnTest(_T("2*b*5"), 20, true); + iStat += EqnTest(_T("2*b*5 + 4*b"), 28, true); + iStat += EqnTest(_T("2*a/3"), 2.0 / 3.0, true); + + // Addition auf cmVARMUL + iStat += EqnTest(_T("3+b"), b + 3, true); + iStat += EqnTest(_T("b+3"), b + 3, true); + iStat += EqnTest(_T("b*3+2"), b * 3 + 2, true); + iStat += EqnTest(_T("3*b+2"), b * 3 + 2, true); + iStat += EqnTest(_T("2+b*3"), b * 3 + 2, true); + iStat += EqnTest(_T("2+3*b"), b * 3 + 2, true); + iStat += EqnTest(_T("b+3*b"), b + 3 * b, true); + iStat += EqnTest(_T("3*b+b"), b + 3 * b, true); + + iStat += EqnTest(_T("2+b*3+b"), 2 + b * 3 + b, true); + iStat += EqnTest(_T("b+2+b*3"), b + 2 + b * 3, true); + + iStat += EqnTest(_T("(2*b+1)*4"), (2 * b + 1) * 4, true); + iStat += EqnTest(_T("4*(2*b+1)"), (2 * b + 1) * 4, true); + + // operator precedences + iStat += EqnTest(_T("1+2-3*4/5^6"), 2.99923, true); + iStat += EqnTest(_T("1^2/3*4-5+6"), 2.33333333, true); + iStat += EqnTest(_T("1+2*3"), 7, true); + iStat += EqnTest(_T("1+2*3"), 7, true); + iStat += EqnTest(_T("(1+2)*3"), 9, true); + iStat += EqnTest(_T("(1+2)*(-3)"), -9, true); + iStat += EqnTest(_T("2/4"), 0.5, true); + + iStat += EqnTest(_T("exp(ln(7))"), 7, true); + iStat += EqnTest(_T("e^ln(7)"), 7, true); + iStat += EqnTest(_T("e^(ln(7))"), 7, true); + iStat += EqnTest(_T("(e^(ln(7)))"), 7, true); + iStat += EqnTest(_T("1-(e^(ln(7)))"), -6, true); + iStat += EqnTest(_T("2*(e^(ln(7)))"), 14, true); + iStat += EqnTest(_T("10^log(5)"), pow(10.0, log(5.0)), true); + iStat += EqnTest(_T("10^log10(5)"), 5, true); + iStat += EqnTest(_T("2^log2(4)"), 4, true); + iStat += EqnTest(_T("-(sin(0)+1)"), -1, true); + iStat += EqnTest(_T("-(2^1.1)"), -2.14354692, true); + + iStat += EqnTest(_T("(cos(2.41)/b)"), -0.372056, true); + iStat += EqnTest(_T("(1*(2*(3*(4*(5*(6*(a+b)))))))"), 2160, true); + iStat += EqnTest(_T("(1*(2*(3*(4*(5*(6*(7*(a+b))))))))"), 15120, true); + iStat += EqnTest(_T("(a/((((b+(((e*(((((pi*((((3.45*((pi+a)+pi))+b)+b)*a))+0.68)+e)+a)/a))+a)+b))+b)*a)-pi))"), + 0.00377999, true); + + // long formula (Reference: Matlab) + iStat += EqnTest( + _T("(((-9))-e/(((((((pi-(((-7)+(-3)/4/e))))/(((-5))-2)-((pi+(-0))*(sqrt((e+e))*(-8))*(((-pi)+(-pi)-(-9)*(6*5))") + _T("/(-e)-e))/2)/((((sqrt(2/(-e)+6)-(4-2))+((5/(-2))/(1*(-pi)+3))/8)*pi*((pi/((-2)/(-6)*1*(-1))*(-6)+(-e)))))/") + _T("((e+(-2)+(-e)*((((-3)*9+(-e)))+(-9)))))))-((((e-7+(((5/pi-(3/1+pi)))))/e)/(-5))/(sqrt((((((1+(-7))))+((((-") + _T("e)*(-e)))-8))*(-5)/((-e)))*(-6)-((((((-2)-(-9)-(-e)-1)/3))))/(sqrt((8+(e-((-6))+(9*(-9))))*(((3+2-8))*(7+6") + _T("+(-5))+((0/(-e)*(-pi))+7)))+(((((-e)/e/e)+((-6)*5)*e+(3+(-5)/pi))))+pi))/sqrt((((9))+((((pi))-8+2))+pi))/e") + _T("*4)*((-5)/(((-pi))*(sqrt(e)))))-(((((((-e)*(e)-pi))/4+(pi)*(-9)))))))+(-pi)"), + -12.23016549, true); + + // long formula (Reference: Matlab) + iStat += EqnTest( + _T("(atan(sin((((((((((((((((pi/cos((a/((((0.53-b)-pi)*e)/b))))+2.51)+a)-0.54)/0.98)+b)*b)+e)/a)+b)+a)+b)+pi)/e") + _T(")+a)))*2.77)"), + -2.16995656, true); + + // long formula (Reference: Matlab) + iStat += EqnTest(_T("1+2-3*4/5^6*(2*(1-5+(3*7^9)*(4+6*7-3)))+12"), -7995810.09926, true); + + if (iStat == 0) + mu::console() << _T("passed") << endl; + else mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; - return iStat; - } - - + return iStat; +} - //--------------------------------------------------------------------------- - int ParserTester::TestIfThenElse() - { - int iStat = 0; - mu::console() << _T("testing if-then-else operator..."); - - // Test error detection - iStat += ThrowTest(_T(":3"), ecUNEXPECTED_CONDITIONAL); - iStat += ThrowTest(_T("? 1 : 2"), ecUNEXPECTED_CONDITIONAL); - iStat += ThrowTest(_T("(ab) ? 10 : 11"), 11, true); - iStat += EqnTest(_T("(ab) ? c : d"), -2, true); - - iStat += EqnTest(_T("(a>b) ? 1 : 0"), 0, true); - iStat += EqnTest(_T("((a>b) ? 1 : 0) ? 1 : 2"), 2, true); - iStat += EqnTest(_T("((a>b) ? 1 : 0) ? 1 : sum((a>b) ? 1 : 2)"), 2, true); - iStat += EqnTest(_T("((a>b) ? 0 : 1) ? 1 : sum((a>b) ? 1 : 2)"), 1, true); - - iStat += EqnTest(_T("sum((a>b) ? 1 : 2)"), 2, true); - iStat += EqnTest(_T("sum((1) ? 1 : 2)"), 1, true); - iStat += EqnTest(_T("sum((a>b) ? 1 : 2, 100)"), 102, true); - iStat += EqnTest(_T("sum((1) ? 1 : 2, 100)"), 101, true); - iStat += EqnTest(_T("sum(3, (a>b) ? 3 : 10)"), 13, true); - iStat += EqnTest(_T("sum(3, (ab) ? 3 : 10)"), 130, true); - iStat += EqnTest(_T("10*sum(3, (ab) ? 3 : 10)*10"), 130, true); - iStat += EqnTest(_T("sum(3, (ab) ? sum(3, (ab) ? sum(3, (ab) ? sum(3, (ab)&&(a2)&&(1<2) ? 128 : 255"), 255, true); - iStat += EqnTest(_T("((1<2)&&(1<2)) ? 128 : 255"), 128, true); - iStat += EqnTest(_T("((1>2)&&(1<2)) ? 128 : 255"), 255, true); - iStat += EqnTest(_T("((ab)&&(a0 ? 1>2 ? 128 : 255 : 1>0 ? 32 : 64"), 255, true); - iStat += EqnTest(_T("1>0 ? 1>2 ? 128 : 255 :(1>0 ? 32 : 64)"), 255, true); - iStat += EqnTest(_T("1>0 ? 1>0 ? 128 : 255 : 1>2 ? 32 : 64"), 128, true); - iStat += EqnTest(_T("1>0 ? 1>0 ? 128 : 255 :(1>2 ? 32 : 64)"), 128, true); - iStat += EqnTest(_T("1>2 ? 1>2 ? 128 : 255 : 1>0 ? 32 : 64"), 32, true); - iStat += EqnTest(_T("1>2 ? 1>0 ? 128 : 255 : 1>2 ? 32 : 64"), 64, true); - iStat += EqnTest(_T("1>0 ? 50 : 1>0 ? 128 : 255"), 50, true); - iStat += EqnTest(_T("1>0 ? 50 : (1>0 ? 128 : 255)"), 50, true); - iStat += EqnTest(_T("1>0 ? 1>0 ? 128 : 255 : 50"), 128, true); - iStat += EqnTest(_T("1>2 ? 1>2 ? 128 : 255 : 1>0 ? 32 : 1>2 ? 64 : 16"), 32, true); - iStat += EqnTest(_T("1>2 ? 1>2 ? 128 : 255 : 1>0 ? 32 :(1>2 ? 64 : 16)"), 32, true); - iStat += EqnTest(_T("1>0 ? 1>2 ? 128 : 255 : 1>0 ? 32 :1>2 ? 64 : 16"), 255, true); - iStat += EqnTest(_T("1>0 ? 1>2 ? 128 : 255 : (1>0 ? 32 :1>2 ? 64 : 16)"), 255, true); - iStat += EqnTest(_T("1 ? 0 ? 128 : 255 : 1 ? 32 : 64"), 255, true); - - // assignment operators - iStat += EqnTest(_T("a= 0 ? 128 : 255, a"), 255, true); - iStat += EqnTest(_T("a=((a>b)&&(ab) ? 10 : 11"), 11, true); + iStat += EqnTest(_T("(ab) ? c : d"), -2, true); + + iStat += EqnTest(_T("(a>b) ? 1 : 0"), 0, true); + iStat += EqnTest(_T("((a>b) ? 1 : 0) ? 1 : 2"), 2, true); + iStat += EqnTest(_T("((a>b) ? 1 : 0) ? 1 : sum((a>b) ? 1 : 2)"), 2, true); + iStat += EqnTest(_T("((a>b) ? 0 : 1) ? 1 : sum((a>b) ? 1 : 2)"), 1, true); + + iStat += EqnTest(_T("sum((a>b) ? 1 : 2)"), 2, true); + iStat += EqnTest(_T("sum((1) ? 1 : 2)"), 1, true); + iStat += EqnTest(_T("sum((a>b) ? 1 : 2, 100)"), 102, true); + iStat += EqnTest(_T("sum((1) ? 1 : 2, 100)"), 101, true); + iStat += EqnTest(_T("sum(3, (a>b) ? 3 : 10)"), 13, true); + iStat += EqnTest(_T("sum(3, (ab) ? 3 : 10)"), 130, true); + iStat += EqnTest(_T("10*sum(3, (ab) ? 3 : 10)*10"), 130, true); + iStat += EqnTest(_T("sum(3, (ab) ? sum(3, (ab) ? sum(3, (ab) ? sum(3, (ab)&&(a2)&&(1<2) ? 128 : 255"), 255, true); + iStat += EqnTest(_T("((1<2)&&(1<2)) ? 128 : 255"), 128, true); + iStat += EqnTest(_T("((1>2)&&(1<2)) ? 128 : 255"), 255, true); + iStat += EqnTest(_T("((ab)&&(a0 ? 1>2 ? 128 : 255 : 1>0 ? 32 : 64"), 255, true); + iStat += EqnTest(_T("1>0 ? 1>2 ? 128 : 255 :(1>0 ? 32 : 64)"), 255, true); + iStat += EqnTest(_T("1>0 ? 1>0 ? 128 : 255 : 1>2 ? 32 : 64"), 128, true); + iStat += EqnTest(_T("1>0 ? 1>0 ? 128 : 255 :(1>2 ? 32 : 64)"), 128, true); + iStat += EqnTest(_T("1>2 ? 1>2 ? 128 : 255 : 1>0 ? 32 : 64"), 32, true); + iStat += EqnTest(_T("1>2 ? 1>0 ? 128 : 255 : 1>2 ? 32 : 64"), 64, true); + iStat += EqnTest(_T("1>0 ? 50 : 1>0 ? 128 : 255"), 50, true); + iStat += EqnTest(_T("1>0 ? 50 : (1>0 ? 128 : 255)"), 50, true); + iStat += EqnTest(_T("1>0 ? 1>0 ? 128 : 255 : 50"), 128, true); + iStat += EqnTest(_T("1>2 ? 1>2 ? 128 : 255 : 1>0 ? 32 : 1>2 ? 64 : 16"), 32, true); + iStat += EqnTest(_T("1>2 ? 1>2 ? 128 : 255 : 1>0 ? 32 :(1>2 ? 64 : 16)"), 32, true); + iStat += EqnTest(_T("1>0 ? 1>2 ? 128 : 255 : 1>0 ? 32 :1>2 ? 64 : 16"), 255, true); + iStat += EqnTest(_T("1>0 ? 1>2 ? 128 : 255 : (1>0 ? 32 :1>2 ? 64 : 16)"), 255, true); + iStat += EqnTest(_T("1 ? 0 ? 128 : 255 : 1 ? 32 : 64"), 255, true); + + // assignment operators + iStat += EqnTest(_T("a= 0 ? 128 : 255, a"), 255, true); + iStat += EqnTest(_T("a=((a>b)&&(a - // this is now legal, for reference see: - // https://sourceforge.net/forum/message.php?msg_id=7411373 - // iStat += ThrowTest( _T("sin=9"), ecUNEXPECTED_OPERATOR); - //
- - iStat += ThrowTest( _T("(8)=5"), ecUNEXPECTED_OPERATOR); - iStat += ThrowTest( _T("(a)=5"), ecUNEXPECTED_OPERATOR); - iStat += ThrowTest( _T("a=\"tttt\""), ecOPRT_TYPE_CONFLICT); - - if (iStat==0) + // functions without parameter + iStat += ThrowTest(_T("3+ping(2)"), ecTOO_MANY_PARAMS); + iStat += ThrowTest(_T("3+ping(a+2)"), ecTOO_MANY_PARAMS); + iStat += ThrowTest(_T("3+ping(sin(a)+2)"), ecTOO_MANY_PARAMS); + iStat += ThrowTest(_T("3+ping(1+sin(a))"), ecTOO_MANY_PARAMS); + + // String function related + iStat += ThrowTest(_T("valueof(\"xxx\")"), 999, false); + iStat += ThrowTest(_T("valueof()"), ecUNEXPECTED_PARENS); + iStat += ThrowTest(_T("1+valueof(\"abc\""), ecMISSING_PARENS); + iStat += ThrowTest(_T("valueof(\"abc\""), ecMISSING_PARENS); + iStat += ThrowTest(_T("valueof(\"abc"), ecUNTERMINATED_STRING); + iStat += ThrowTest(_T("valueof(\"abc\",3)"), ecTOO_MANY_PARAMS); + iStat += ThrowTest(_T("valueof(3)"), ecSTRING_EXPECTED); + iStat += ThrowTest(_T("sin(\"abc\")"), ecVAL_EXPECTED); + iStat += ThrowTest(_T("valueof(\"\\\"abc\\\"\")"), 999, false); + iStat += ThrowTest(_T("\"hello world\""), ecSTR_RESULT); + iStat += ThrowTest(_T("(\"hello world\")"), ecSTR_RESULT); + iStat += ThrowTest(_T("\"abcd\"+100"), ecOPRT_TYPE_CONFLICT); + iStat += ThrowTest(_T("\"a\"+\"b\""), ecOPRT_TYPE_CONFLICT); + iStat += ThrowTest(_T("strfun1(\"100\",3)"), ecTOO_MANY_PARAMS); + iStat += ThrowTest(_T("strfun2(\"100\",3,5)"), ecTOO_MANY_PARAMS); + iStat += ThrowTest(_T("strfun3(\"100\",3,5,6)"), ecTOO_MANY_PARAMS); + iStat += ThrowTest(_T("strfun2(\"100\")"), ecTOO_FEW_PARAMS); + iStat += ThrowTest(_T("strfun3(\"100\",6)"), ecTOO_FEW_PARAMS); + iStat += ThrowTest(_T("strfun2(1,1)"), ecSTRING_EXPECTED); + iStat += ThrowTest(_T("strfun2(a,1)"), ecSTRING_EXPECTED); + iStat += ThrowTest(_T("strfun2(1,1,1)"), ecTOO_MANY_PARAMS); + iStat += ThrowTest(_T("strfun2(a,1,1)"), ecTOO_MANY_PARAMS); + iStat += ThrowTest(_T("strfun3(1,2,3)"), ecSTRING_EXPECTED); + iStat += ThrowTest(_T("strfun3(1, \"100\",3)"), ecSTRING_EXPECTED); + iStat += ThrowTest(_T("strfun3(\"1\", \"100\",3)"), ecVAL_EXPECTED); + iStat += ThrowTest(_T("strfun3(\"1\", 3, \"100\")"), ecVAL_EXPECTED); + iStat += ThrowTest(_T("strfun3(\"1\", \"100\", \"100\", \"100\")"), ecTOO_MANY_PARAMS); + + // assignment operator + iStat += ThrowTest(_T("3=4"), ecUNEXPECTED_OPERATOR); + iStat += ThrowTest(_T("sin(8)=4"), ecUNEXPECTED_OPERATOR); + iStat += ThrowTest(_T("\"test\"=a"), ecUNEXPECTED_OPERATOR); + + // + // this is now legal, for reference see: + // https://sourceforge.net/forum/message.php?msg_id=7411373 + // iStat += ThrowTest( _T("sin=9"), ecUNEXPECTED_OPERATOR); + // + + iStat += ThrowTest(_T("(8)=5"), ecUNEXPECTED_OPERATOR); + iStat += ThrowTest(_T("(a)=5"), ecUNEXPECTED_OPERATOR); + iStat += ThrowTest(_T("a=\"tttt\""), ecOPRT_TYPE_CONFLICT); + + if (iStat == 0) mu::console() << _T("passed") << endl; - else + else mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; - return iStat; - } + return iStat; +} +//--------------------------------------------------------------------------- +void ParserTester::AddTest(testfun_type a_pFun) +{ + m_vTestFun.push_back(a_pFun); +} - //--------------------------------------------------------------------------- - void ParserTester::AddTest(testfun_type a_pFun) +//--------------------------------------------------------------------------- +void ParserTester::Run() +{ + int iStat = 0; + try { - m_vTestFun.push_back(a_pFun); + for (int i = 0; i < (int)m_vTestFun.size(); ++i) + iStat += (this->*m_vTestFun[i])(); } - - //--------------------------------------------------------------------------- - void ParserTester::Run() + catch (Parser::exception_type& e) { - int iStat = 0; - try - { - for (int i=0; i<(int)m_vTestFun.size(); ++i) - iStat += (this->*m_vTestFun[i])(); - } - catch(Parser::exception_type &e) - { mu::console() << "\n" << e.GetMsg() << endl; mu::console() << e.GetToken() << endl; Abort(); - } - catch(std::exception &e) - { + } + catch (std::exception& e) + { mu::console() << e.what() << endl; Abort(); - } - catch(...) - { + } + catch (...) + { mu::console() << "Internal error"; Abort(); - } - - if (iStat==0) - { - mu::console() << "Test passed (" << ParserTester::c_iCount << " expressions)" << endl; - } - else - { - mu::console() << "Test failed with " << iStat - << " errors (" << ParserTester::c_iCount - << " expressions)" << endl; - } - ParserTester::c_iCount = 0; } - - //--------------------------------------------------------------------------- - int ParserTester::ThrowTest(const string_type &a_str, int a_iErrc, bool a_bFail) + if (iStat == 0) { - ParserTester::c_iCount++; + mu::console() << "Test passed (" << ParserTester::c_iCount << " expressions)" << endl; + } + else + { + mu::console() << "Test failed with " << iStat << " errors (" << ParserTester::c_iCount << " expressions)" + << endl; + } + ParserTester::c_iCount = 0; +} + +//--------------------------------------------------------------------------- +int ParserTester::ThrowTest(const string_type& a_str, int a_iErrc, bool a_bFail) +{ + ParserTester::c_iCount++; - try - { - value_type fVal[] = {1,1,1}; + try + { + value_type fVal[] = {1, 1, 1}; Parser p; - p.DefineVar( _T("a"), &fVal[0]); - p.DefineVar( _T("b"), &fVal[1]); - p.DefineVar( _T("c"), &fVal[2]); - p.DefinePostfixOprt( _T("{m}"), Milli); - p.DefinePostfixOprt( _T("m"), Milli); - p.DefineFun( _T("ping"), Ping); - p.DefineFun( _T("valueof"), ValueOf); - p.DefineFun( _T("strfun1"), StrFun1); - p.DefineFun( _T("strfun2"), StrFun2); - p.DefineFun( _T("strfun3"), StrFun3); + p.DefineVar(_T("a"), &fVal[0]); + p.DefineVar(_T("b"), &fVal[1]); + p.DefineVar(_T("c"), &fVal[2]); + p.DefinePostfixOprt(_T("{m}"), Milli); + p.DefinePostfixOprt(_T("m"), Milli); + p.DefineFun(_T("ping"), Ping); + p.DefineFun(_T("valueof"), ValueOf); + p.DefineFun(_T("strfun1"), StrFun1); + p.DefineFun(_T("strfun2"), StrFun2); + p.DefineFun(_T("strfun3"), StrFun3); p.SetExpr(a_str); p.Eval(); - } - catch(ParserError &e) - { + } + catch (ParserError& e) + { // output the formula in case of an failed test - if (a_bFail==false || (a_bFail==true && a_iErrc!=e.GetCode()) ) + if (a_bFail == false || (a_bFail == true && a_iErrc != e.GetCode())) { - mu::console() << _T("\n ") - << _T("Expression: ") << a_str - << _T(" Code:") << e.GetCode() << _T("(") << e.GetMsg() << _T(")") - << _T(" Expected:") << a_iErrc; + mu::console() << _T("\n ") + << _T("Expression: ") << a_str << _T(" Code:") << e.GetCode() << _T("(") << e.GetMsg() + << _T(")") + << _T(" Expected:") << a_iErrc; } - return (a_iErrc==e.GetCode()) ? 0 : 1; - } - - // if a_bFail==false no exception is expected - bool bRet((a_bFail==false) ? 0 : 1); - if (bRet==1) - { - mu::console() << _T("\n ") - << _T("Expression: ") << a_str - << _T(" did evaluate; Expected error:") << a_iErrc; - } + return (a_iErrc == e.GetCode()) ? 0 : 1; + } - return bRet; + // if a_bFail==false no exception is expected + bool bRet((a_bFail == false) ? 0 : 1); + if (bRet == 1) + { + mu::console() << _T("\n ") + << _T("Expression: ") << a_str << _T(" did evaluate; Expected error:") << a_iErrc; } - //--------------------------------------------------------------------------- - /** \brief Evaluate a tet expression. + return bRet; +} + +//--------------------------------------------------------------------------- +/** \brief Evaluate a tet expression. + + \return 1 in case of a failure, 0 otherwise. +*/ +int ParserTester::EqnTestWithVarChange(const string_type& a_str, + double a_fVar1, + double a_fRes1, + double a_fVar2, + double a_fRes2) +{ + ParserTester::c_iCount++; - \return 1 in case of a failure, 0 otherwise. - */ - int ParserTester::EqnTestWithVarChange(const string_type &a_str, - double a_fVar1, - double a_fRes1, - double a_fVar2, - double a_fRes2) + try { - ParserTester::c_iCount++; + value_type fVal[2] = {-999, -999}; // should be equal - try - { - value_type fVal[2] = {-999, -999 }; // should be equal - - Parser p; + Parser p; value_type var = 0; // variable - p.DefineVar( _T("a"), &var); + p.DefineVar(_T("a"), &var); p.SetExpr(a_str); var = a_fVar1; @@ -1219,334 +1212,329 @@ namespace mu var = a_fVar2; fVal[1] = p.Eval(); - - if ( fabs(a_fRes1-fVal[0]) > 0.0000000001) - throw std::runtime_error("incorrect result (first pass)"); - - if ( fabs(a_fRes2-fVal[1]) > 0.0000000001) - throw std::runtime_error("incorrect result (second pass)"); - } - catch(Parser::exception_type &e) - { + + if (fabs(a_fRes1 - fVal[0]) > 0.0000000001) + throw std::runtime_error("incorrect result (first pass)"); + + if (fabs(a_fRes2 - fVal[1]) > 0.0000000001) + throw std::runtime_error("incorrect result (second pass)"); + } + catch (Parser::exception_type& e) + { mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (") << e.GetMsg() << _T(")"); return 1; - } - catch(std::exception &e) - { + } + catch (std::exception& e) + { mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (") << e.what() << _T(")"); - return 1; // always return a failure since this exception is not expected - } - catch(...) - { - mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (unexpected exception)"); - return 1; // exceptions other than ParserException are not allowed - } - - return 0; + return 1; // always return a failure since this exception is not expected + } + catch (...) + { + mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (unexpected exception)"); + return 1; // exceptions other than ParserException are not allowed } - //--------------------------------------------------------------------------- - /** \brief Evaluate a tet expression. + return 0; +} - \return 1 in case of a failure, 0 otherwise. - */ - int ParserTester::EqnTest(const string_type &a_str, double a_fRes, bool a_fPass) - { - ParserTester::c_iCount++; - int iRet(0); - value_type fVal[5] = {-999, -998, -997, -996, -995}; // initially should be different +//--------------------------------------------------------------------------- +/** \brief Evaluate a tet expression. - try - { + \return 1 in case of a failure, 0 otherwise. +*/ +int ParserTester::EqnTest(const string_type& a_str, double a_fRes, bool a_fPass) +{ + ParserTester::c_iCount++; + int iRet(0); + value_type fVal[5] = {-999, -998, -997, -996, -995}; // initially should be different + + try + { std::auto_ptr p1; - Parser p2, p3; // three parser objects - // they will be used for testing copy and assignment operators + Parser p2, p3; // three parser objects + // they will be used for testing copy and assignment operators // p1 is a pointer since i'm going to delete it in order to test if // parsers after copy construction still refer to members of it. // !! If this is the case this function will crash !! - - p1.reset(new mu::Parser()); + + p1.reset(new mu::Parser()); // Add constants - p1->DefineConst( _T("pi"), (value_type)PARSER_CONST_PI); - p1->DefineConst( _T("e"), (value_type)PARSER_CONST_E); - p1->DefineConst( _T("const"), 1); - p1->DefineConst( _T("const1"), 2); - p1->DefineConst( _T("const2"), 3); + p1->DefineConst(_T("pi"), (value_type)PARSER_CONST_PI); + p1->DefineConst(_T("e"), (value_type)PARSER_CONST_E); + p1->DefineConst(_T("const"), 1); + p1->DefineConst(_T("const1"), 2); + p1->DefineConst(_T("const2"), 3); // string constants - p1->DefineStrConst( _T("str1"), _T("1.11")); - p1->DefineStrConst( _T("str2"), _T("2.22")); + p1->DefineStrConst(_T("str1"), _T("1.11")); + p1->DefineStrConst(_T("str2"), _T("2.22")); // variables - value_type vVarVal[] = { 1, 2, 3, -2}; - p1->DefineVar( _T("a"), &vVarVal[0]); - p1->DefineVar( _T("aa"), &vVarVal[1]); - p1->DefineVar( _T("b"), &vVarVal[1]); - p1->DefineVar( _T("c"), &vVarVal[2]); - p1->DefineVar( _T("d"), &vVarVal[3]); - + value_type vVarVal[] = {1, 2, 3, -2}; + p1->DefineVar(_T("a"), &vVarVal[0]); + p1->DefineVar(_T("aa"), &vVarVal[1]); + p1->DefineVar(_T("b"), &vVarVal[1]); + p1->DefineVar(_T("c"), &vVarVal[2]); + p1->DefineVar(_T("d"), &vVarVal[3]); + // custom value ident functions - p1->AddValIdent(&ParserTester::IsHexVal); + p1->AddValIdent(&ParserTester::IsHexVal); // functions - p1->DefineFun( _T("ping"), Ping); - p1->DefineFun( _T("f1of1"), f1of1); // one parameter - p1->DefineFun( _T("f1of2"), f1of2); // two parameter - p1->DefineFun( _T("f2of2"), f2of2); - p1->DefineFun( _T("f1of3"), f1of3); // three parameter - p1->DefineFun( _T("f2of3"), f2of3); - p1->DefineFun( _T("f3of3"), f3of3); - p1->DefineFun( _T("f1of4"), f1of4); // four parameter - p1->DefineFun( _T("f2of4"), f2of4); - p1->DefineFun( _T("f3of4"), f3of4); - p1->DefineFun( _T("f4of4"), f4of4); - p1->DefineFun( _T("f1of5"), f1of5); // five parameter - p1->DefineFun( _T("f2of5"), f2of5); - p1->DefineFun( _T("f3of5"), f3of5); - p1->DefineFun( _T("f4of5"), f4of5); - p1->DefineFun( _T("f5of5"), f5of5); + p1->DefineFun(_T("ping"), Ping); + p1->DefineFun(_T("f1of1"), f1of1); // one parameter + p1->DefineFun(_T("f1of2"), f1of2); // two parameter + p1->DefineFun(_T("f2of2"), f2of2); + p1->DefineFun(_T("f1of3"), f1of3); // three parameter + p1->DefineFun(_T("f2of3"), f2of3); + p1->DefineFun(_T("f3of3"), f3of3); + p1->DefineFun(_T("f1of4"), f1of4); // four parameter + p1->DefineFun(_T("f2of4"), f2of4); + p1->DefineFun(_T("f3of4"), f3of4); + p1->DefineFun(_T("f4of4"), f4of4); + p1->DefineFun(_T("f1of5"), f1of5); // five parameter + p1->DefineFun(_T("f2of5"), f2of5); + p1->DefineFun(_T("f3of5"), f3of5); + p1->DefineFun(_T("f4of5"), f4of5); + p1->DefineFun(_T("f5of5"), f5of5); // binary operators - p1->DefineOprt( _T("add"), add, 0); - p1->DefineOprt( _T("++"), add, 0); - p1->DefineOprt( _T("&"), land, prLAND); + p1->DefineOprt(_T("add"), add, 0); + p1->DefineOprt(_T("++"), add, 0); + p1->DefineOprt(_T("&"), land, prLAND); // sample functions - p1->DefineFun( _T("min"), Min); - p1->DefineFun( _T("max"), Max); - p1->DefineFun( _T("sum"), Sum); - p1->DefineFun( _T("valueof"), ValueOf); - p1->DefineFun( _T("atof"), StrToFloat); - p1->DefineFun( _T("strfun1"), StrFun1); - p1->DefineFun( _T("strfun2"), StrFun2); - p1->DefineFun( _T("strfun3"), StrFun3); - p1->DefineFun( _T("lastArg"), LastArg); - p1->DefineFun( _T("firstArg"), FirstArg); - p1->DefineFun( _T("order"), FirstArg); + p1->DefineFun(_T("min"), Min); + p1->DefineFun(_T("max"), Max); + p1->DefineFun(_T("sum"), Sum); + p1->DefineFun(_T("valueof"), ValueOf); + p1->DefineFun(_T("atof"), StrToFloat); + p1->DefineFun(_T("strfun1"), StrFun1); + p1->DefineFun(_T("strfun2"), StrFun2); + p1->DefineFun(_T("strfun3"), StrFun3); + p1->DefineFun(_T("lastArg"), LastArg); + p1->DefineFun(_T("firstArg"), FirstArg); + p1->DefineFun(_T("order"), FirstArg); // infix / postfix operator - // Note: Identifiers used here do not have any meaning + // Note: Identifiers used here do not have any meaning // they are mere placeholders to test certain features. - p1->DefineInfixOprt( _T("$"), sign, prPOW+1); // sign with high priority - p1->DefineInfixOprt( _T("~"), plus2); // high priority - p1->DefineInfixOprt( _T("~~"), plus2); - p1->DefinePostfixOprt( _T("{m}"), Milli); - p1->DefinePostfixOprt( _T("{M}"), Mega); - p1->DefinePostfixOprt( _T("m"), Milli); - p1->DefinePostfixOprt( _T("meg"), Mega); - p1->DefinePostfixOprt( _T("#"), times3); - p1->DefinePostfixOprt( _T("'"), sqr); + p1->DefineInfixOprt(_T("$"), sign, prPOW + 1); // sign with high priority + p1->DefineInfixOprt(_T("~"), plus2); // high priority + p1->DefineInfixOprt(_T("~~"), plus2); + p1->DefinePostfixOprt(_T("{m}"), Milli); + p1->DefinePostfixOprt(_T("{M}"), Mega); + p1->DefinePostfixOprt(_T("m"), Milli); + p1->DefinePostfixOprt(_T("meg"), Mega); + p1->DefinePostfixOprt(_T("#"), times3); + p1->DefinePostfixOprt(_T("'"), sqr); p1->SetExpr(a_str); // Test bytecode integrity // String parsing and bytecode parsing must yield the same result fVal[0] = p1->Eval(); // result from stringparsing fVal[1] = p1->Eval(); // result from bytecode - if (fVal[0]!=fVal[1]) - throw Parser::exception_type( _T("Bytecode / string parsing mismatch.") ); + if (fVal[0] != fVal[1]) + throw Parser::exception_type(_T("Bytecode / string parsing mismatch.")); // Test copy and assignment operators try { - // Test copy constructor - std::vector vParser; - vParser.push_back(*(p1.get())); - mu::Parser p2 = vParser[0]; // take parser from vector - - // destroy the originals from p2 - vParser.clear(); // delete the vector - p1.reset(0); - - fVal[2] = p2.Eval(); - - // Test assignment operator - // additionally disable Optimizer this time - mu::Parser p3; - p3 = p2; - p3.EnableOptimizer(false); - fVal[3] = p3.Eval(); - - // Test Eval function for multiple return values - // use p2 since it has the optimizer enabled! - int nNum; - value_type *v = p2.Eval(nNum); - fVal[4] = v[nNum-1]; + // Test copy constructor + std::vector vParser; + vParser.push_back(*(p1.get())); + mu::Parser p2 = vParser[0]; // take parser from vector + + // destroy the originals from p2 + vParser.clear(); // delete the vector + p1.reset(0); + + fVal[2] = p2.Eval(); + + // Test assignment operator + // additionally disable Optimizer this time + mu::Parser p3; + p3 = p2; + p3.EnableOptimizer(false); + fVal[3] = p3.Eval(); + + // Test Eval function for multiple return values + // use p2 since it has the optimizer enabled! + int nNum; + value_type* v = p2.Eval(nNum); + fVal[4] = v[nNum - 1]; } - catch(std::exception &e) + catch (std::exception& e) { - mu::console() << _T("\n ") << e.what() << _T("\n"); + mu::console() << _T("\n ") << e.what() << _T("\n"); } // limited floating point accuracy requires the following test bool bCloseEnough(true); - for (unsigned i=0; i::has_infinity) - #pragma warning(pop) - { - bCloseEnough &= (fabs(fVal[i]) != numeric_limits::infinity()); - } - } + bCloseEnough &= (fabs(a_fRes - fVal[i]) <= fabs(fVal[i] * 0.00001)); + +// The tests equations never result in infinity, if they do thats a bug. +// reference: +// http://sourceforge.net/projects/muparser/forums/forum/462843/topic/5037825 +#pragma warning(push) +#pragma warning(disable : 4127) + if (std::numeric_limits::has_infinity) +#pragma warning(pop) + { + bCloseEnough &= (fabs(fVal[i]) != numeric_limits::infinity()); + } + } iRet = ((bCloseEnough && a_fPass) || (!bCloseEnough && !a_fPass)) ? 0 : 1; - - - if (iRet==1) + + if (iRet == 1) { - mu::console() << _T("\n fail: ") << a_str.c_str() - << _T(" (incorrect result; expected: ") << a_fRes - << _T(" ;calculated: ") << fVal[0] << _T(",") - << fVal[1] << _T(",") - << fVal[2] << _T(",") - << fVal[3] << _T(",") - << fVal[4] << _T(")."); + mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (incorrect result; expected: ") << a_fRes + << _T(" ;calculated: ") << fVal[0] << _T(",") << fVal[1] << _T(",") << fVal[2] << _T(",") + << fVal[3] << _T(",") << fVal[4] << _T(")."); } - } - catch(Parser::exception_type &e) - { + } + catch (Parser::exception_type& e) + { if (a_fPass) { - if (fVal[0]!=fVal[2] && fVal[0]!=-999 && fVal[1]!=-998) - mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (copy construction)"); - else - mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (") << e.GetMsg() << _T(")"); - return 1; + if (fVal[0] != fVal[2] && fVal[0] != -999 && fVal[1] != -998) + mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (copy construction)"); + else + mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (") << e.GetMsg() << _T(")"); + return 1; } - } - catch(std::exception &e) - { + } + catch (std::exception& e) + { mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (") << e.what() << _T(")"); - return 1; // always return a failure since this exception is not expected - } - catch(...) - { - mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (unexpected exception)"); - return 1; // exceptions other than ParserException are not allowed - } - - return iRet; + return 1; // always return a failure since this exception is not expected } - - //--------------------------------------------------------------------------- - int ParserTester::EqnTestInt(const string_type &a_str, double a_fRes, bool a_fPass) + catch (...) { - ParserTester::c_iCount++; + mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (unexpected exception)"); + return 1; // exceptions other than ParserException are not allowed + } + + return iRet; +} - value_type vVarVal[] = {1, 2, 3}; // variable values - int iRet(0); +//--------------------------------------------------------------------------- +int ParserTester::EqnTestInt(const string_type& a_str, double a_fRes, bool a_fPass) +{ + ParserTester::c_iCount++; - try - { - value_type fVal[2] = {-99, -999}; // results: initially should be different + value_type vVarVal[] = {1, 2, 3}; // variable values + int iRet(0); + + try + { + value_type fVal[2] = {-99, -999}; // results: initially should be different ParserInt p; - p.DefineConst( _T("const1"), 1); - p.DefineConst( _T("const2"), 2); - p.DefineVar( _T("a"), &vVarVal[0]); - p.DefineVar( _T("b"), &vVarVal[1]); - p.DefineVar( _T("c"), &vVarVal[2]); + p.DefineConst(_T("const1"), 1); + p.DefineConst(_T("const2"), 2); + p.DefineVar(_T("a"), &vVarVal[0]); + p.DefineVar(_T("b"), &vVarVal[1]); + p.DefineVar(_T("c"), &vVarVal[2]); p.SetExpr(a_str); fVal[0] = p.Eval(); // result from stringparsing fVal[1] = p.Eval(); // result from bytecode - if (fVal[0]!=fVal[1]) - throw Parser::exception_type( _T("Bytecode corrupt.") ); + if (fVal[0] != fVal[1]) + throw Parser::exception_type(_T("Bytecode corrupt.")); - iRet = ( (a_fRes==fVal[0] && a_fPass) || - (a_fRes!=fVal[0] && !a_fPass) ) ? 0 : 1; - if (iRet==1) + iRet = ((a_fRes == fVal[0] && a_fPass) || (a_fRes != fVal[0] && !a_fPass)) ? 0 : 1; + if (iRet == 1) { - mu::console() << _T("\n fail: ") << a_str.c_str() - << _T(" (incorrect result; expected: ") << a_fRes - << _T(" ;calculated: ") << fVal[0]<< _T(")."); + mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (incorrect result; expected: ") << a_fRes + << _T(" ;calculated: ") << fVal[0] << _T(")."); } - } - catch(Parser::exception_type &e) - { + } + catch (Parser::exception_type& e) + { if (a_fPass) { - mu::console() << _T("\n fail: ") << e.GetExpr() << _T(" : ") << e.GetMsg(); - iRet = 1; + mu::console() << _T("\n fail: ") << e.GetExpr() << _T(" : ") << e.GetMsg(); + iRet = 1; } - } - catch(...) - { - mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (unexpected exception)"); - iRet = 1; // exceptions other than ParserException are not allowed - } - - return iRet; } + catch (...) + { + mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (unexpected exception)"); + iRet = 1; // exceptions other than ParserException are not allowed + } + + return iRet; +} - //--------------------------------------------------------------------------- - /** \brief Test an expression in Bulk Mode. */ - int ParserTester::EqnTestBulk(const string_type &a_str, double a_fRes[4], bool a_fPass) +//--------------------------------------------------------------------------- +/** \brief Test an expression in Bulk Mode. */ +int ParserTester::EqnTestBulk(const string_type& a_str, double a_fRes[4], bool a_fPass) +{ + ParserTester::c_iCount++; + + // Define Bulk Variables + int nBulkSize = 4; + value_type vVariableA[] = {1, 2, 3, 4}; // variable values + value_type vVariableB[] = {2, 2, 2, 2}; // variable values + value_type vVariableC[] = {3, 3, 3, 3}; // variable values + value_type vResults[] = {0, 0, 0, 0}; // variable values + int iRet(0); + + try { - ParserTester::c_iCount++; + Parser p; + p.DefineConst(_T("const1"), 1); + p.DefineConst(_T("const2"), 2); + p.DefineVar(_T("a"), vVariableA); + p.DefineVar(_T("b"), vVariableB); + p.DefineVar(_T("c"), vVariableC); - // Define Bulk Variables - int nBulkSize = 4; - value_type vVariableA[] = { 1, 2, 3, 4 }; // variable values - value_type vVariableB[] = { 2, 2, 2, 2 }; // variable values - value_type vVariableC[] = { 3, 3, 3, 3 }; // variable values - value_type vResults[] = { 0, 0, 0, 0 }; // variable values - int iRet(0); + p.SetExpr(a_str); + p.Eval(vResults, nBulkSize); - try + bool bCloseEnough(true); + for (int i = 0; i < nBulkSize; ++i) { - Parser p; - p.DefineConst(_T("const1"), 1); - p.DefineConst(_T("const2"), 2); - p.DefineVar(_T("a"), vVariableA); - p.DefineVar(_T("b"), vVariableB); - p.DefineVar(_T("c"), vVariableC); - - p.SetExpr(a_str); - p.Eval(vResults, nBulkSize); - - bool bCloseEnough(true); - for (int i = 0; i < nBulkSize; ++i) - { - bCloseEnough &= (fabs(a_fRes[i] - vResults[i]) <= fabs(a_fRes[i] * 0.00001)); - } - - iRet = ((bCloseEnough && a_fPass) || (!bCloseEnough && !a_fPass)) ? 0 : 1; - if (iRet == 1) - { - mu::console() << _T("\n fail: ") << a_str.c_str() - << _T(" (incorrect result; expected: {") << a_fRes[0] << _T(",") << a_fRes[1] << _T(",") << a_fRes[2] << _T(",") << a_fRes[3] << _T("}") - << _T(" ;calculated: ") << vResults[0] << _T(",") << vResults[1] << _T(",") << vResults[2] << _T(",") << vResults[3] << _T("}"); - } + bCloseEnough &= (fabs(a_fRes[i] - vResults[i]) <= fabs(a_fRes[i] * 0.00001)); } - catch (Parser::exception_type &e) + + iRet = ((bCloseEnough && a_fPass) || (!bCloseEnough && !a_fPass)) ? 0 : 1; + if (iRet == 1) { - if (a_fPass) - { - mu::console() << _T("\n fail: ") << e.GetExpr() << _T(" : ") << e.GetMsg(); - iRet = 1; - } + mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (incorrect result; expected: {") << a_fRes[0] + << _T(",") << a_fRes[1] << _T(",") << a_fRes[2] << _T(",") << a_fRes[3] << _T("}") + << _T(" ;calculated: ") << vResults[0] << _T(",") << vResults[1] << _T(",") << vResults[2] + << _T(",") << vResults[3] << _T("}"); } - catch (...) + } + catch (Parser::exception_type& e) + { + if (a_fPass) { - mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (unexpected exception)"); - iRet = 1; // exceptions other than ParserException are not allowed + mu::console() << _T("\n fail: ") << e.GetExpr() << _T(" : ") << e.GetMsg(); + iRet = 1; } - - return iRet; } - - //--------------------------------------------------------------------------- - /** \brief Internal error in test class Test is going to be aborted. */ - void ParserTester::Abort() const + catch (...) { - mu::console() << _T("Test failed (internal error in test class)") << endl; - while (!getchar()); - exit(-1); + mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (unexpected exception)"); + iRet = 1; // exceptions other than ParserException are not allowed } - } // namespace test + + return iRet; +} + +//--------------------------------------------------------------------------- +/** \brief Internal error in test class Test is going to be aborted. */ +void ParserTester::Abort() const +{ + mu::console() << _T("Test failed (internal error in test class)") << endl; + while (!getchar()) + ; + exit(-1); +} +} // namespace Test } // namespace mu diff --git a/ext_libs/muparser/muParserTest.h b/ext_libs/muparser/muParserTest.h old mode 100755 new mode 100644 index c02b0218..6e266e57 --- a/ext_libs/muparser/muParserTest.h +++ b/ext_libs/muparser/muParserTest.h @@ -1,26 +1,26 @@ /* - __________ - _____ __ __\______ \_____ _______ ______ ____ _______ + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ - |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| - \/ \/ \/ \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ Copyright (C) 2013 Ingo Berg - Permission is hereby granted, free of charge, to any person obtaining a copy of this + 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 + 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 + 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. + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MU_PARSER_TEST_H @@ -38,177 +38,162 @@ namespace mu { - /** \brief Namespace for test cases. */ - namespace Test - { - //------------------------------------------------------------------------------ - /** \brief Test cases for unit testing. - - (C) 2004-2011 Ingo Berg - */ - class ParserTester // final +/** \brief Namespace for test cases. */ +namespace Test +{ +//------------------------------------------------------------------------------ +/** \brief Test cases for unit testing. + + (C) 2004-2011 Ingo Berg +*/ +class ParserTester // final +{ +private: + static int c_iCount; + + // Multiarg callbacks + static value_type f1of1(value_type v) { return v; }; + + static value_type f1of2(value_type v, value_type) { return v; }; + static value_type f2of2(value_type, value_type v) { return v; }; + + static value_type f1of3(value_type v, value_type, value_type) { return v; }; + static value_type f2of3(value_type, value_type v, value_type) { return v; }; + static value_type f3of3(value_type, value_type, value_type v) { return v; }; + + static value_type f1of4(value_type v, value_type, value_type, value_type) { return v; } + static value_type f2of4(value_type, value_type v, value_type, value_type) { return v; } + static value_type f3of4(value_type, value_type, value_type v, value_type) { return v; } + static value_type f4of4(value_type, value_type, value_type, value_type v) { return v; } + + static value_type f1of5(value_type v, value_type, value_type, value_type, value_type) { return v; } + static value_type f2of5(value_type, value_type v, value_type, value_type, value_type) { return v; } + static value_type f3of5(value_type, value_type, value_type v, value_type, value_type) { return v; } + static value_type f4of5(value_type, value_type, value_type, value_type v, value_type) { return v; } + static value_type f5of5(value_type, value_type, value_type, value_type, value_type v) { return v; } + + static value_type Min(value_type a_fVal1, value_type a_fVal2) { return (a_fVal1 < a_fVal2) ? a_fVal1 : a_fVal2; } + static value_type Max(value_type a_fVal1, value_type a_fVal2) { return (a_fVal1 > a_fVal2) ? a_fVal1 : a_fVal2; } + + static value_type plus2(value_type v1) { return v1 + 2; } + static value_type times3(value_type v1) { return v1 * 3; } + static value_type sqr(value_type v1) { return v1 * v1; } + static value_type sign(value_type v) { return -v; } + static value_type add(value_type v1, value_type v2) { return v1 + v2; } + static value_type land(value_type v1, value_type v2) { return (int)v1 & (int)v2; } + + static value_type FirstArg(const value_type* a_afArg, int a_iArgc) { - private: - static int c_iCount; - - // Multiarg callbacks - static value_type f1of1(value_type v) { return v;}; - - static value_type f1of2(value_type v, value_type ) {return v;}; - static value_type f2of2(value_type , value_type v) {return v;}; - - static value_type f1of3(value_type v, value_type , value_type ) {return v;}; - static value_type f2of3(value_type , value_type v, value_type ) {return v;}; - static value_type f3of3(value_type , value_type , value_type v) {return v;}; - - static value_type f1of4(value_type v, value_type, value_type , value_type ) {return v;} - static value_type f2of4(value_type , value_type v, value_type , value_type ) {return v;} - static value_type f3of4(value_type , value_type, value_type v, value_type ) {return v;} - static value_type f4of4(value_type , value_type, value_type , value_type v) {return v;} - - static value_type f1of5(value_type v, value_type, value_type , value_type , value_type ) { return v; } - static value_type f2of5(value_type , value_type v, value_type , value_type , value_type ) { return v; } - static value_type f3of5(value_type , value_type, value_type v, value_type , value_type ) { return v; } - static value_type f4of5(value_type , value_type, value_type , value_type v, value_type ) { return v; } - static value_type f5of5(value_type , value_type, value_type , value_type , value_type v) { return v; } - - static value_type Min(value_type a_fVal1, value_type a_fVal2) { return (a_fVal1a_fVal2) ? a_fVal1 : a_fVal2; } - - static value_type plus2(value_type v1) { return v1+2; } - static value_type times3(value_type v1) { return v1*3; } - static value_type sqr(value_type v1) { return v1*v1; } - static value_type sign(value_type v) { return -v; } - static value_type add(value_type v1, value_type v2) { return v1+v2; } - static value_type land(value_type v1, value_type v2) { return (int)v1 & (int)v2; } - - - static value_type FirstArg(const value_type* a_afArg, int a_iArgc) - { - if (!a_iArgc) - throw mu::Parser::exception_type( _T("too few arguments for function FirstArg.") ); - - return a_afArg[0]; - } - - static value_type LastArg(const value_type* a_afArg, int a_iArgc) - { - if (!a_iArgc) - throw mu::Parser::exception_type( _T("too few arguments for function LastArg.") ); - - return a_afArg[a_iArgc-1]; - } - - static value_type Sum(const value_type* a_afArg, int a_iArgc) - { - if (!a_iArgc) - throw mu::Parser::exception_type( _T("too few arguments for function sum.") ); - - value_type fRes=0; - for (int i=0; i> val; - return (value_type)val; - } - - static value_type StrFun2(const char_type* v1, value_type v2) - { - int val(0); - stringstream_type(v1) >> val; - return (value_type)(val + v2); - } - - static value_type StrFun3(const char_type* v1, value_type v2, value_type v3) - { - int val(0); - stringstream_type(v1) >> val; - return val + v2 + v3; - } - - static value_type StrToFloat(const char_type* a_szMsg) - { - value_type val(0); - stringstream_type(a_szMsg) >> val; - return val; - } - - // postfix operator callback - static value_type Mega(value_type a_fVal) { return a_fVal * (value_type)1e6; } - static value_type Micro(value_type a_fVal) { return a_fVal * (value_type)1e-6; } - static value_type Milli(value_type a_fVal) { return a_fVal / (value_type)1e3; } - - // Custom value recognition - static int IsHexVal(const char_type *a_szExpr, int *a_iPos, value_type *a_fVal); - - int TestNames(); - int TestSyntax(); - int TestMultiArg(); - int TestPostFix(); - int TestExpression(); - int TestInfixOprt(); - int TestBinOprt(); - int TestVarConst(); - int TestInterface(); - int TestException(); - int TestStrArg(); - int TestIfThenElse(); - int TestBulkMode(); - - void Abort() const; - - public: - typedef int (ParserTester::*testfun_type)(); - - ParserTester(); - void Run(); - - private: - std::vector m_vTestFun; - void AddTest(testfun_type a_pFun); - - // Test Double Parser - int EqnTest(const string_type& a_str, double a_fRes, bool a_fPass); - int EqnTestWithVarChange(const string_type& a_str, - double a_fRes1, - double a_fVar1, - double a_fRes2, - double a_fVar2); - int ThrowTest(const string_type& a_str, int a_iErrc, bool a_bFail = true); - - // Test Int Parser - int EqnTestInt(const string_type& a_str, double a_fRes, bool a_fPass); - - // Test Bulkmode - int EqnTestBulk(const string_type& a_str, double a_fRes[4], bool a_fPass); - }; - } // namespace Test -} // namespace mu + if (!a_iArgc) + throw mu::Parser::exception_type(_T("too few arguments for function FirstArg.")); -#endif + return a_afArg[0]; + } + + static value_type LastArg(const value_type* a_afArg, int a_iArgc) + { + if (!a_iArgc) + throw mu::Parser::exception_type(_T("too few arguments for function LastArg.")); + + return a_afArg[a_iArgc - 1]; + } + static value_type Sum(const value_type* a_afArg, int a_iArgc) + { + if (!a_iArgc) + throw mu::Parser::exception_type(_T("too few arguments for function sum.")); + + value_type fRes = 0; + for (int i = 0; i < a_iArgc; ++i) + fRes += a_afArg[i]; + return fRes; + } + + static value_type Rnd(value_type v) { return (value_type)(1 + (v * std::rand() / (RAND_MAX + 1.0))); } + + static value_type RndWithString(const char_type*) + { + return (value_type)(1 + (1000.0f * std::rand() / (RAND_MAX + 1.0))); + } + + static value_type Ping() { return 10; } + + static value_type ValueOf(const char_type*) { return 123; } + + static value_type StrFun1(const char_type* v1) + { + int val(0); + stringstream_type(v1) >> val; + return (value_type)val; + } + static value_type StrFun2(const char_type* v1, value_type v2) + { + int val(0); + stringstream_type(v1) >> val; + return (value_type)(val + v2); + } + + static value_type StrFun3(const char_type* v1, value_type v2, value_type v3) + { + int val(0); + stringstream_type(v1) >> val; + return val + v2 + v3; + } + + static value_type StrToFloat(const char_type* a_szMsg) + { + value_type val(0); + stringstream_type(a_szMsg) >> val; + return val; + } + + // postfix operator callback + static value_type Mega(value_type a_fVal) { return a_fVal * (value_type)1e6; } + static value_type Micro(value_type a_fVal) { return a_fVal * (value_type)1e-6; } + static value_type Milli(value_type a_fVal) { return a_fVal / (value_type)1e3; } + + // Custom value recognition + static int IsHexVal(const char_type* a_szExpr, int* a_iPos, value_type* a_fVal); + + int TestNames(); + int TestSyntax(); + int TestMultiArg(); + int TestPostFix(); + int TestExpression(); + int TestInfixOprt(); + int TestBinOprt(); + int TestVarConst(); + int TestInterface(); + int TestException(); + int TestStrArg(); + int TestIfThenElse(); + int TestBulkMode(); + + void Abort() const; + +public: + typedef int (ParserTester::*testfun_type)(); + + ParserTester(); + void Run(); + +private: + std::vector m_vTestFun; + void AddTest(testfun_type a_pFun); + + // Test Double Parser + int EqnTest(const string_type& a_str, double a_fRes, bool a_fPass); + int EqnTestWithVarChange(const string_type& a_str, double a_fRes1, double a_fVar1, double a_fRes2, double a_fVar2); + int ThrowTest(const string_type& a_str, int a_iErrc, bool a_bFail = true); + + // Test Int Parser + int EqnTestInt(const string_type& a_str, double a_fRes, bool a_fPass); + + // Test Bulkmode + int EqnTestBulk(const string_type& a_str, double a_fRes[4], bool a_fPass); +}; +} // namespace Test +} // namespace mu + +#endif diff --git a/ext_libs/muparser/muParserToken.h b/ext_libs/muparser/muParserToken.h old mode 100755 new mode 100644 index fc91d781..07e349f3 --- a/ext_libs/muparser/muParserToken.h +++ b/ext_libs/muparser/muParserToken.h @@ -1,26 +1,26 @@ /* - __________ - _____ __ __\______ \_____ _______ ______ ____ _______ + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ - |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| - \/ \/ \/ \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ Copyright (C) 2004-2013 Ingo Berg - Permission is hereby granted, free of charge, to any person obtaining a copy of this + 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 + 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 + 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. + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MU_PARSER_TOKEN_H @@ -41,89 +41,78 @@ namespace mu { - /** \brief Encapsulation of the data for a single formula token. - - Formula token implementation. Part of the Math Parser Package. - Formula tokens can be either one of the following: -
    -
  • value
  • -
  • variable
  • -
  • function with numerical arguments
  • -
  • functions with a string as argument
  • -
  • prefix operators
  • -
  • infix operators
  • -
  • binary operator
  • -
- - \author (C) 2004-2013 Ingo Berg - */ - template - class ParserToken - { - private: - - ECmdCode m_iCode; ///< Type of the token; The token type is a constant of type #ECmdCode. - ETypeCode m_iType; - void *m_pTok; ///< Stores Token pointer; not applicable for all tokens - int m_iIdx; ///< An otional index to an external buffer storing the token data - TString m_strTok; ///< Token string - TString m_strVal; ///< Value for string variables - value_type m_fVal; ///< the value - std::auto_ptr m_pCallback; - - public: - - //--------------------------------------------------------------------------- - /** \brief Constructor (default). - - Sets token to an neutral state of type cmUNKNOWN. - \throw nothrow - \sa ECmdCode - */ - ParserToken() - :m_iCode(cmUNKNOWN) - ,m_iType(tpVOID) - ,m_pTok(0) - ,m_iIdx(-1) - ,m_strTok() - ,m_strVal() - ,m_fVal(0) - ,m_pCallback() - {} - - //------------------------------------------------------------------------------ - /** \brief Create token from another one. - - Implemented by calling Assign(...) - \throw nothrow - \post m_iType==cmUNKNOWN - \sa #Assign - */ - ParserToken(const ParserToken &a_Tok) - { - Assign(a_Tok); - } - - //------------------------------------------------------------------------------ - /** \brief Assignement operator. - - Copy token state from another token and return this. - Implemented by calling Assign(...). - \throw nothrow - */ - ParserToken& operator=(const ParserToken &a_Tok) - { +/** \brief Encapsulation of the data for a single formula token. + + Formula token implementation. Part of the Math Parser Package. + Formula tokens can be either one of the following: +
    +
  • value
  • +
  • variable
  • +
  • function with numerical arguments
  • +
  • functions with a string as argument
  • +
  • prefix operators
  • +
  • infix operators
  • +
  • binary operator
  • +
+ + \author (C) 2004-2013 Ingo Berg +*/ +template +class ParserToken +{ +private: + ECmdCode m_iCode; ///< Type of the token; The token type is a constant of type #ECmdCode. + ETypeCode m_iType; + void* m_pTok; ///< Stores Token pointer; not applicable for all tokens + int m_iIdx; ///< An otional index to an external buffer storing the token data + TString m_strTok; ///< Token string + TString m_strVal; ///< Value for string variables + value_type m_fVal; ///< the value + std::auto_ptr m_pCallback; + +public: + //--------------------------------------------------------------------------- + /** \brief Constructor (default). + + Sets token to an neutral state of type cmUNKNOWN. + \throw nothrow + \sa ECmdCode + */ + ParserToken() : + m_iCode(cmUNKNOWN), m_iType(tpVOID), m_pTok(0), m_iIdx(-1), m_strTok(), m_strVal(), m_fVal(0), m_pCallback() + { + } + + //------------------------------------------------------------------------------ + /** \brief Create token from another one. + + Implemented by calling Assign(...) + \throw nothrow + \post m_iType==cmUNKNOWN + \sa #Assign + */ + ParserToken(const ParserToken& a_Tok) { Assign(a_Tok); } + + //------------------------------------------------------------------------------ + /** \brief Assignement operator. + + Copy token state from another token and return this. + Implemented by calling Assign(...). + \throw nothrow + */ + ParserToken& operator=(const ParserToken& a_Tok) + { Assign(a_Tok); return *this; - } - - //------------------------------------------------------------------------------ - /** \brief Copy token information from argument. - - \throw nothrow - */ - void Assign(const ParserToken &a_Tok) - { + } + + //------------------------------------------------------------------------------ + /** \brief Copy token information from argument. + + \throw nothrow + */ + void Assign(const ParserToken& a_Tok) + { m_iCode = a_Tok.m_iCode; m_pTok = a_Tok.m_pTok; m_strTok = a_Tok.m_strTok; @@ -131,27 +120,27 @@ namespace mu m_strVal = a_Tok.m_strVal; m_iType = a_Tok.m_iType; m_fVal = a_Tok.m_fVal; - // create new callback object if a_Tok has one + // create new callback object if a_Tok has one m_pCallback.reset(a_Tok.m_pCallback.get() ? a_Tok.m_pCallback->Clone() : 0); - } + } - //------------------------------------------------------------------------------ - /** \brief Assign a token type. + //------------------------------------------------------------------------------ + /** \brief Assign a token type. - Token may not be of type value, variable or function. Those have seperate set functions. + Token may not be of type value, variable or function. Those have seperate set functions. - \pre [assert] a_iType!=cmVAR - \pre [assert] a_iType!=cmVAL - \pre [assert] a_iType!=cmFUNC - \post m_fVal = 0 - \post m_pTok = 0 - */ - ParserToken& Set(ECmdCode a_iType, const TString &a_strTok=TString()) - { + \pre [assert] a_iType!=cmVAR + \pre [assert] a_iType!=cmVAL + \pre [assert] a_iType!=cmFUNC + \post m_fVal = 0 + \post m_pTok = 0 + */ + ParserToken& Set(ECmdCode a_iType, const TString& a_strTok = TString()) + { // The following types cant be set this way, they have special Set functions - assert(a_iType!=cmVAR); - assert(a_iType!=cmVAL); - assert(a_iType!=cmFUNC); + assert(a_iType != cmVAR); + assert(a_iType != cmVAL); + assert(a_iType != cmFUNC); m_iCode = a_iType; m_iType = tpVOID; @@ -160,12 +149,12 @@ namespace mu m_iIdx = -1; return *this; - } + } - //------------------------------------------------------------------------------ - /** \brief Set Callback type. */ - ParserToken& Set(const ParserCallback &a_pCallback, const TString &a_sTok) - { + //------------------------------------------------------------------------------ + /** \brief Set Callback type. */ + ParserToken& Set(const ParserCallback& a_pCallback, const TString& a_sTok) + { assert(a_pCallback.GetAddr()); m_iCode = a_pCallback.GetCode(); @@ -175,38 +164,38 @@ namespace mu m_pTok = 0; m_iIdx = -1; - + return *this; - } - - //------------------------------------------------------------------------------ - /** \brief Make this token a value token. - - Member variables not necessary for value tokens will be invalidated. - \throw nothrow - */ - ParserToken& SetVal(TBase a_fVal, const TString &a_strTok=TString()) - { + } + + //------------------------------------------------------------------------------ + /** \brief Make this token a value token. + + Member variables not necessary for value tokens will be invalidated. + \throw nothrow + */ + ParserToken& SetVal(TBase a_fVal, const TString& a_strTok = TString()) + { m_iCode = cmVAL; m_iType = tpDBL; m_fVal = a_fVal; m_strTok = a_strTok; m_iIdx = -1; - + m_pTok = 0; m_pCallback.reset(0); return *this; - } - - //------------------------------------------------------------------------------ - /** \brief make this token a variable token. - - Member variables not necessary for variable tokens will be invalidated. - \throw nothrow - */ - ParserToken& SetVar(TBase *a_pVar, const TString &a_strTok) - { + } + + //------------------------------------------------------------------------------ + /** \brief make this token a variable token. + + Member variables not necessary for variable tokens will be invalidated. + \throw nothrow + */ + ParserToken& SetVar(TBase* a_pVar, const TString& a_strTok) + { m_iCode = cmVAR; m_iType = tpDBL; m_strTok = a_strTok; @@ -214,16 +203,16 @@ namespace mu m_pTok = (void*)a_pVar; m_pCallback.reset(0); return *this; - } - - //------------------------------------------------------------------------------ - /** \brief Make this token a variable token. - - Member variables not necessary for variable tokens will be invalidated. - \throw nothrow - */ - ParserToken& SetString(const TString &a_strTok, std::size_t a_iSize) - { + } + + //------------------------------------------------------------------------------ + /** \brief Make this token a variable token. + + Member variables not necessary for variable tokens will be invalidated. + \throw nothrow + */ + ParserToken& SetString(const TString& a_strTok, std::size_t a_iSize) + { m_iCode = cmSTRING; m_iType = tpSTR; m_strTok = a_strTok; @@ -232,170 +221,167 @@ namespace mu m_pTok = 0; m_pCallback.reset(0); return *this; - } - - //------------------------------------------------------------------------------ - /** \brief Set an index associated with the token related data. - - In cmSTRFUNC - This is the index to a string table in the main parser. - \param a_iIdx The index the string function result will take in the bytecode parser. - \throw exception_type if #a_iIdx<0 or #m_iType!=cmSTRING - */ - void SetIdx(int a_iIdx) - { - if (m_iCode!=cmSTRING || a_iIdx<0) - throw ParserError(ecINTERNAL_ERROR); - + } + + //------------------------------------------------------------------------------ + /** \brief Set an index associated with the token related data. + + In cmSTRFUNC - This is the index to a string table in the main parser. + \param a_iIdx The index the string function result will take in the bytecode parser. + \throw exception_type if #a_iIdx<0 or #m_iType!=cmSTRING + */ + void SetIdx(int a_iIdx) + { + if (m_iCode != cmSTRING || a_iIdx < 0) + throw ParserError(ecINTERNAL_ERROR); + m_iIdx = a_iIdx; - } + } - //------------------------------------------------------------------------------ - /** \brief Return Index associated with the token related data. - - In cmSTRFUNC - This is the index to a string table in the main parser. + //------------------------------------------------------------------------------ + /** \brief Return Index associated with the token related data. - \throw exception_type if #m_iIdx<0 or #m_iType!=cmSTRING - \return The index the result will take in the Bytecode calculatin array (#m_iIdx). - */ - int GetIdx() const - { - if (m_iIdx<0 || m_iCode!=cmSTRING ) - throw ParserError(ecINTERNAL_ERROR); + In cmSTRFUNC - This is the index to a string table in the main parser. + + \throw exception_type if #m_iIdx<0 or #m_iType!=cmSTRING + \return The index the result will take in the Bytecode calculatin array (#m_iIdx). + */ + int GetIdx() const + { + if (m_iIdx < 0 || m_iCode != cmSTRING) + throw ParserError(ecINTERNAL_ERROR); return m_iIdx; - } - - //------------------------------------------------------------------------------ - /** \brief Return the token type. - - \return #m_iType - \throw nothrow - */ - ECmdCode GetCode() const - { + } + + //------------------------------------------------------------------------------ + /** \brief Return the token type. + + \return #m_iType + \throw nothrow + */ + ECmdCode GetCode() const + { if (m_pCallback.get()) { - return m_pCallback->GetCode(); + return m_pCallback->GetCode(); } else { - return m_iCode; + return m_iCode; } - } + } - //------------------------------------------------------------------------------ - ETypeCode GetType() const - { + //------------------------------------------------------------------------------ + ETypeCode GetType() const + { if (m_pCallback.get()) { - return m_pCallback->GetType(); + return m_pCallback->GetType(); } else { - return m_iType; + return m_iType; } - } - - //------------------------------------------------------------------------------ - int GetPri() const - { - if ( !m_pCallback.get()) - throw ParserError(ecINTERNAL_ERROR); - - if ( m_pCallback->GetCode()!=cmOPRT_BIN && m_pCallback->GetCode()!=cmOPRT_INFIX) - throw ParserError(ecINTERNAL_ERROR); + } + + //------------------------------------------------------------------------------ + int GetPri() const + { + if (!m_pCallback.get()) + throw ParserError(ecINTERNAL_ERROR); + + if (m_pCallback->GetCode() != cmOPRT_BIN && m_pCallback->GetCode() != cmOPRT_INFIX) + throw ParserError(ecINTERNAL_ERROR); return m_pCallback->GetPri(); - } + } - //------------------------------------------------------------------------------ - EOprtAssociativity GetAssociativity() const - { - if (m_pCallback.get()==NULL || m_pCallback->GetCode()!=cmOPRT_BIN) - throw ParserError(ecINTERNAL_ERROR); + //------------------------------------------------------------------------------ + EOprtAssociativity GetAssociativity() const + { + if (m_pCallback.get() == NULL || m_pCallback->GetCode() != cmOPRT_BIN) + throw ParserError(ecINTERNAL_ERROR); return m_pCallback->GetAssociativity(); - } - - //------------------------------------------------------------------------------ - /** \brief Return the address of the callback function assoziated with - function and operator tokens. - - \return The pointer stored in #m_pTok. - \throw exception_type if token type is non of: -
    -
  • cmFUNC
  • -
  • cmSTRFUNC
  • -
  • cmPOSTOP
  • -
  • cmINFIXOP
  • -
  • cmOPRT_BIN
  • -
- \sa ECmdCode - */ - generic_fun_type GetFuncAddr() const - { - return (m_pCallback.get()) ? (generic_fun_type)m_pCallback->GetAddr() : 0; - } - - //------------------------------------------------------------------------------ - /** \biref Get value of the token. - - Only applicable to variable and value tokens. - \throw exception_type if token is no value/variable token. - */ - TBase GetVal() const - { + } + + //------------------------------------------------------------------------------ + /** \brief Return the address of the callback function assoziated with + function and operator tokens. + + \return The pointer stored in #m_pTok. + \throw exception_type if token type is non of: +
    +
  • cmFUNC
  • +
  • cmSTRFUNC
  • +
  • cmPOSTOP
  • +
  • cmINFIXOP
  • +
  • cmOPRT_BIN
  • +
+ \sa ECmdCode + */ + generic_fun_type GetFuncAddr() const { return (m_pCallback.get()) ? (generic_fun_type)m_pCallback->GetAddr() : 0; } + + //------------------------------------------------------------------------------ + /** \biref Get value of the token. + + Only applicable to variable and value tokens. + \throw exception_type if token is no value/variable token. + */ + TBase GetVal() const + { switch (m_iCode) { - case cmVAL: return m_fVal; - case cmVAR: return *((TBase*)m_pTok); - default: throw ParserError(ecVAL_EXPECTED); + case cmVAL: + return m_fVal; + case cmVAR: + return *((TBase*)m_pTok); + default: + throw ParserError(ecVAL_EXPECTED); } - } + } - //------------------------------------------------------------------------------ - /** \brief Get address of a variable token. + //------------------------------------------------------------------------------ + /** \brief Get address of a variable token. - Valid only if m_iType==CmdVar. - \throw exception_type if token is no variable token. - */ - TBase* GetVar() const - { - if (m_iCode!=cmVAR) - throw ParserError(ecINTERNAL_ERROR); + Valid only if m_iType==CmdVar. + \throw exception_type if token is no variable token. + */ + TBase* GetVar() const + { + if (m_iCode != cmVAR) + throw ParserError(ecINTERNAL_ERROR); return (TBase*)m_pTok; - } + } - //------------------------------------------------------------------------------ - /** \brief Return the number of function arguments. + //------------------------------------------------------------------------------ + /** \brief Return the number of function arguments. - Valid only if m_iType==CmdFUNC. - */ - int GetArgCount() const - { + Valid only if m_iType==CmdFUNC. + */ + int GetArgCount() const + { assert(m_pCallback.get()); if (!m_pCallback->GetAddr()) - throw ParserError(ecINTERNAL_ERROR); + throw ParserError(ecINTERNAL_ERROR); return m_pCallback->GetArgc(); - } - - //------------------------------------------------------------------------------ - /** \brief Return the token identifier. - - If #m_iType is cmSTRING the token identifier is the value of the string argument - for a string function. - \return #m_strTok - \throw nothrow - \sa m_strTok - */ - const TString& GetAsString() const - { - return m_strTok; - } - }; + } + + //------------------------------------------------------------------------------ + /** \brief Return the token identifier. + + If #m_iType is cmSTRING the token identifier is the value of the string argument + for a string function. + \return #m_strTok + \throw nothrow + \sa m_strTok + */ + const TString& GetAsString() const { return m_strTok; } +}; } // namespace mu #endif diff --git a/ext_libs/muparser/muParserTokenReader.cpp b/ext_libs/muparser/muParserTokenReader.cpp old mode 100755 new mode 100644 index 8da1e402..20f99456 --- a/ext_libs/muparser/muParserTokenReader.cpp +++ b/ext_libs/muparser/muParserTokenReader.cpp @@ -1,26 +1,26 @@ /* - __________ - _____ __ __\______ \_____ _______ ______ ____ _______ + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ - |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| - \/ \/ \/ \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ Copyright (C) 2013 Ingo Berg - Permission is hereby granted, free of charge, to any person obtaining a copy of this + 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 + 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 + 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. + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include @@ -36,846 +36,850 @@ \brief This file contains the parser token reader implementation. */ - namespace mu { +// Forward declaration +class ParserBase; - // Forward declaration - class ParserBase; - - //--------------------------------------------------------------------------- - /** \brief Copy constructor. +//--------------------------------------------------------------------------- +/** \brief Copy constructor. - \sa Assign - \throw nothrow - */ - ParserTokenReader::ParserTokenReader(const ParserTokenReader &a_Reader) - { + \sa Assign + \throw nothrow +*/ +ParserTokenReader::ParserTokenReader(const ParserTokenReader& a_Reader) +{ Assign(a_Reader); - } - - //--------------------------------------------------------------------------- - /** \brief Assignment operator. +} - Self assignment will be suppressed otherwise #Assign is called. +//--------------------------------------------------------------------------- +/** \brief Assignment operator. - \param a_Reader Object to copy to this token reader. - \throw nothrow - */ - ParserTokenReader& ParserTokenReader::operator=(const ParserTokenReader &a_Reader) - { - if (&a_Reader!=this) - Assign(a_Reader); + Self assignment will be suppressed otherwise #Assign is called. + + \param a_Reader Object to copy to this token reader. + \throw nothrow +*/ +ParserTokenReader& ParserTokenReader::operator=(const ParserTokenReader& a_Reader) +{ + if (&a_Reader != this) + Assign(a_Reader); return *this; - } - - //--------------------------------------------------------------------------- - /** \brief Assign state of a token reader to this token reader. - - \param a_Reader Object from which the state should be copied. - \throw nothrow - */ - void ParserTokenReader::Assign(const ParserTokenReader &a_Reader) - { +} + +//--------------------------------------------------------------------------- +/** \brief Assign state of a token reader to this token reader. + + \param a_Reader Object from which the state should be copied. + \throw nothrow +*/ +void ParserTokenReader::Assign(const ParserTokenReader& a_Reader) +{ m_pParser = a_Reader.m_pParser; m_strFormula = a_Reader.m_strFormula; m_iPos = a_Reader.m_iPos; m_iSynFlags = a_Reader.m_iSynFlags; - - m_UsedVar = a_Reader.m_UsedVar; - m_pFunDef = a_Reader.m_pFunDef; - m_pConstDef = a_Reader.m_pConstDef; - m_pVarDef = a_Reader.m_pVarDef; - m_pStrVarDef = a_Reader.m_pStrVarDef; - m_pPostOprtDef = a_Reader.m_pPostOprtDef; - m_pInfixOprtDef = a_Reader.m_pInfixOprtDef; - m_pOprtDef = a_Reader.m_pOprtDef; + + m_UsedVar = a_Reader.m_UsedVar; + m_pFunDef = a_Reader.m_pFunDef; + m_pConstDef = a_Reader.m_pConstDef; + m_pVarDef = a_Reader.m_pVarDef; + m_pStrVarDef = a_Reader.m_pStrVarDef; + m_pPostOprtDef = a_Reader.m_pPostOprtDef; + m_pInfixOprtDef = a_Reader.m_pInfixOprtDef; + m_pOprtDef = a_Reader.m_pOprtDef; m_bIgnoreUndefVar = a_Reader.m_bIgnoreUndefVar; - m_vIdentFun = a_Reader.m_vIdentFun; - m_pFactory = a_Reader.m_pFactory; - m_pFactoryData = a_Reader.m_pFactoryData; - m_iBrackets = a_Reader.m_iBrackets; - m_cArgSep = a_Reader.m_cArgSep; - m_fZero = a_Reader.m_fZero; - m_lastTok = a_Reader.m_lastTok; - } - - //--------------------------------------------------------------------------- - /** \brief Constructor. - - Create a Token reader and bind it to a parser object. - - \pre [assert] a_pParser may not be NULL - \post #m_pParser==a_pParser - \param a_pParent Parent parser object of the token reader. - */ - ParserTokenReader::ParserTokenReader(ParserBase *a_pParent) - :m_pParser(a_pParent) - ,m_strFormula() - ,m_iPos(0) - ,m_iSynFlags(0) - ,m_bIgnoreUndefVar(false) - ,m_pFunDef(NULL) - ,m_pPostOprtDef(NULL) - ,m_pInfixOprtDef(NULL) - ,m_pOprtDef(NULL) - ,m_pConstDef(NULL) - ,m_pStrVarDef(NULL) - ,m_pVarDef(NULL) - ,m_pFactory(NULL) - ,m_pFactoryData(NULL) - ,m_vIdentFun() - ,m_UsedVar() - ,m_fZero(0) - ,m_iBrackets(0) - ,m_lastTok() - ,m_cArgSep(',') - { + m_vIdentFun = a_Reader.m_vIdentFun; + m_pFactory = a_Reader.m_pFactory; + m_pFactoryData = a_Reader.m_pFactoryData; + m_iBrackets = a_Reader.m_iBrackets; + m_cArgSep = a_Reader.m_cArgSep; + m_fZero = a_Reader.m_fZero; + m_lastTok = a_Reader.m_lastTok; +} + +//--------------------------------------------------------------------------- +/** \brief Constructor. + + Create a Token reader and bind it to a parser object. + + \pre [assert] a_pParser may not be NULL + \post #m_pParser==a_pParser + \param a_pParent Parent parser object of the token reader. +*/ +ParserTokenReader::ParserTokenReader(ParserBase* a_pParent) : + m_pParser(a_pParent), + m_strFormula(), + m_iPos(0), + m_iSynFlags(0), + m_bIgnoreUndefVar(false), + m_pFunDef(NULL), + m_pPostOprtDef(NULL), + m_pInfixOprtDef(NULL), + m_pOprtDef(NULL), + m_pConstDef(NULL), + m_pStrVarDef(NULL), + m_pVarDef(NULL), + m_pFactory(NULL), + m_pFactoryData(NULL), + m_vIdentFun(), + m_UsedVar(), + m_fZero(0), + m_iBrackets(0), + m_lastTok(), + m_cArgSep(',') +{ assert(m_pParser); SetParent(m_pParser); - } - - //--------------------------------------------------------------------------- - /** \brief Create instance of a ParserTokenReader identical with this - and return its pointer. - - This is a factory method the calling function must take care of the object destruction. - - \return A new ParserTokenReader object. - \throw nothrow - */ - ParserTokenReader* ParserTokenReader::Clone(ParserBase *a_pParent) const - { +} + +//--------------------------------------------------------------------------- +/** \brief Create instance of a ParserTokenReader identical with this + and return its pointer. + + This is a factory method the calling function must take care of the object destruction. + + \return A new ParserTokenReader object. + \throw nothrow +*/ +ParserTokenReader* ParserTokenReader::Clone(ParserBase* a_pParent) const +{ std::auto_ptr ptr(new ParserTokenReader(*this)); ptr->SetParent(a_pParent); return ptr.release(); - } +} - //--------------------------------------------------------------------------- - ParserTokenReader::token_type& ParserTokenReader::SaveBeforeReturn(const token_type &tok) - { +//--------------------------------------------------------------------------- +ParserTokenReader::token_type& ParserTokenReader::SaveBeforeReturn(const token_type& tok) +{ m_lastTok = tok; return m_lastTok; - } +} - //--------------------------------------------------------------------------- - void ParserTokenReader::AddValIdent(identfun_type a_pCallback) - { +//--------------------------------------------------------------------------- +void ParserTokenReader::AddValIdent(identfun_type a_pCallback) +{ // Use push_front is used to give user defined callbacks a higher priority than // the built in ones. Otherwise reading hex numbers would not work - // since the "0" in "0xff" would always be read first making parsing of + // since the "0" in "0xff" would always be read first making parsing of // the rest impossible. // reference: // http://sourceforge.net/projects/muparser/forums/forum/462843/topic/4824956 m_vIdentFun.push_front(a_pCallback); - } +} - //--------------------------------------------------------------------------- - void ParserTokenReader::SetVarCreator(facfun_type a_pFactory, void *pUserData) - { +//--------------------------------------------------------------------------- +void ParserTokenReader::SetVarCreator(facfun_type a_pFactory, void* pUserData) +{ m_pFactory = a_pFactory; m_pFactoryData = pUserData; - } +} - //--------------------------------------------------------------------------- - /** \brief Return the current position of the token reader in the formula string. +//--------------------------------------------------------------------------- +/** \brief Return the current position of the token reader in the formula string. - \return #m_iPos - \throw nothrow - */ - int ParserTokenReader::GetPos() const - { + \return #m_iPos + \throw nothrow +*/ +int ParserTokenReader::GetPos() const +{ return m_iPos; - } +} - //--------------------------------------------------------------------------- - /** \brief Return a reference to the formula. +//--------------------------------------------------------------------------- +/** \brief Return a reference to the formula. - \return #m_strFormula - \throw nothrow - */ - const string_type& ParserTokenReader::GetExpr() const - { + \return #m_strFormula + \throw nothrow +*/ +const string_type& ParserTokenReader::GetExpr() const +{ return m_strFormula; - } +} - //--------------------------------------------------------------------------- - /** \brief Return a map containing the used variables only. */ - varmap_type& ParserTokenReader::GetUsedVar() - { +//--------------------------------------------------------------------------- +/** \brief Return a map containing the used variables only. */ +varmap_type& ParserTokenReader::GetUsedVar() +{ return m_UsedVar; - } - - //--------------------------------------------------------------------------- - /** \brief Initialize the token Reader. - - Sets the formula position index to zero and set Syntax flags to default for initial formula parsing. - \pre [assert] triggered if a_szFormula==0 - */ - void ParserTokenReader::SetFormula(const string_type &a_strFormula) - { +} + +//--------------------------------------------------------------------------- +/** \brief Initialize the token Reader. + + Sets the formula position index to zero and set Syntax flags to default for initial formula parsing. + \pre [assert] triggered if a_szFormula==0 +*/ +void ParserTokenReader::SetFormula(const string_type& a_strFormula) +{ m_strFormula = a_strFormula; ReInit(); - } - - //--------------------------------------------------------------------------- - /** \brief Set Flag that controls behaviour in case of undefined variables being found. - - If true, the parser does not throw an exception if an undefined variable is found. - otherwise it does. This variable is used internally only! - It suppresses a "undefined variable" exception in GetUsedVar(). - Those function should return a complete list of variables including - those the are not defined by the time of it's call. - */ - void ParserTokenReader::IgnoreUndefVar(bool bIgnore) - { +} + +//--------------------------------------------------------------------------- +/** \brief Set Flag that controls behaviour in case of undefined variables being found. + + If true, the parser does not throw an exception if an undefined variable is found. + otherwise it does. This variable is used internally only! + It suppresses a "undefined variable" exception in GetUsedVar(). + Those function should return a complete list of variables including + those the are not defined by the time of it's call. +*/ +void ParserTokenReader::IgnoreUndefVar(bool bIgnore) +{ m_bIgnoreUndefVar = bIgnore; - } - - //--------------------------------------------------------------------------- - /** \brief Reset the token reader to the start of the formula. - - The syntax flags will be reset to a value appropriate for the - start of a formula. - \post #m_iPos==0, #m_iSynFlags = noOPT | noBC | noPOSTOP | noSTR - \throw nothrow - \sa ESynCodes - */ - void ParserTokenReader::ReInit() - { +} + +//--------------------------------------------------------------------------- +/** \brief Reset the token reader to the start of the formula. + + The syntax flags will be reset to a value appropriate for the + start of a formula. + \post #m_iPos==0, #m_iSynFlags = noOPT | noBC | noPOSTOP | noSTR + \throw nothrow + \sa ESynCodes +*/ +void ParserTokenReader::ReInit() +{ m_iPos = 0; m_iSynFlags = sfSTART_OF_LINE; m_iBrackets = 0; m_UsedVar.clear(); m_lastTok = token_type(); - } +} - //--------------------------------------------------------------------------- - /** \brief Read the next token from the string. */ - ParserTokenReader::token_type ParserTokenReader::ReadNextToken() - { +//--------------------------------------------------------------------------- +/** \brief Read the next token from the string. */ +ParserTokenReader::token_type ParserTokenReader::ReadNextToken() +{ assert(m_pParser); - const char_type *szFormula = m_strFormula.c_str(); + const char_type* szFormula = m_strFormula.c_str(); token_type tok; // Ignore all non printable characters when reading the expression - while (szFormula[m_iPos]>0 && szFormula[m_iPos]<=0x20) - ++m_iPos; - - if ( IsEOF(tok) ) return SaveBeforeReturn(tok); // Check for end of formula - if ( IsOprt(tok) ) return SaveBeforeReturn(tok); // Check for user defined binary operator - if ( IsFunTok(tok) ) return SaveBeforeReturn(tok); // Check for function token - if ( IsBuiltIn(tok) ) return SaveBeforeReturn(tok); // Check built in operators / tokens - if ( IsArgSep(tok) ) return SaveBeforeReturn(tok); // Check for function argument separators - if ( IsValTok(tok) ) return SaveBeforeReturn(tok); // Check for values / constant tokens - if ( IsVarTok(tok) ) return SaveBeforeReturn(tok); // Check for variable tokens - if ( IsStrVarTok(tok) ) return SaveBeforeReturn(tok); // Check for string variables - if ( IsString(tok) ) return SaveBeforeReturn(tok); // Check for String tokens - if ( IsInfixOpTok(tok) ) return SaveBeforeReturn(tok); // Check for unary operators - if ( IsPostOpTok(tok) ) return SaveBeforeReturn(tok); // Check for unary operators - - // Check String for undefined variable token. Done only if a + while (szFormula[m_iPos] > 0 && szFormula[m_iPos] <= 0x20) + ++m_iPos; + + if (IsEOF(tok)) + return SaveBeforeReturn(tok); // Check for end of formula + if (IsOprt(tok)) + return SaveBeforeReturn(tok); // Check for user defined binary operator + if (IsFunTok(tok)) + return SaveBeforeReturn(tok); // Check for function token + if (IsBuiltIn(tok)) + return SaveBeforeReturn(tok); // Check built in operators / tokens + if (IsArgSep(tok)) + return SaveBeforeReturn(tok); // Check for function argument separators + if (IsValTok(tok)) + return SaveBeforeReturn(tok); // Check for values / constant tokens + if (IsVarTok(tok)) + return SaveBeforeReturn(tok); // Check for variable tokens + if (IsStrVarTok(tok)) + return SaveBeforeReturn(tok); // Check for string variables + if (IsString(tok)) + return SaveBeforeReturn(tok); // Check for String tokens + if (IsInfixOpTok(tok)) + return SaveBeforeReturn(tok); // Check for unary operators + if (IsPostOpTok(tok)) + return SaveBeforeReturn(tok); // Check for unary operators + + // Check String for undefined variable token. Done only if a // flag is set indicating to ignore undefined variables. - // This is a way to conditionally avoid an error if - // undefined variables occur. + // This is a way to conditionally avoid an error if + // undefined variables occur. // (The GetUsedVar function must suppress the error for - // undefined variables in order to collect all variable + // undefined variables in order to collect all variable // names including the undefined ones.) - if ( (m_bIgnoreUndefVar || m_pFactory) && IsUndefVarTok(tok) ) - return SaveBeforeReturn(tok); + if ((m_bIgnoreUndefVar || m_pFactory) && IsUndefVarTok(tok)) + return SaveBeforeReturn(tok); // Check for unknown token - // + // // !!! From this point on there is no exit without an exception possible... - // + // string_type strTok; int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos); - if (iEnd!=m_iPos) - Error(ecUNASSIGNABLE_TOKEN, m_iPos, strTok); + if (iEnd != m_iPos) + Error(ecUNASSIGNABLE_TOKEN, m_iPos, strTok); Error(ecUNASSIGNABLE_TOKEN, m_iPos, m_strFormula.substr(m_iPos)); return token_type(); // never reached - } - - //--------------------------------------------------------------------------- - void ParserTokenReader::SetParent(ParserBase *a_pParent) - { - m_pParser = a_pParent; - m_pFunDef = &a_pParent->m_FunDef; - m_pOprtDef = &a_pParent->m_OprtDef; +} + +//--------------------------------------------------------------------------- +void ParserTokenReader::SetParent(ParserBase* a_pParent) +{ + m_pParser = a_pParent; + m_pFunDef = &a_pParent->m_FunDef; + m_pOprtDef = &a_pParent->m_OprtDef; m_pInfixOprtDef = &a_pParent->m_InfixOprtDef; - m_pPostOprtDef = &a_pParent->m_PostOprtDef; - m_pVarDef = &a_pParent->m_VarDef; - m_pStrVarDef = &a_pParent->m_StrVarDef; - m_pConstDef = &a_pParent->m_ConstDef; - } - - //--------------------------------------------------------------------------- - /** \brief Extract all characters that belong to a certain charset. - - \param a_szCharSet [in] Const char array of the characters allowed in the token. - \param a_strTok [out] The string that consists entirely of characters listed in a_szCharSet. - \param a_iPos [in] Position in the string from where to start reading. - \return The Position of the first character not listed in a_szCharSet. - \throw nothrow - */ - int ParserTokenReader::ExtractToken(const char_type *a_szCharSet, - string_type &a_sTok, - int a_iPos) const - { + m_pPostOprtDef = &a_pParent->m_PostOprtDef; + m_pVarDef = &a_pParent->m_VarDef; + m_pStrVarDef = &a_pParent->m_StrVarDef; + m_pConstDef = &a_pParent->m_ConstDef; +} + +//--------------------------------------------------------------------------- +/** \brief Extract all characters that belong to a certain charset. + + \param a_szCharSet [in] Const char array of the characters allowed in the token. + \param a_strTok [out] The string that consists entirely of characters listed in a_szCharSet. + \param a_iPos [in] Position in the string from where to start reading. + \return The Position of the first character not listed in a_szCharSet. + \throw nothrow +*/ +int ParserTokenReader::ExtractToken(const char_type* a_szCharSet, string_type& a_sTok, int a_iPos) const +{ int iEnd = (int)m_strFormula.find_first_not_of(a_szCharSet, a_iPos); - if (iEnd==(int)string_type::npos) + if (iEnd == (int)string_type::npos) iEnd = (int)m_strFormula.length(); - + // Assign token string if there was something found - if (a_iPos!=iEnd) - a_sTok = string_type( m_strFormula.begin()+a_iPos, m_strFormula.begin()+iEnd); + if (a_iPos != iEnd) + a_sTok = string_type(m_strFormula.begin() + a_iPos, m_strFormula.begin() + iEnd); return iEnd; - } - - //--------------------------------------------------------------------------- - /** \brief Check Expression for the presence of a binary operator token. - - Userdefined binary operator "++" gives inconsistent parsing result for - the equations "a++b" and "a ++ b" if alphabetic characters are allowed - in operator tokens. To avoid this this function checks specifically - for operator tokens. - */ - int ParserTokenReader::ExtractOperatorToken(string_type &a_sTok, - int a_iPos) const - { +} + +//--------------------------------------------------------------------------- +/** \brief Check Expression for the presence of a binary operator token. + + Userdefined binary operator "++" gives inconsistent parsing result for + the equations "a++b" and "a ++ b" if alphabetic characters are allowed + in operator tokens. To avoid this this function checks specifically + for operator tokens. +*/ +int ParserTokenReader::ExtractOperatorToken(string_type& a_sTok, int a_iPos) const +{ // Changed as per Issue 6: https://code.google.com/p/muparser/issues/detail?id=6 int iEnd = (int)m_strFormula.find_first_not_of(m_pParser->ValidOprtChars(), a_iPos); - if (iEnd==(int)string_type::npos) - iEnd = (int)m_strFormula.length(); + if (iEnd == (int)string_type::npos) + iEnd = (int)m_strFormula.length(); // Assign token string if there was something found - if (a_iPos!=iEnd) + if (a_iPos != iEnd) { - a_sTok = string_type( m_strFormula.begin() + a_iPos, m_strFormula.begin() + iEnd); - return iEnd; + a_sTok = string_type(m_strFormula.begin() + a_iPos, m_strFormula.begin() + iEnd); + return iEnd; } else { - // There is still the chance of having to deal with an operator consisting exclusively - // of alphabetic characters. - return ExtractToken(MUP_CHARS, a_sTok, a_iPos); + // There is still the chance of having to deal with an operator consisting exclusively + // of alphabetic characters. + return ExtractToken(MUP_CHARS, a_sTok, a_iPos); } - } - - //--------------------------------------------------------------------------- - /** \brief Check if a built in operator or other token can be found - \param a_Tok [out] Operator token if one is found. This can either be a binary operator or an infix operator token. - \return true if an operator token has been found. - */ - bool ParserTokenReader::IsBuiltIn(token_type &a_Tok) - { - const char_type **const pOprtDef = m_pParser->GetOprtDef(), - *const szFormula = m_strFormula.c_str(); +} + +//--------------------------------------------------------------------------- +/** \brief Check if a built in operator or other token can be found + \param a_Tok [out] Operator token if one is found. This can either be a binary operator or an infix operator token. + \return true if an operator token has been found. +*/ +bool ParserTokenReader::IsBuiltIn(token_type& a_Tok) +{ + const char_type **const pOprtDef = m_pParser->GetOprtDef(), *const szFormula = m_strFormula.c_str(); // Compare token with function and operator strings // check string for operator/function - for (int i=0; pOprtDef[i]; i++) + for (int i = 0; pOprtDef[i]; i++) { - std::size_t len( std::char_traits::length(pOprtDef[i]) ); - if ( string_type(pOprtDef[i]) == string_type(szFormula + m_iPos, szFormula + m_iPos + len) ) - { - switch(i) + std::size_t len(std::char_traits::length(pOprtDef[i])); + if (string_type(pOprtDef[i]) == string_type(szFormula + m_iPos, szFormula + m_iPos + len)) { - //case cmAND: - //case cmOR: - //case cmXOR: - case cmLAND: - case cmLOR: - case cmLT: - case cmGT: - case cmLE: - case cmGE: - case cmNEQ: - case cmEQ: - case cmADD: - case cmSUB: - case cmMUL: - case cmDIV: - case cmPOW: - case cmASSIGN: - //if (len!=sTok.length()) - // continue; - - // The assignment operator need special treatment - if (i==cmASSIGN && m_iSynFlags & noASSIGN) - Error(ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef[i]); - - if (!m_pParser->HasBuiltInOprt()) continue; - if (m_iSynFlags & noOPT) - { - // Maybe its an infix operator not an operator - // Both operator types can share characters in - // their identifiers - if ( IsInfixOpTok(a_Tok) ) - return true; - - Error(ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef[i]); - } - - m_iSynFlags = noBC | noOPT | noARG_SEP | noPOSTOP | noASSIGN | noIF | noELSE | noEND; - break; - - case cmBO: - if (m_iSynFlags & noBO) - Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]); - - if (m_lastTok.GetCode()==cmFUNC) - m_iSynFlags = noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN | noIF | noELSE; - else - m_iSynFlags = noBC | noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN| noIF | noELSE; - - ++m_iBrackets; - break; - - case cmBC: - if (m_iSynFlags & noBC) - Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]); - - m_iSynFlags = noBO | noVAR | noVAL | noFUN | noINFIXOP | noSTR | noASSIGN; - - if (--m_iBrackets<0) - Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]); - break; - - case cmELSE: - if (m_iSynFlags & noELSE) - Error(ecUNEXPECTED_CONDITIONAL, m_iPos, pOprtDef[i]); - - m_iSynFlags = noBC | noPOSTOP | noEND | noOPT | noIF | noELSE; - break; - - case cmIF: - if (m_iSynFlags & noIF) - Error(ecUNEXPECTED_CONDITIONAL, m_iPos, pOprtDef[i]); - - m_iSynFlags = noBC | noPOSTOP | noEND | noOPT | noIF | noELSE; - break; - - default: // The operator is listed in c_DefaultOprt, but not here. This is a bad thing... - Error(ecINTERNAL_ERROR); - } // switch operator id - - m_iPos += (int)len; - a_Tok.Set( (ECmdCode)i, pOprtDef[i] ); - return true; - } // if operator string found - } // end of for all operator strings - + switch (i) + { + // case cmAND: + // case cmOR: + // case cmXOR: + case cmLAND: + case cmLOR: + case cmLT: + case cmGT: + case cmLE: + case cmGE: + case cmNEQ: + case cmEQ: + case cmADD: + case cmSUB: + case cmMUL: + case cmDIV: + case cmPOW: + case cmASSIGN: + // if (len!=sTok.length()) + // continue; + + // The assignment operator need special treatment + if (i == cmASSIGN && m_iSynFlags & noASSIGN) + Error(ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef[i]); + + if (!m_pParser->HasBuiltInOprt()) + continue; + if (m_iSynFlags & noOPT) + { + // Maybe its an infix operator not an operator + // Both operator types can share characters in + // their identifiers + if (IsInfixOpTok(a_Tok)) + return true; + + Error(ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef[i]); + } + + m_iSynFlags = noBC | noOPT | noARG_SEP | noPOSTOP | noASSIGN | noIF | noELSE | noEND; + break; + + case cmBO: + if (m_iSynFlags & noBO) + Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]); + + if (m_lastTok.GetCode() == cmFUNC) + m_iSynFlags = noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN | noIF | noELSE; + else + m_iSynFlags = noBC | noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN | noIF | noELSE; + + ++m_iBrackets; + break; + + case cmBC: + if (m_iSynFlags & noBC) + Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]); + + m_iSynFlags = noBO | noVAR | noVAL | noFUN | noINFIXOP | noSTR | noASSIGN; + + if (--m_iBrackets < 0) + Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]); + break; + + case cmELSE: + if (m_iSynFlags & noELSE) + Error(ecUNEXPECTED_CONDITIONAL, m_iPos, pOprtDef[i]); + + m_iSynFlags = noBC | noPOSTOP | noEND | noOPT | noIF | noELSE; + break; + + case cmIF: + if (m_iSynFlags & noIF) + Error(ecUNEXPECTED_CONDITIONAL, m_iPos, pOprtDef[i]); + + m_iSynFlags = noBC | noPOSTOP | noEND | noOPT | noIF | noELSE; + break; + + default: // The operator is listed in c_DefaultOprt, but not here. This is a bad thing... + Error(ecINTERNAL_ERROR); + } // switch operator id + + m_iPos += (int)len; + a_Tok.Set((ECmdCode)i, pOprtDef[i]); + return true; + } // if operator string found + } // end of for all operator strings + return false; - } +} - //--------------------------------------------------------------------------- - bool ParserTokenReader::IsArgSep(token_type &a_Tok) - { +//--------------------------------------------------------------------------- +bool ParserTokenReader::IsArgSep(token_type& a_Tok) +{ const char_type* szFormula = m_strFormula.c_str(); - if (szFormula[m_iPos]==m_cArgSep) + if (szFormula[m_iPos] == m_cArgSep) { - // copy the separator into null terminated string - char_type szSep[2]; - szSep[0] = m_cArgSep; - szSep[1] = 0; - - if (m_iSynFlags & noARG_SEP) - Error(ecUNEXPECTED_ARG_SEP, m_iPos, szSep); - - m_iSynFlags = noBC | noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN; - m_iPos++; - a_Tok.Set(cmARG_SEP, szSep); - return true; + // copy the separator into null terminated string + char_type szSep[2]; + szSep[0] = m_cArgSep; + szSep[1] = 0; + + if (m_iSynFlags & noARG_SEP) + Error(ecUNEXPECTED_ARG_SEP, m_iPos, szSep); + + m_iSynFlags = noBC | noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN; + m_iPos++; + a_Tok.Set(cmARG_SEP, szSep); + return true; } return false; - } - - //--------------------------------------------------------------------------- - /** \brief Check for End of Formula. - - \return true if an end of formula is found false otherwise. - \param a_Tok [out] If an eof is found the corresponding token will be stored there. - \throw nothrow - \sa IsOprt, IsFunTok, IsStrFunTok, IsValTok, IsVarTok, IsString, IsInfixOpTok, IsPostOpTok - */ - bool ParserTokenReader::IsEOF(token_type &a_Tok) - { +} + +//--------------------------------------------------------------------------- +/** \brief Check for End of Formula. + + \return true if an end of formula is found false otherwise. + \param a_Tok [out] If an eof is found the corresponding token will be stored there. + \throw nothrow + \sa IsOprt, IsFunTok, IsStrFunTok, IsValTok, IsVarTok, IsString, IsInfixOpTok, IsPostOpTok +*/ +bool ParserTokenReader::IsEOF(token_type& a_Tok) +{ const char_type* szFormula = m_strFormula.c_str(); // check for EOF - if ( !szFormula[m_iPos] /*|| szFormula[m_iPos] == '\n'*/) + if (!szFormula[m_iPos] /*|| szFormula[m_iPos] == '\n'*/) { - if ( m_iSynFlags & noEND ) - Error(ecUNEXPECTED_EOF, m_iPos); + if (m_iSynFlags & noEND) + Error(ecUNEXPECTED_EOF, m_iPos); - if (m_iBrackets>0) - Error(ecMISSING_PARENS, m_iPos, _T(")")); + if (m_iBrackets > 0) + Error(ecMISSING_PARENS, m_iPos, _T(")")); - m_iSynFlags = 0; - a_Tok.Set(cmEND); - return true; + m_iSynFlags = 0; + a_Tok.Set(cmEND); + return true; } return false; - } - - //--------------------------------------------------------------------------- - /** \brief Check if a string position contains a unary infix operator. - \return true if a function token has been found false otherwise. - */ - bool ParserTokenReader::IsInfixOpTok(token_type &a_Tok) - { +} + +//--------------------------------------------------------------------------- +/** \brief Check if a string position contains a unary infix operator. + \return true if a function token has been found false otherwise. +*/ +bool ParserTokenReader::IsInfixOpTok(token_type& a_Tok) +{ string_type sTok; int iEnd = ExtractToken(m_pParser->ValidInfixOprtChars(), sTok, m_iPos); - if (iEnd==m_iPos) - return false; + if (iEnd == m_iPos) + return false; // iterate over all postfix operator strings funmap_type::const_reverse_iterator it = m_pInfixOprtDef->rbegin(); - for ( ; it!=m_pInfixOprtDef->rend(); ++it) + for (; it != m_pInfixOprtDef->rend(); ++it) { - if (sTok.find(it->first)!=0) - continue; + if (sTok.find(it->first) != 0) + continue; - a_Tok.Set(it->second, it->first); - m_iPos += (int)it->first.length(); + a_Tok.Set(it->second, it->first); + m_iPos += (int)it->first.length(); - if (m_iSynFlags & noINFIXOP) - Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString()); + if (m_iSynFlags & noINFIXOP) + Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString()); - m_iSynFlags = noPOSTOP | noINFIXOP | noOPT | noBC | noSTR | noASSIGN; - return true; + m_iSynFlags = noPOSTOP | noINFIXOP | noOPT | noBC | noSTR | noASSIGN; + return true; } return false; -/* - a_Tok.Set(item->second, sTok); - m_iPos = (int)iEnd; + /* + a_Tok.Set(item->second, sTok); + m_iPos = (int)iEnd; - if (m_iSynFlags & noINFIXOP) - Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString()); + if (m_iSynFlags & noINFIXOP) + Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString()); - m_iSynFlags = noPOSTOP | noINFIXOP | noOPT | noBC | noSTR | noASSIGN; - return true; + m_iSynFlags = noPOSTOP | noINFIXOP | noOPT | noBC | noSTR | noASSIGN; + return true; + */ +} + +//--------------------------------------------------------------------------- +/** \brief Check whether the token at a given position is a function token. + \param a_Tok [out] If a value token is found it will be placed here. + \throw ParserException if Syntaxflags do not allow a function at a_iPos + \return true if a function token has been found false otherwise. + \pre [assert] m_pParser!=0 */ - } - - //--------------------------------------------------------------------------- - /** \brief Check whether the token at a given position is a function token. - \param a_Tok [out] If a value token is found it will be placed here. - \throw ParserException if Syntaxflags do not allow a function at a_iPos - \return true if a function token has been found false otherwise. - \pre [assert] m_pParser!=0 - */ - bool ParserTokenReader::IsFunTok(token_type &a_Tok) - { +bool ParserTokenReader::IsFunTok(token_type& a_Tok) +{ string_type strTok; int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos); - if (iEnd==m_iPos) - return false; + if (iEnd == m_iPos) + return false; funmap_type::const_iterator item = m_pFunDef->find(strTok); - if (item==m_pFunDef->end()) - return false; + if (item == m_pFunDef->end()) + return false; // Check if the next sign is an opening bracket - const char_type *szFormula = m_strFormula.c_str(); - if (szFormula[iEnd]!='(') - return false; + const char_type* szFormula = m_strFormula.c_str(); + if (szFormula[iEnd] != '(') + return false; a_Tok.Set(item->second, strTok); m_iPos = (int)iEnd; if (m_iSynFlags & noFUN) - Error(ecUNEXPECTED_FUN, m_iPos-(int)a_Tok.GetAsString().length(), a_Tok.GetAsString()); + Error(ecUNEXPECTED_FUN, m_iPos - (int)a_Tok.GetAsString().length(), a_Tok.GetAsString()); m_iSynFlags = noANY ^ noBO; return true; - } - - //--------------------------------------------------------------------------- - /** \brief Check if a string position contains a binary operator. - \param a_Tok [out] Operator token if one is found. This can either be a binary operator or an infix operator token. - \return true if an operator token has been found. - */ - bool ParserTokenReader::IsOprt(token_type &a_Tok) - { - const char_type *const szExpr = m_strFormula.c_str(); +} + +//--------------------------------------------------------------------------- +/** \brief Check if a string position contains a binary operator. + \param a_Tok [out] Operator token if one is found. This can either be a binary operator or an infix operator token. + \return true if an operator token has been found. +*/ +bool ParserTokenReader::IsOprt(token_type& a_Tok) +{ + const char_type* const szExpr = m_strFormula.c_str(); string_type strTok; int iEnd = ExtractOperatorToken(strTok, m_iPos); - if (iEnd==m_iPos) - return false; + if (iEnd == m_iPos) + return false; // Check if the operator is a built in operator, if so ignore it here - const char_type **const pOprtDef = m_pParser->GetOprtDef(); - for (int i=0; m_pParser->HasBuiltInOprt() && pOprtDef[i]; ++i) + const char_type** const pOprtDef = m_pParser->GetOprtDef(); + for (int i = 0; m_pParser->HasBuiltInOprt() && pOprtDef[i]; ++i) { - if (string_type(pOprtDef[i])==strTok) - return false; + if (string_type(pOprtDef[i]) == strTok) + return false; } // Note: // All tokens in oprt_bin_maptype are have been sorted by their length // Long operators must come first! Otherwise short names (like: "add") that - // are part of long token names (like: "add123") will be found instead + // are part of long token names (like: "add123") will be found instead // of the long ones. // Length sorting is done with ascending length so we use a reverse iterator here. funmap_type::const_reverse_iterator it = m_pOprtDef->rbegin(); - for ( ; it!=m_pOprtDef->rend(); ++it) + for (; it != m_pOprtDef->rend(); ++it) { - const string_type &sID = it->first; - if ( sID == string_type(szExpr + m_iPos, szExpr + m_iPos + sID.length()) ) - { - a_Tok.Set(it->second, strTok); - - // operator was found - if (m_iSynFlags & noOPT) + const string_type& sID = it->first; + if (sID == string_type(szExpr + m_iPos, szExpr + m_iPos + sID.length())) { - // An operator was found but is not expected to occur at - // this position of the formula, maybe it is an infix - // operator, not a binary operator. Both operator types - // can share characters in their identifiers. - if ( IsInfixOpTok(a_Tok) ) + a_Tok.Set(it->second, strTok); + + // operator was found + if (m_iSynFlags & noOPT) + { + // An operator was found but is not expected to occur at + // this position of the formula, maybe it is an infix + // operator, not a binary operator. Both operator types + // can share characters in their identifiers. + if (IsInfixOpTok(a_Tok)) + return true; + else + { + // nope, no infix operator + return false; + // Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString()); + } + } + + m_iPos += (int)sID.length(); + m_iSynFlags = noBC | noOPT | noARG_SEP | noPOSTOP | noEND | noASSIGN; return true; - else - { - // nope, no infix operator - return false; - //Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString()); - } - } - - m_iPos += (int)sID.length(); - m_iSynFlags = noBC | noOPT | noARG_SEP | noPOSTOP | noEND | noASSIGN; - return true; - } } return false; - } +} - //--------------------------------------------------------------------------- - /** \brief Check if a string position contains a unary post value operator. */ - bool ParserTokenReader::IsPostOpTok(token_type &a_Tok) - { +//--------------------------------------------------------------------------- +/** \brief Check if a string position contains a unary post value operator. */ +bool ParserTokenReader::IsPostOpTok(token_type& a_Tok) +{ // Do not check for postfix operators if they are not allowed at // the current expression index. // - // This will fix the bug reported here: + // This will fix the bug reported here: // // http://sourceforge.net/tracker/index.php?func=detail&aid=3343891&group_id=137191&atid=737979 // if (m_iSynFlags & noPOSTOP) - return false; + return false; // // Tricky problem with equations like "3m+5": - // m is a postfix operator, + is a valid sign for postfix operators and - // for binary operators parser detects "m+" as operator string and + // m is a postfix operator, + is a valid sign for postfix operators and + // for binary operators parser detects "m+" as operator string and // finds no matching postfix operator. - // + // // This is a special case so this routine slightly differs from the other // token readers. - + // Test if there could be a postfix operator string_type sTok; int iEnd = ExtractToken(m_pParser->ValidOprtChars(), sTok, m_iPos); - if (iEnd==m_iPos) - return false; + if (iEnd == m_iPos) + return false; // iterate over all postfix operator strings funmap_type::const_reverse_iterator it = m_pPostOprtDef->rbegin(); - for ( ; it!=m_pPostOprtDef->rend(); ++it) + for (; it != m_pPostOprtDef->rend(); ++it) { - if (sTok.find(it->first)!=0) - continue; + if (sTok.find(it->first) != 0) + continue; - a_Tok.Set(it->second, sTok); - m_iPos += (int)it->first.length(); + a_Tok.Set(it->second, sTok); + m_iPos += (int)it->first.length(); - m_iSynFlags = noVAL | noVAR | noFUN | noBO | noPOSTOP | noSTR | noASSIGN; - return true; + m_iSynFlags = noVAL | noVAR | noFUN | noBO | noPOSTOP | noSTR | noASSIGN; + return true; } return false; - } +} - //--------------------------------------------------------------------------- - /** \brief Check whether the token at a given position is a value token. +//--------------------------------------------------------------------------- +/** \brief Check whether the token at a given position is a value token. - Value tokens are either values or constants. + Value tokens are either values or constants. - \param a_Tok [out] If a value token is found it will be placed here. - \return true if a value token has been found. - */ - bool ParserTokenReader::IsValTok(token_type &a_Tok) - { + \param a_Tok [out] If a value token is found it will be placed here. + \return true if a value token has been found. +*/ +bool ParserTokenReader::IsValTok(token_type& a_Tok) +{ assert(m_pConstDef); assert(m_pParser); string_type strTok; value_type fVal(0); int iEnd(0); - + // 2.) Check for user defined constant // Read everything that could be a constant name iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos); - if (iEnd!=m_iPos) + if (iEnd != m_iPos) { - valmap_type::const_iterator item = m_pConstDef->find(strTok); - if (item!=m_pConstDef->end()) - { - m_iPos = iEnd; - a_Tok.SetVal(item->second, strTok); + valmap_type::const_iterator item = m_pConstDef->find(strTok); + if (item != m_pConstDef->end()) + { + m_iPos = iEnd; + a_Tok.SetVal(item->second, strTok); - if (m_iSynFlags & noVAL) - Error(ecUNEXPECTED_VAL, m_iPos - (int)strTok.length(), strTok); + if (m_iSynFlags & noVAL) + Error(ecUNEXPECTED_VAL, m_iPos - (int)strTok.length(), strTok); - m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN; - return true; - } + m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN; + return true; + } } // 3.call the value recognition functions provided by the user // Call user defined value recognition functions std::list::const_iterator item = m_vIdentFun.begin(); - for (item = m_vIdentFun.begin(); item!=m_vIdentFun.end(); ++item) + for (item = m_vIdentFun.begin(); item != m_vIdentFun.end(); ++item) { - int iStart = m_iPos; - if ( (*item)(m_strFormula.c_str() + m_iPos, &m_iPos, &fVal)==1 ) - { - // 2013-11-27 Issue 2: https://code.google.com/p/muparser/issues/detail?id=2 - strTok.assign(m_strFormula.c_str(), iStart, m_iPos-iStart); + int iStart = m_iPos; + if ((*item)(m_strFormula.c_str() + m_iPos, &m_iPos, &fVal) == 1) + { + // 2013-11-27 Issue 2: https://code.google.com/p/muparser/issues/detail?id=2 + strTok.assign(m_strFormula.c_str(), iStart, m_iPos - iStart); - if (m_iSynFlags & noVAL) - Error(ecUNEXPECTED_VAL, m_iPos - (int)strTok.length(), strTok); + if (m_iSynFlags & noVAL) + Error(ecUNEXPECTED_VAL, m_iPos - (int)strTok.length(), strTok); - a_Tok.SetVal(fVal, strTok); - m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN; - return true; - } + a_Tok.SetVal(fVal, strTok); + m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN; + return true; + } } return false; - } - - //--------------------------------------------------------------------------- - /** \brief Check wheter a token at a given position is a variable token. - \param a_Tok [out] If a variable token has been found it will be placed here. - \return true if a variable token has been found. - */ - bool ParserTokenReader::IsVarTok(token_type &a_Tok) - { +} + +//--------------------------------------------------------------------------- +/** \brief Check wheter a token at a given position is a variable token. + \param a_Tok [out] If a variable token has been found it will be placed here. + \return true if a variable token has been found. +*/ +bool ParserTokenReader::IsVarTok(token_type& a_Tok) +{ if (m_pVarDef->empty()) - return false; + return false; string_type strTok; int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos); - if (iEnd==m_iPos) - return false; + if (iEnd == m_iPos) + return false; - varmap_type::const_iterator item = m_pVarDef->find(strTok); - if (item==m_pVarDef->end()) - return false; + varmap_type::const_iterator item = m_pVarDef->find(strTok); + if (item == m_pVarDef->end()) + return false; if (m_iSynFlags & noVAR) - Error(ecUNEXPECTED_VAR, m_iPos, strTok); + Error(ecUNEXPECTED_VAR, m_iPos, strTok); m_pParser->OnDetectVar(&m_strFormula, m_iPos, iEnd); m_iPos = iEnd; a_Tok.SetVar(item->second, strTok); - m_UsedVar[item->first] = item->second; // Add variable to used-var-list + m_UsedVar[item->first] = item->second; // Add variable to used-var-list m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR; -// Zur Info hier die SynFlags von IsVal(): -// m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN; + // Zur Info hier die SynFlags von IsVal(): + // m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN; return true; - } +} - //--------------------------------------------------------------------------- - bool ParserTokenReader::IsStrVarTok(token_type &a_Tok) - { +//--------------------------------------------------------------------------- +bool ParserTokenReader::IsStrVarTok(token_type& a_Tok) +{ if (!m_pStrVarDef || m_pStrVarDef->empty()) - return false; + return false; string_type strTok; int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos); - if (iEnd==m_iPos) - return false; + if (iEnd == m_iPos) + return false; - strmap_type::const_iterator item = m_pStrVarDef->find(strTok); - if (item==m_pStrVarDef->end()) - return false; + strmap_type::const_iterator item = m_pStrVarDef->find(strTok); + if (item == m_pStrVarDef->end()) + return false; if (m_iSynFlags & noSTR) - Error(ecUNEXPECTED_VAR, m_iPos, strTok); + Error(ecUNEXPECTED_VAR, m_iPos, strTok); m_iPos = iEnd; if (!m_pParser->m_vStringVarBuf.size()) - Error(ecINTERNAL_ERROR); + Error(ecINTERNAL_ERROR); - a_Tok.SetString(m_pParser->m_vStringVarBuf[item->second], m_pParser->m_vStringVarBuf.size() ); + a_Tok.SetString(m_pParser->m_vStringVarBuf[item->second], m_pParser->m_vStringVarBuf.size()); - m_iSynFlags = noANY ^ ( noBC | noOPT | noEND | noARG_SEP); + m_iSynFlags = noANY ^ (noBC | noOPT | noEND | noARG_SEP); return true; - } - +} - //--------------------------------------------------------------------------- - /** \brief Check wheter a token at a given position is an undefined variable. +//--------------------------------------------------------------------------- +/** \brief Check wheter a token at a given position is an undefined variable. - \param a_Tok [out] If a variable tom_pParser->m_vStringBufken has been found it will be placed here. - \return true if a variable token has been found. - \throw nothrow - */ - bool ParserTokenReader::IsUndefVarTok(token_type &a_Tok) - { + \param a_Tok [out] If a variable tom_pParser->m_vStringBufken has been found it will be placed here. + \return true if a variable token has been found. + \throw nothrow +*/ +bool ParserTokenReader::IsUndefVarTok(token_type& a_Tok) +{ string_type strTok; - int iEnd( ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos) ); - if ( iEnd==m_iPos ) - return false; + int iEnd(ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos)); + if (iEnd == m_iPos) + return false; if (m_iSynFlags & noVAR) { - // 20061021 added token string strTok instead of a_Tok.GetAsString() as the - // token identifier. - // related bug report: - // http://sourceforge.net/tracker/index.php?func=detail&aid=1578779&group_id=137191&atid=737979 - Error(ecUNEXPECTED_VAR, m_iPos - (int)a_Tok.GetAsString().length(), strTok); + // 20061021 added token string strTok instead of a_Tok.GetAsString() as the + // token identifier. + // related bug report: + // http://sourceforge.net/tracker/index.php?func=detail&aid=1578779&group_id=137191&atid=737979 + Error(ecUNEXPECTED_VAR, m_iPos - (int)a_Tok.GetAsString().length(), strTok); } // If a factory is available implicitely create new variables if (m_pFactory) { - value_type *fVar = m_pFactory(strTok.c_str(), m_pFactoryData); - a_Tok.SetVar(fVar, strTok ); - - // Do not use m_pParser->DefineVar( strTok, fVar ); - // in order to define the new variable, it will clear the - // m_UsedVar array which will kill previously defined variables - // from the list - // This is safe because the new variable can never override an existing one - // because they are checked first! - (*m_pVarDef)[strTok] = fVar; - m_UsedVar[strTok] = fVar; // Add variable to used-var-list + value_type* fVar = m_pFactory(strTok.c_str(), m_pFactoryData); + a_Tok.SetVar(fVar, strTok); + + // Do not use m_pParser->DefineVar( strTok, fVar ); + // in order to define the new variable, it will clear the + // m_UsedVar array which will kill previously defined variables + // from the list + // This is safe because the new variable can never override an existing one + // because they are checked first! + (*m_pVarDef)[strTok] = fVar; + m_UsedVar[strTok] = fVar; // Add variable to used-var-list } else { - a_Tok.SetVar((value_type*)&m_fZero, strTok); - m_UsedVar[strTok] = 0; // Add variable to used-var-list + a_Tok.SetVar((value_type*)&m_fZero, strTok); + m_UsedVar[strTok] = 0; // Add variable to used-var-list } m_iPos = iEnd; @@ -883,76 +887,74 @@ namespace mu // Call the variable factory in order to let it define a new parser variable m_iSynFlags = noVAL | noVAR | noFUN | noBO | noPOSTOP | noINFIXOP | noSTR; return true; - } - - - //--------------------------------------------------------------------------- - /** \brief Check wheter a token at a given position is a string. - \param a_Tok [out] If a variable token has been found it will be placed here. - \return true if a string token has been found. - \sa IsOprt, IsFunTok, IsStrFunTok, IsValTok, IsVarTok, IsEOF, IsInfixOpTok, IsPostOpTok - \throw nothrow - */ - bool ParserTokenReader::IsString(token_type &a_Tok) - { - if (m_strFormula[m_iPos]!='"') - return false; - - string_type strBuf(&m_strFormula[m_iPos+1]); +} + +//--------------------------------------------------------------------------- +/** \brief Check wheter a token at a given position is a string. + \param a_Tok [out] If a variable token has been found it will be placed here. + \return true if a string token has been found. + \sa IsOprt, IsFunTok, IsStrFunTok, IsValTok, IsVarTok, IsEOF, IsInfixOpTok, IsPostOpTok + \throw nothrow +*/ +bool ParserTokenReader::IsString(token_type& a_Tok) +{ + if (m_strFormula[m_iPos] != '"') + return false; + + string_type strBuf(&m_strFormula[m_iPos + 1]); std::size_t iEnd(0), iSkip(0); // parser over escaped '\"' end replace them with '"' - for(iEnd=(int)strBuf.find( _T("\"") ); iEnd!=0 && iEnd!=string_type::npos; iEnd=(int)strBuf.find( _T("\""), iEnd)) + for (iEnd = (int)strBuf.find(_T("\"")); iEnd != 0 && iEnd != string_type::npos; + iEnd = (int)strBuf.find(_T("\""), iEnd)) { - if (strBuf[iEnd-1]!='\\') break; - strBuf.replace(iEnd-1, 2, _T("\"") ); - iSkip++; + if (strBuf[iEnd - 1] != '\\') + break; + strBuf.replace(iEnd - 1, 2, _T("\"")); + iSkip++; } - if (iEnd==string_type::npos) - Error(ecUNTERMINATED_STRING, m_iPos, _T("\"") ); + if (iEnd == string_type::npos) + Error(ecUNTERMINATED_STRING, m_iPos, _T("\"")); - string_type strTok(strBuf.begin(), strBuf.begin()+iEnd); + string_type strTok(strBuf.begin(), strBuf.begin() + iEnd); if (m_iSynFlags & noSTR) - Error(ecUNEXPECTED_STR, m_iPos, strTok); + Error(ecUNEXPECTED_STR, m_iPos, strTok); - m_pParser->m_vStringBuf.push_back(strTok); // Store string in internal buffer + m_pParser->m_vStringBuf.push_back(strTok); // Store string in internal buffer a_Tok.SetString(strTok, m_pParser->m_vStringBuf.size()); - m_iPos += (int)strTok.length() + 2 + (int)iSkip; // +2 wg Anführungszeichen; +iSkip für entfernte escape zeichen - m_iSynFlags = noANY ^ ( noARG_SEP | noBC | noOPT | noEND ); + m_iPos += (int)strTok.length() + 2 + (int)iSkip; // +2 wg Anführungszeichen; +iSkip für entfernte escape zeichen + m_iSynFlags = noANY ^ (noARG_SEP | noBC | noOPT | noEND); return true; - } - - //--------------------------------------------------------------------------- - /** \brief Create an error containing the parse error position. - - This function will create an Parser Exception object containing the error text and its position. - - \param a_iErrc [in] The error code of type #EErrorCodes. - \param a_iPos [in] The position where the error was detected. - \param a_strTok [in] The token string representation associated with the error. - \throw ParserException always throws thats the only purpose of this function. - */ - void ParserTokenReader::Error( EErrorCodes a_iErrc, - int a_iPos, - const string_type &a_sTok) const - { +} + +//--------------------------------------------------------------------------- +/** \brief Create an error containing the parse error position. + + This function will create an Parser Exception object containing the error text and its position. + + \param a_iErrc [in] The error code of type #EErrorCodes. + \param a_iPos [in] The position where the error was detected. + \param a_strTok [in] The token string representation associated with the error. + \throw ParserException always throws thats the only purpose of this function. +*/ +void ParserTokenReader::Error(EErrorCodes a_iErrc, int a_iPos, const string_type& a_sTok) const +{ m_pParser->Error(a_iErrc, a_iPos, a_sTok); - } +} - //--------------------------------------------------------------------------- - void ParserTokenReader::SetArgSep(char_type cArgSep) - { +//--------------------------------------------------------------------------- +void ParserTokenReader::SetArgSep(char_type cArgSep) +{ m_cArgSep = cArgSep; - } +} - //--------------------------------------------------------------------------- - char_type ParserTokenReader::GetArgSep() const - { +//--------------------------------------------------------------------------- +char_type ParserTokenReader::GetArgSep() const +{ return m_cArgSep; - } +} } // namespace mu - diff --git a/ext_libs/muparser/muParserTokenReader.h b/ext_libs/muparser/muParserTokenReader.h old mode 100755 new mode 100644 index 9d96225d..5ac4e598 --- a/ext_libs/muparser/muParserTokenReader.h +++ b/ext_libs/muparser/muParserTokenReader.h @@ -1,26 +1,26 @@ /* - __________ - _____ __ __\______ \_____ _______ ______ ____ _______ + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ - |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| - \/ \/ \/ \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ Copyright (C) 2004-2013 Ingo Berg - Permission is hereby granted, free of charge, to any person obtaining a copy of this + 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 + 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 + 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. + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MU_PARSER_TOKEN_READER_H @@ -42,120 +42,110 @@ \brief This file contains the parser token reader definition. */ - namespace mu { - // Forward declaration - class ParserBase; - - /** \brief Token reader for the ParserBase class. - - */ - class ParserTokenReader - { - private: - - typedef ParserToken token_type; - - public: - - ParserTokenReader(ParserBase *a_pParent); - ParserTokenReader* Clone(ParserBase *a_pParent) const; - - void AddValIdent(identfun_type a_pCallback); - void SetVarCreator(facfun_type a_pFactory, void *pUserData); - void SetFormula(const string_type &a_strFormula); - void SetArgSep(char_type cArgSep); - - int GetPos() const; - const string_type& GetExpr() const; - varmap_type& GetUsedVar(); - char_type GetArgSep() const; - - void IgnoreUndefVar(bool bIgnore); - void ReInit(); - token_type ReadNextToken(); - - private: - - /** \brief Syntax codes. - - The syntax codes control the syntax check done during the first time parsing of - the expression string. They are flags that indicate which tokens are allowed next - if certain tokens are identified. - */ - enum ESynCodes - { - noBO = 1 << 0, ///< to avoid i.e. "cos(7)(" - noBC = 1 << 1, ///< to avoid i.e. "sin)" or "()" - noVAL = 1 << 2, ///< to avoid i.e. "tan 2" or "sin(8)3.14" - noVAR = 1 << 3, ///< to avoid i.e. "sin a" or "sin(8)a" - noARG_SEP = 1 << 4, ///< to avoid i.e. ",," or "+," ... - noFUN = 1 << 5, ///< to avoid i.e. "sqrt cos" or "(1)sin" - noOPT = 1 << 6, ///< to avoid i.e. "(+)" - noPOSTOP = 1 << 7, ///< to avoid i.e. "(5!!)" "sin!" - noINFIXOP = 1 << 8, ///< to avoid i.e. "++4" "!!4" - noEND = 1 << 9, ///< to avoid unexpected end of formula - noSTR = 1 << 10, ///< to block numeric arguments on string functions - noASSIGN = 1 << 11, ///< to block assignement to constant i.e. "4=7" - noIF = 1 << 12, - noELSE = 1 << 13, +// Forward declaration +class ParserBase; + +/** \brief Token reader for the ParserBase class. + +*/ +class ParserTokenReader +{ +private: + typedef ParserToken token_type; + +public: + ParserTokenReader(ParserBase* a_pParent); + ParserTokenReader* Clone(ParserBase* a_pParent) const; + + void AddValIdent(identfun_type a_pCallback); + void SetVarCreator(facfun_type a_pFactory, void* pUserData); + void SetFormula(const string_type& a_strFormula); + void SetArgSep(char_type cArgSep); + + int GetPos() const; + const string_type& GetExpr() const; + varmap_type& GetUsedVar(); + char_type GetArgSep() const; + + void IgnoreUndefVar(bool bIgnore); + void ReInit(); + token_type ReadNextToken(); + +private: + /** \brief Syntax codes. + + The syntax codes control the syntax check done during the first time parsing of + the expression string. They are flags that indicate which tokens are allowed next + if certain tokens are identified. + */ + enum ESynCodes + { + noBO = 1 << 0, ///< to avoid i.e. "cos(7)(" + noBC = 1 << 1, ///< to avoid i.e. "sin)" or "()" + noVAL = 1 << 2, ///< to avoid i.e. "tan 2" or "sin(8)3.14" + noVAR = 1 << 3, ///< to avoid i.e. "sin a" or "sin(8)a" + noARG_SEP = 1 << 4, ///< to avoid i.e. ",," or "+," ... + noFUN = 1 << 5, ///< to avoid i.e. "sqrt cos" or "(1)sin" + noOPT = 1 << 6, ///< to avoid i.e. "(+)" + noPOSTOP = 1 << 7, ///< to avoid i.e. "(5!!)" "sin!" + noINFIXOP = 1 << 8, ///< to avoid i.e. "++4" "!!4" + noEND = 1 << 9, ///< to avoid unexpected end of formula + noSTR = 1 << 10, ///< to block numeric arguments on string functions + noASSIGN = 1 << 11, ///< to block assignement to constant i.e. "4=7" + noIF = 1 << 12, + noELSE = 1 << 13, sfSTART_OF_LINE = noOPT | noBC | noPOSTOP | noASSIGN | noIF | noELSE | noARG_SEP, - noANY = ~0 ///< All of he above flags set - }; - - ParserTokenReader(const ParserTokenReader &a_Reader); - ParserTokenReader& operator=(const ParserTokenReader &a_Reader); - void Assign(const ParserTokenReader &a_Reader); - - void SetParent(ParserBase *a_pParent); - int ExtractToken(const char_type *a_szCharSet, - string_type &a_strTok, - int a_iPos) const; - int ExtractOperatorToken(string_type &a_sTok, int a_iPos) const; - - bool IsBuiltIn(token_type &a_Tok); - bool IsArgSep(token_type &a_Tok); - bool IsEOF(token_type &a_Tok); - bool IsInfixOpTok(token_type &a_Tok); - bool IsFunTok(token_type &a_Tok); - bool IsPostOpTok(token_type &a_Tok); - bool IsOprt(token_type &a_Tok); - bool IsValTok(token_type &a_Tok); - bool IsVarTok(token_type &a_Tok); - bool IsStrVarTok(token_type &a_Tok); - bool IsUndefVarTok(token_type &a_Tok); - bool IsString(token_type &a_Tok); - void Error(EErrorCodes a_iErrc, - int a_iPos = -1, - const string_type &a_sTok = string_type() ) const; - - token_type& SaveBeforeReturn(const token_type &tok); - - ParserBase *m_pParser; - string_type m_strFormula; - int m_iPos; - int m_iSynFlags; - bool m_bIgnoreUndefVar; - - const funmap_type *m_pFunDef; - const funmap_type *m_pPostOprtDef; - const funmap_type *m_pInfixOprtDef; - const funmap_type *m_pOprtDef; - const valmap_type *m_pConstDef; - const strmap_type *m_pStrVarDef; - varmap_type *m_pVarDef; ///< The only non const pointer to parser internals - facfun_type m_pFactory; - void *m_pFactoryData; - std::list m_vIdentFun; ///< Value token identification function - varmap_type m_UsedVar; - value_type m_fZero; ///< Dummy value of zero, referenced by undefined variables - int m_iBrackets; - token_type m_lastTok; - char_type m_cArgSep; ///< The character used for separating function arguments - }; + noANY = ~0 ///< All of he above flags set + }; + + ParserTokenReader(const ParserTokenReader& a_Reader); + ParserTokenReader& operator=(const ParserTokenReader& a_Reader); + void Assign(const ParserTokenReader& a_Reader); + + void SetParent(ParserBase* a_pParent); + int ExtractToken(const char_type* a_szCharSet, string_type& a_strTok, int a_iPos) const; + int ExtractOperatorToken(string_type& a_sTok, int a_iPos) const; + + bool IsBuiltIn(token_type& a_Tok); + bool IsArgSep(token_type& a_Tok); + bool IsEOF(token_type& a_Tok); + bool IsInfixOpTok(token_type& a_Tok); + bool IsFunTok(token_type& a_Tok); + bool IsPostOpTok(token_type& a_Tok); + bool IsOprt(token_type& a_Tok); + bool IsValTok(token_type& a_Tok); + bool IsVarTok(token_type& a_Tok); + bool IsStrVarTok(token_type& a_Tok); + bool IsUndefVarTok(token_type& a_Tok); + bool IsString(token_type& a_Tok); + void Error(EErrorCodes a_iErrc, int a_iPos = -1, const string_type& a_sTok = string_type()) const; + + token_type& SaveBeforeReturn(const token_type& tok); + + ParserBase* m_pParser; + string_type m_strFormula; + int m_iPos; + int m_iSynFlags; + bool m_bIgnoreUndefVar; + + const funmap_type* m_pFunDef; + const funmap_type* m_pPostOprtDef; + const funmap_type* m_pInfixOprtDef; + const funmap_type* m_pOprtDef; + const valmap_type* m_pConstDef; + const strmap_type* m_pStrVarDef; + varmap_type* m_pVarDef; ///< The only non const pointer to parser internals + facfun_type m_pFactory; + void* m_pFactoryData; + std::list m_vIdentFun; ///< Value token identification function + varmap_type m_UsedVar; + value_type m_fZero; ///< Dummy value of zero, referenced by undefined variables + int m_iBrackets; + token_type m_lastTok; + char_type m_cArgSep; ///< The character used for separating function arguments +}; } // namespace mu #endif - - diff --git a/ext_libs/sqlite/sqlite3.h b/ext_libs/sqlite/sqlite3.h index 34636b9b..16f81c2f 100644 --- a/ext_libs/sqlite/sqlite3.h +++ b/ext_libs/sqlite/sqlite3.h @@ -32,16 +32,16 @@ */ #ifndef SQLITE3_H #define SQLITE3_H -#include /* Needed for the definition of va_list */ +#include /* Needed for the definition of va_list */ /* ** Make sure we can call this stuff from C++. */ #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif - /* ** Facilitate override of interface linkage and calling conventions. ** Be aware that these macros may not be used within this particular @@ -69,25 +69,25 @@ extern "C" { ** that require non-default calling conventions. */ #ifndef SQLITE_EXTERN -# define SQLITE_EXTERN extern +#define SQLITE_EXTERN extern #endif #ifndef SQLITE_API -# define SQLITE_API +#define SQLITE_API #endif #ifndef SQLITE_CDECL -# define SQLITE_CDECL +#define SQLITE_CDECL #endif #ifndef SQLITE_APICALL -# define SQLITE_APICALL +#define SQLITE_APICALL #endif #ifndef SQLITE_STDCALL -# define SQLITE_STDCALL SQLITE_APICALL +#define SQLITE_STDCALL SQLITE_APICALL #endif #ifndef SQLITE_CALLBACK -# define SQLITE_CALLBACK +#define SQLITE_CALLBACK #endif #ifndef SQLITE_SYSAPI -# define SQLITE_SYSAPI +#define SQLITE_SYSAPI #endif /* @@ -110,10 +110,10 @@ extern "C" { ** Ensure these symbols were not defined by some previous header file. */ #ifdef SQLITE_VERSION -# undef SQLITE_VERSION +#undef SQLITE_VERSION #endif #ifdef SQLITE_VERSION_NUMBER -# undef SQLITE_VERSION_NUMBER +#undef SQLITE_VERSION_NUMBER #endif /* @@ -146,46 +146,46 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.38.0" +#define SQLITE_VERSION "3.38.0" #define SQLITE_VERSION_NUMBER 3038000 -#define SQLITE_SOURCE_ID "2022-02-22 18:58:40 40fa792d359f84c3b9e9d6623743e1a59826274e221df1bde8f47086968a1bab" - -/* -** CAPI3REF: Run-Time Library Version Numbers -** KEYWORDS: sqlite3_version sqlite3_sourceid -** -** These interfaces provide the same information as the [SQLITE_VERSION], -** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros -** but are associated with the library instead of the header file. ^(Cautious -** programmers might include assert() statements in their application to -** verify that values returned by these interfaces match the macros in -** the header, and thus ensure that the application is -** compiled with matching library and header files. -** -**
-** assert( sqlite3_libversion_number()==SQLITE_VERSION_NUMBER );
-** assert( strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,80)==0 );
-** assert( strcmp(sqlite3_libversion(),SQLITE_VERSION)==0 );
-** 
)^ -** -** ^The sqlite3_version[] string constant contains the text of [SQLITE_VERSION] -** macro. ^The sqlite3_libversion() function returns a pointer to the -** to the sqlite3_version[] string constant. The sqlite3_libversion() -** function is provided for use in DLLs since DLL users usually do not have -** direct access to string constants within the DLL. ^The -** sqlite3_libversion_number() function returns an integer equal to -** [SQLITE_VERSION_NUMBER]. ^(The sqlite3_sourceid() function returns -** a pointer to a string constant whose value is the same as the -** [SQLITE_SOURCE_ID] C preprocessor macro. Except if SQLite is built -** using an edited copy of [the amalgamation], then the last four characters -** of the hash might be different from [SQLITE_SOURCE_ID].)^ -** -** See also: [sqlite_version()] and [sqlite_source_id()]. -*/ -SQLITE_API SQLITE_EXTERN const char sqlite3_version[]; -SQLITE_API const char *sqlite3_libversion(void); -SQLITE_API const char *sqlite3_sourceid(void); -SQLITE_API int sqlite3_libversion_number(void); +#define SQLITE_SOURCE_ID "2022-02-22 18:58:40 40fa792d359f84c3b9e9d6623743e1a59826274e221df1bde8f47086968a1bab" + + /* + ** CAPI3REF: Run-Time Library Version Numbers + ** KEYWORDS: sqlite3_version sqlite3_sourceid + ** + ** These interfaces provide the same information as the [SQLITE_VERSION], + ** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros + ** but are associated with the library instead of the header file. ^(Cautious + ** programmers might include assert() statements in their application to + ** verify that values returned by these interfaces match the macros in + ** the header, and thus ensure that the application is + ** compiled with matching library and header files. + ** + **
+    ** assert( sqlite3_libversion_number()==SQLITE_VERSION_NUMBER );
+    ** assert( strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,80)==0 );
+    ** assert( strcmp(sqlite3_libversion(),SQLITE_VERSION)==0 );
+    ** 
)^ + ** + ** ^The sqlite3_version[] string constant contains the text of [SQLITE_VERSION] + ** macro. ^The sqlite3_libversion() function returns a pointer to the + ** to the sqlite3_version[] string constant. The sqlite3_libversion() + ** function is provided for use in DLLs since DLL users usually do not have + ** direct access to string constants within the DLL. ^The + ** sqlite3_libversion_number() function returns an integer equal to + ** [SQLITE_VERSION_NUMBER]. ^(The sqlite3_sourceid() function returns + ** a pointer to a string constant whose value is the same as the + ** [SQLITE_SOURCE_ID] C preprocessor macro. Except if SQLite is built + ** using an edited copy of [the amalgamation], then the last four characters + ** of the hash might be different from [SQLITE_SOURCE_ID].)^ + ** + ** See also: [sqlite_version()] and [sqlite_source_id()]. + */ + SQLITE_API SQLITE_EXTERN const char sqlite3_version[]; + SQLITE_API const char* sqlite3_libversion(void); + SQLITE_API const char* sqlite3_sourceid(void); + SQLITE_API int sqlite3_libversion_number(void); /* ** CAPI3REF: Run-Time Library Compilation Options Diagnostics @@ -210,66 +210,66 @@ SQLITE_API int sqlite3_libversion_number(void); ** [sqlite_compileoption_get()] and the [compile_options pragma]. */ #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS -SQLITE_API int sqlite3_compileoption_used(const char *zOptName); -SQLITE_API const char *sqlite3_compileoption_get(int N); + SQLITE_API int sqlite3_compileoption_used(const char* zOptName); + SQLITE_API const char* sqlite3_compileoption_get(int N); #else -# define sqlite3_compileoption_used(X) 0 -# define sqlite3_compileoption_get(X) ((void*)0) +#define sqlite3_compileoption_used(X) 0 +#define sqlite3_compileoption_get(X) ((void*)0) #endif -/* -** CAPI3REF: Test To See If The Library Is Threadsafe -** -** ^The sqlite3_threadsafe() function returns zero if and only if -** SQLite was compiled with mutexing code omitted due to the -** [SQLITE_THREADSAFE] compile-time option being set to 0. -** -** SQLite can be compiled with or without mutexes. When -** the [SQLITE_THREADSAFE] C preprocessor macro is 1 or 2, mutexes -** are enabled and SQLite is threadsafe. When the -** [SQLITE_THREADSAFE] macro is 0, -** the mutexes are omitted. Without the mutexes, it is not safe -** to use SQLite concurrently from more than one thread. -** -** Enabling mutexes incurs a measurable performance penalty. -** So if speed is of utmost importance, it makes sense to disable -** the mutexes. But for maximum safety, mutexes should be enabled. -** ^The default behavior is for mutexes to be enabled. -** -** This interface can be used by an application to make sure that the -** version of SQLite that it is linking against was compiled with -** the desired setting of the [SQLITE_THREADSAFE] macro. -** -** This interface only reports on the compile-time mutex setting -** of the [SQLITE_THREADSAFE] flag. If SQLite is compiled with -** SQLITE_THREADSAFE=1 or =2 then mutexes are enabled by default but -** can be fully or partially disabled using a call to [sqlite3_config()] -** with the verbs [SQLITE_CONFIG_SINGLETHREAD], [SQLITE_CONFIG_MULTITHREAD], -** or [SQLITE_CONFIG_SERIALIZED]. ^(The return value of the -** sqlite3_threadsafe() function shows only the compile-time setting of -** thread safety, not any run-time changes to that setting made by -** sqlite3_config(). In other words, the return value from sqlite3_threadsafe() -** is unchanged by calls to sqlite3_config().)^ -** -** See the [threading mode] documentation for additional information. -*/ -SQLITE_API int sqlite3_threadsafe(void); - -/* -** CAPI3REF: Database Connection Handle -** KEYWORDS: {database connection} {database connections} -** -** Each open SQLite database is represented by a pointer to an instance of -** the opaque structure named "sqlite3". It is useful to think of an sqlite3 -** pointer as an object. The [sqlite3_open()], [sqlite3_open16()], and -** [sqlite3_open_v2()] interfaces are its constructors, and [sqlite3_close()] -** and [sqlite3_close_v2()] are its destructors. There are many other -** interfaces (such as -** [sqlite3_prepare_v2()], [sqlite3_create_function()], and -** [sqlite3_busy_timeout()] to name but three) that are methods on an -** sqlite3 object. -*/ -typedef struct sqlite3 sqlite3; + /* + ** CAPI3REF: Test To See If The Library Is Threadsafe + ** + ** ^The sqlite3_threadsafe() function returns zero if and only if + ** SQLite was compiled with mutexing code omitted due to the + ** [SQLITE_THREADSAFE] compile-time option being set to 0. + ** + ** SQLite can be compiled with or without mutexes. When + ** the [SQLITE_THREADSAFE] C preprocessor macro is 1 or 2, mutexes + ** are enabled and SQLite is threadsafe. When the + ** [SQLITE_THREADSAFE] macro is 0, + ** the mutexes are omitted. Without the mutexes, it is not safe + ** to use SQLite concurrently from more than one thread. + ** + ** Enabling mutexes incurs a measurable performance penalty. + ** So if speed is of utmost importance, it makes sense to disable + ** the mutexes. But for maximum safety, mutexes should be enabled. + ** ^The default behavior is for mutexes to be enabled. + ** + ** This interface can be used by an application to make sure that the + ** version of SQLite that it is linking against was compiled with + ** the desired setting of the [SQLITE_THREADSAFE] macro. + ** + ** This interface only reports on the compile-time mutex setting + ** of the [SQLITE_THREADSAFE] flag. If SQLite is compiled with + ** SQLITE_THREADSAFE=1 or =2 then mutexes are enabled by default but + ** can be fully or partially disabled using a call to [sqlite3_config()] + ** with the verbs [SQLITE_CONFIG_SINGLETHREAD], [SQLITE_CONFIG_MULTITHREAD], + ** or [SQLITE_CONFIG_SERIALIZED]. ^(The return value of the + ** sqlite3_threadsafe() function shows only the compile-time setting of + ** thread safety, not any run-time changes to that setting made by + ** sqlite3_config(). In other words, the return value from sqlite3_threadsafe() + ** is unchanged by calls to sqlite3_config().)^ + ** + ** See the [threading mode] documentation for additional information. + */ + SQLITE_API int sqlite3_threadsafe(void); + + /* + ** CAPI3REF: Database Connection Handle + ** KEYWORDS: {database connection} {database connections} + ** + ** Each open SQLite database is represented by a pointer to an instance of + ** the opaque structure named "sqlite3". It is useful to think of an sqlite3 + ** pointer as an object. The [sqlite3_open()], [sqlite3_open16()], and + ** [sqlite3_open_v2()] interfaces are its constructors, and [sqlite3_close()] + ** and [sqlite3_close_v2()] are its destructors. There are many other + ** interfaces (such as + ** [sqlite3_prepare_v2()], [sqlite3_create_function()], and + ** [sqlite3_busy_timeout()] to name but three) that are methods on an + ** sqlite3 object. + */ + typedef struct sqlite3 sqlite3; /* ** CAPI3REF: 64-Bit Integer Types @@ -288,147 +288,146 @@ typedef struct sqlite3 sqlite3; ** between 0 and +18446744073709551615 inclusive. */ #ifdef SQLITE_INT64_TYPE - typedef SQLITE_INT64_TYPE sqlite_int64; -# ifdef SQLITE_UINT64_TYPE + typedef SQLITE_INT64_TYPE sqlite_int64; +#ifdef SQLITE_UINT64_TYPE typedef SQLITE_UINT64_TYPE sqlite_uint64; -# else +#else typedef unsigned SQLITE_INT64_TYPE sqlite_uint64; -# endif +#endif #elif defined(_MSC_VER) || defined(__BORLANDC__) - typedef __int64 sqlite_int64; - typedef unsigned __int64 sqlite_uint64; +typedef __int64 sqlite_int64; +typedef unsigned __int64 sqlite_uint64; #else - typedef long long int sqlite_int64; - typedef unsigned long long int sqlite_uint64; +typedef long long int sqlite_int64; +typedef unsigned long long int sqlite_uint64; #endif -typedef sqlite_int64 sqlite3_int64; -typedef sqlite_uint64 sqlite3_uint64; + typedef sqlite_int64 sqlite3_int64; + typedef sqlite_uint64 sqlite3_uint64; /* ** If compiling for a processor that lacks floating point support, ** substitute integer for floating-point. */ #ifdef SQLITE_OMIT_FLOATING_POINT -# define double sqlite3_int64 +#define double sqlite3_int64 #endif -/* -** CAPI3REF: Closing A Database Connection -** DESTRUCTOR: sqlite3 -** -** ^The sqlite3_close() and sqlite3_close_v2() routines are destructors -** for the [sqlite3] object. -** ^Calls to sqlite3_close() and sqlite3_close_v2() return [SQLITE_OK] if -** the [sqlite3] object is successfully destroyed and all associated -** resources are deallocated. -** -** Ideally, applications should [sqlite3_finalize | finalize] all -** [prepared statements], [sqlite3_blob_close | close] all [BLOB handles], and -** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated -** with the [sqlite3] object prior to attempting to close the object. -** ^If the database connection is associated with unfinalized prepared -** statements, BLOB handlers, and/or unfinished sqlite3_backup objects then -** sqlite3_close() will leave the database connection open and return -** [SQLITE_BUSY]. ^If sqlite3_close_v2() is called with unfinalized prepared -** statements, unclosed BLOB handlers, and/or unfinished sqlite3_backups, -** it returns [SQLITE_OK] regardless, but instead of deallocating the database -** connection immediately, it marks the database connection as an unusable -** "zombie" and makes arrangements to automatically deallocate the database -** connection after all prepared statements are finalized, all BLOB handles -** are closed, and all backups have finished. The sqlite3_close_v2() interface -** is intended for use with host languages that are garbage collected, and -** where the order in which destructors are called is arbitrary. -** -** ^If an [sqlite3] object is destroyed while a transaction is open, -** the transaction is automatically rolled back. -** -** The C parameter to [sqlite3_close(C)] and [sqlite3_close_v2(C)] -** must be either a NULL -** pointer or an [sqlite3] object pointer obtained -** from [sqlite3_open()], [sqlite3_open16()], or -** [sqlite3_open_v2()], and not previously closed. -** ^Calling sqlite3_close() or sqlite3_close_v2() with a NULL pointer -** argument is a harmless no-op. -*/ -SQLITE_API int sqlite3_close(sqlite3*); -SQLITE_API int sqlite3_close_v2(sqlite3*); - -/* -** The type for a callback function. -** This is legacy and deprecated. It is included for historical -** compatibility and is not documented. -*/ -typedef int (*sqlite3_callback)(void*,int,char**, char**); - -/* -** CAPI3REF: One-Step Query Execution Interface -** METHOD: sqlite3 -** -** The sqlite3_exec() interface is a convenience wrapper around -** [sqlite3_prepare_v2()], [sqlite3_step()], and [sqlite3_finalize()], -** that allows an application to run multiple statements of SQL -** without having to use a lot of C code. -** -** ^The sqlite3_exec() interface runs zero or more UTF-8 encoded, -** semicolon-separate SQL statements passed into its 2nd argument, -** in the context of the [database connection] passed in as its 1st -** argument. ^If the callback function of the 3rd argument to -** sqlite3_exec() is not NULL, then it is invoked for each result row -** coming out of the evaluated SQL statements. ^The 4th argument to -** sqlite3_exec() is relayed through to the 1st argument of each -** callback invocation. ^If the callback pointer to sqlite3_exec() -** is NULL, then no callback is ever invoked and result rows are -** ignored. -** -** ^If an error occurs while evaluating the SQL statements passed into -** sqlite3_exec(), then execution of the current statement stops and -** subsequent statements are skipped. ^If the 5th parameter to sqlite3_exec() -** is not NULL then any error message is written into memory obtained -** from [sqlite3_malloc()] and passed back through the 5th parameter. -** To avoid memory leaks, the application should invoke [sqlite3_free()] -** on error message strings returned through the 5th parameter of -** sqlite3_exec() after the error message string is no longer needed. -** ^If the 5th parameter to sqlite3_exec() is not NULL and no errors -** occur, then sqlite3_exec() sets the pointer in its 5th parameter to -** NULL before returning. -** -** ^If an sqlite3_exec() callback returns non-zero, the sqlite3_exec() -** routine returns SQLITE_ABORT without invoking the callback again and -** without running any subsequent SQL statements. -** -** ^The 2nd argument to the sqlite3_exec() callback function is the -** number of columns in the result. ^The 3rd argument to the sqlite3_exec() -** callback is an array of pointers to strings obtained as if from -** [sqlite3_column_text()], one for each column. ^If an element of a -** result row is NULL then the corresponding string pointer for the -** sqlite3_exec() callback is a NULL pointer. ^The 4th argument to the -** sqlite3_exec() callback is an array of pointers to strings where each -** entry represents the name of corresponding result column as obtained -** from [sqlite3_column_name()]. -** -** ^If the 2nd parameter to sqlite3_exec() is a NULL pointer, a pointer -** to an empty string, or a pointer that contains only whitespace and/or -** SQL comments, then no SQL statements are evaluated and the database -** is not changed. -** -** Restrictions: -** -**
    -**
  • The application must ensure that the 1st parameter to sqlite3_exec() -** is a valid and open [database connection]. -**
  • The application must not close the [database connection] specified by -** the 1st parameter to sqlite3_exec() while sqlite3_exec() is running. -**
  • The application must not modify the SQL statement text passed into -** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running. -**
-*/ -SQLITE_API int sqlite3_exec( - sqlite3*, /* An open database */ - const char *sql, /* SQL to be evaluated */ - int (*callback)(void*,int,char**,char**), /* Callback function */ - void *, /* 1st argument to callback */ - char **errmsg /* Error msg written here */ -); + /* + ** CAPI3REF: Closing A Database Connection + ** DESTRUCTOR: sqlite3 + ** + ** ^The sqlite3_close() and sqlite3_close_v2() routines are destructors + ** for the [sqlite3] object. + ** ^Calls to sqlite3_close() and sqlite3_close_v2() return [SQLITE_OK] if + ** the [sqlite3] object is successfully destroyed and all associated + ** resources are deallocated. + ** + ** Ideally, applications should [sqlite3_finalize | finalize] all + ** [prepared statements], [sqlite3_blob_close | close] all [BLOB handles], and + ** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated + ** with the [sqlite3] object prior to attempting to close the object. + ** ^If the database connection is associated with unfinalized prepared + ** statements, BLOB handlers, and/or unfinished sqlite3_backup objects then + ** sqlite3_close() will leave the database connection open and return + ** [SQLITE_BUSY]. ^If sqlite3_close_v2() is called with unfinalized prepared + ** statements, unclosed BLOB handlers, and/or unfinished sqlite3_backups, + ** it returns [SQLITE_OK] regardless, but instead of deallocating the database + ** connection immediately, it marks the database connection as an unusable + ** "zombie" and makes arrangements to automatically deallocate the database + ** connection after all prepared statements are finalized, all BLOB handles + ** are closed, and all backups have finished. The sqlite3_close_v2() interface + ** is intended for use with host languages that are garbage collected, and + ** where the order in which destructors are called is arbitrary. + ** + ** ^If an [sqlite3] object is destroyed while a transaction is open, + ** the transaction is automatically rolled back. + ** + ** The C parameter to [sqlite3_close(C)] and [sqlite3_close_v2(C)] + ** must be either a NULL + ** pointer or an [sqlite3] object pointer obtained + ** from [sqlite3_open()], [sqlite3_open16()], or + ** [sqlite3_open_v2()], and not previously closed. + ** ^Calling sqlite3_close() or sqlite3_close_v2() with a NULL pointer + ** argument is a harmless no-op. + */ + SQLITE_API int sqlite3_close(sqlite3*); + SQLITE_API int sqlite3_close_v2(sqlite3*); + + /* + ** The type for a callback function. + ** This is legacy and deprecated. It is included for historical + ** compatibility and is not documented. + */ + typedef int (*sqlite3_callback)(void*, int, char**, char**); + + /* + ** CAPI3REF: One-Step Query Execution Interface + ** METHOD: sqlite3 + ** + ** The sqlite3_exec() interface is a convenience wrapper around + ** [sqlite3_prepare_v2()], [sqlite3_step()], and [sqlite3_finalize()], + ** that allows an application to run multiple statements of SQL + ** without having to use a lot of C code. + ** + ** ^The sqlite3_exec() interface runs zero or more UTF-8 encoded, + ** semicolon-separate SQL statements passed into its 2nd argument, + ** in the context of the [database connection] passed in as its 1st + ** argument. ^If the callback function of the 3rd argument to + ** sqlite3_exec() is not NULL, then it is invoked for each result row + ** coming out of the evaluated SQL statements. ^The 4th argument to + ** sqlite3_exec() is relayed through to the 1st argument of each + ** callback invocation. ^If the callback pointer to sqlite3_exec() + ** is NULL, then no callback is ever invoked and result rows are + ** ignored. + ** + ** ^If an error occurs while evaluating the SQL statements passed into + ** sqlite3_exec(), then execution of the current statement stops and + ** subsequent statements are skipped. ^If the 5th parameter to sqlite3_exec() + ** is not NULL then any error message is written into memory obtained + ** from [sqlite3_malloc()] and passed back through the 5th parameter. + ** To avoid memory leaks, the application should invoke [sqlite3_free()] + ** on error message strings returned through the 5th parameter of + ** sqlite3_exec() after the error message string is no longer needed. + ** ^If the 5th parameter to sqlite3_exec() is not NULL and no errors + ** occur, then sqlite3_exec() sets the pointer in its 5th parameter to + ** NULL before returning. + ** + ** ^If an sqlite3_exec() callback returns non-zero, the sqlite3_exec() + ** routine returns SQLITE_ABORT without invoking the callback again and + ** without running any subsequent SQL statements. + ** + ** ^The 2nd argument to the sqlite3_exec() callback function is the + ** number of columns in the result. ^The 3rd argument to the sqlite3_exec() + ** callback is an array of pointers to strings obtained as if from + ** [sqlite3_column_text()], one for each column. ^If an element of a + ** result row is NULL then the corresponding string pointer for the + ** sqlite3_exec() callback is a NULL pointer. ^The 4th argument to the + ** sqlite3_exec() callback is an array of pointers to strings where each + ** entry represents the name of corresponding result column as obtained + ** from [sqlite3_column_name()]. + ** + ** ^If the 2nd parameter to sqlite3_exec() is a NULL pointer, a pointer + ** to an empty string, or a pointer that contains only whitespace and/or + ** SQL comments, then no SQL statements are evaluated and the database + ** is not changed. + ** + ** Restrictions: + ** + **
    + **
  • The application must ensure that the 1st parameter to sqlite3_exec() + ** is a valid and open [database connection]. + **
  • The application must not close the [database connection] specified by + ** the 1st parameter to sqlite3_exec() while sqlite3_exec() is running. + **
  • The application must not modify the SQL statement text passed into + ** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running. + **
+ */ + SQLITE_API int sqlite3_exec(sqlite3*, /* An open database */ + const char* sql, /* SQL to be evaluated */ + int (*callback)(void*, int, char**, char**), /* Callback function */ + void*, /* 1st argument to callback */ + char** errmsg /* Error msg written here */ + ); /* ** CAPI3REF: Result Codes @@ -441,38 +440,38 @@ SQLITE_API int sqlite3_exec( ** ** See also: [extended result code definitions] */ -#define SQLITE_OK 0 /* Successful result */ +#define SQLITE_OK 0 /* Successful result */ /* beginning-of-error-codes */ -#define SQLITE_ERROR 1 /* Generic error */ -#define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */ -#define SQLITE_PERM 3 /* Access permission denied */ -#define SQLITE_ABORT 4 /* Callback routine requested an abort */ -#define SQLITE_BUSY 5 /* The database file is locked */ -#define SQLITE_LOCKED 6 /* A table in the database is locked */ -#define SQLITE_NOMEM 7 /* A malloc() failed */ -#define SQLITE_READONLY 8 /* Attempt to write a readonly database */ -#define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite3_interrupt()*/ -#define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */ -#define SQLITE_CORRUPT 11 /* The database disk image is malformed */ -#define SQLITE_NOTFOUND 12 /* Unknown opcode in sqlite3_file_control() */ -#define SQLITE_FULL 13 /* Insertion failed because database is full */ -#define SQLITE_CANTOPEN 14 /* Unable to open the database file */ -#define SQLITE_PROTOCOL 15 /* Database lock protocol error */ -#define SQLITE_EMPTY 16 /* Internal use only */ -#define SQLITE_SCHEMA 17 /* The database schema changed */ -#define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */ -#define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */ -#define SQLITE_MISMATCH 20 /* Data type mismatch */ -#define SQLITE_MISUSE 21 /* Library used incorrectly */ -#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */ -#define SQLITE_AUTH 23 /* Authorization denied */ -#define SQLITE_FORMAT 24 /* Not used */ -#define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */ -#define SQLITE_NOTADB 26 /* File opened that is not a database file */ -#define SQLITE_NOTICE 27 /* Notifications from sqlite3_log() */ -#define SQLITE_WARNING 28 /* Warnings from sqlite3_log() */ -#define SQLITE_ROW 100 /* sqlite3_step() has another row ready */ -#define SQLITE_DONE 101 /* sqlite3_step() has finished executing */ +#define SQLITE_ERROR 1 /* Generic error */ +#define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */ +#define SQLITE_PERM 3 /* Access permission denied */ +#define SQLITE_ABORT 4 /* Callback routine requested an abort */ +#define SQLITE_BUSY 5 /* The database file is locked */ +#define SQLITE_LOCKED 6 /* A table in the database is locked */ +#define SQLITE_NOMEM 7 /* A malloc() failed */ +#define SQLITE_READONLY 8 /* Attempt to write a readonly database */ +#define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite3_interrupt()*/ +#define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */ +#define SQLITE_CORRUPT 11 /* The database disk image is malformed */ +#define SQLITE_NOTFOUND 12 /* Unknown opcode in sqlite3_file_control() */ +#define SQLITE_FULL 13 /* Insertion failed because database is full */ +#define SQLITE_CANTOPEN 14 /* Unable to open the database file */ +#define SQLITE_PROTOCOL 15 /* Database lock protocol error */ +#define SQLITE_EMPTY 16 /* Internal use only */ +#define SQLITE_SCHEMA 17 /* The database schema changed */ +#define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */ +#define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */ +#define SQLITE_MISMATCH 20 /* Data type mismatch */ +#define SQLITE_MISUSE 21 /* Library used incorrectly */ +#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */ +#define SQLITE_AUTH 23 /* Authorization denied */ +#define SQLITE_FORMAT 24 /* Not used */ +#define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */ +#define SQLITE_NOTADB 26 /* File opened that is not a database file */ +#define SQLITE_NOTICE 27 /* Notifications from sqlite3_log() */ +#define SQLITE_WARNING 28 /* Warnings from sqlite3_log() */ +#define SQLITE_ROW 100 /* sqlite3_step() has another row ready */ +#define SQLITE_DONE 101 /* sqlite3_step() has finished executing */ /* end-of-error-codes */ /* @@ -492,81 +491,81 @@ SQLITE_API int sqlite3_exec( ** the most recent error can be obtained using ** [sqlite3_extended_errcode()]. */ -#define SQLITE_ERROR_MISSING_COLLSEQ (SQLITE_ERROR | (1<<8)) -#define SQLITE_ERROR_RETRY (SQLITE_ERROR | (2<<8)) -#define SQLITE_ERROR_SNAPSHOT (SQLITE_ERROR | (3<<8)) -#define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8)) -#define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8)) -#define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8)) -#define SQLITE_IOERR_FSYNC (SQLITE_IOERR | (4<<8)) -#define SQLITE_IOERR_DIR_FSYNC (SQLITE_IOERR | (5<<8)) -#define SQLITE_IOERR_TRUNCATE (SQLITE_IOERR | (6<<8)) -#define SQLITE_IOERR_FSTAT (SQLITE_IOERR | (7<<8)) -#define SQLITE_IOERR_UNLOCK (SQLITE_IOERR | (8<<8)) -#define SQLITE_IOERR_RDLOCK (SQLITE_IOERR | (9<<8)) -#define SQLITE_IOERR_DELETE (SQLITE_IOERR | (10<<8)) -#define SQLITE_IOERR_BLOCKED (SQLITE_IOERR | (11<<8)) -#define SQLITE_IOERR_NOMEM (SQLITE_IOERR | (12<<8)) -#define SQLITE_IOERR_ACCESS (SQLITE_IOERR | (13<<8)) -#define SQLITE_IOERR_CHECKRESERVEDLOCK (SQLITE_IOERR | (14<<8)) -#define SQLITE_IOERR_LOCK (SQLITE_IOERR | (15<<8)) -#define SQLITE_IOERR_CLOSE (SQLITE_IOERR | (16<<8)) -#define SQLITE_IOERR_DIR_CLOSE (SQLITE_IOERR | (17<<8)) -#define SQLITE_IOERR_SHMOPEN (SQLITE_IOERR | (18<<8)) -#define SQLITE_IOERR_SHMSIZE (SQLITE_IOERR | (19<<8)) -#define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20<<8)) -#define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21<<8)) -#define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8)) -#define SQLITE_IOERR_DELETE_NOENT (SQLITE_IOERR | (23<<8)) -#define SQLITE_IOERR_MMAP (SQLITE_IOERR | (24<<8)) -#define SQLITE_IOERR_GETTEMPPATH (SQLITE_IOERR | (25<<8)) -#define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26<<8)) -#define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27<<8)) -#define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8)) -#define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29<<8)) -#define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8)) -#define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8)) -#define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8)) -#define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33<<8)) -#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) -#define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8)) -#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) -#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8)) -#define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3<<8)) -#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) -#define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8)) -#define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8)) -#define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4<<8)) -#define SQLITE_CANTOPEN_DIRTYWAL (SQLITE_CANTOPEN | (5<<8)) /* Not Used */ -#define SQLITE_CANTOPEN_SYMLINK (SQLITE_CANTOPEN | (6<<8)) -#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) -#define SQLITE_CORRUPT_SEQUENCE (SQLITE_CORRUPT | (2<<8)) -#define SQLITE_CORRUPT_INDEX (SQLITE_CORRUPT | (3<<8)) -#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8)) -#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8)) -#define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8)) -#define SQLITE_READONLY_DBMOVED (SQLITE_READONLY | (4<<8)) -#define SQLITE_READONLY_CANTINIT (SQLITE_READONLY | (5<<8)) -#define SQLITE_READONLY_DIRECTORY (SQLITE_READONLY | (6<<8)) -#define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8)) -#define SQLITE_CONSTRAINT_CHECK (SQLITE_CONSTRAINT | (1<<8)) -#define SQLITE_CONSTRAINT_COMMITHOOK (SQLITE_CONSTRAINT | (2<<8)) -#define SQLITE_CONSTRAINT_FOREIGNKEY (SQLITE_CONSTRAINT | (3<<8)) -#define SQLITE_CONSTRAINT_FUNCTION (SQLITE_CONSTRAINT | (4<<8)) -#define SQLITE_CONSTRAINT_NOTNULL (SQLITE_CONSTRAINT | (5<<8)) -#define SQLITE_CONSTRAINT_PRIMARYKEY (SQLITE_CONSTRAINT | (6<<8)) -#define SQLITE_CONSTRAINT_TRIGGER (SQLITE_CONSTRAINT | (7<<8)) -#define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8<<8)) -#define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8)) -#define SQLITE_CONSTRAINT_ROWID (SQLITE_CONSTRAINT |(10<<8)) -#define SQLITE_CONSTRAINT_PINNED (SQLITE_CONSTRAINT |(11<<8)) -#define SQLITE_CONSTRAINT_DATATYPE (SQLITE_CONSTRAINT |(12<<8)) -#define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8)) -#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8)) -#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8)) -#define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8)) -#define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8)) -#define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8)) /* internal use only */ +#define SQLITE_ERROR_MISSING_COLLSEQ (SQLITE_ERROR | (1 << 8)) +#define SQLITE_ERROR_RETRY (SQLITE_ERROR | (2 << 8)) +#define SQLITE_ERROR_SNAPSHOT (SQLITE_ERROR | (3 << 8)) +#define SQLITE_IOERR_READ (SQLITE_IOERR | (1 << 8)) +#define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2 << 8)) +#define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3 << 8)) +#define SQLITE_IOERR_FSYNC (SQLITE_IOERR | (4 << 8)) +#define SQLITE_IOERR_DIR_FSYNC (SQLITE_IOERR | (5 << 8)) +#define SQLITE_IOERR_TRUNCATE (SQLITE_IOERR | (6 << 8)) +#define SQLITE_IOERR_FSTAT (SQLITE_IOERR | (7 << 8)) +#define SQLITE_IOERR_UNLOCK (SQLITE_IOERR | (8 << 8)) +#define SQLITE_IOERR_RDLOCK (SQLITE_IOERR | (9 << 8)) +#define SQLITE_IOERR_DELETE (SQLITE_IOERR | (10 << 8)) +#define SQLITE_IOERR_BLOCKED (SQLITE_IOERR | (11 << 8)) +#define SQLITE_IOERR_NOMEM (SQLITE_IOERR | (12 << 8)) +#define SQLITE_IOERR_ACCESS (SQLITE_IOERR | (13 << 8)) +#define SQLITE_IOERR_CHECKRESERVEDLOCK (SQLITE_IOERR | (14 << 8)) +#define SQLITE_IOERR_LOCK (SQLITE_IOERR | (15 << 8)) +#define SQLITE_IOERR_CLOSE (SQLITE_IOERR | (16 << 8)) +#define SQLITE_IOERR_DIR_CLOSE (SQLITE_IOERR | (17 << 8)) +#define SQLITE_IOERR_SHMOPEN (SQLITE_IOERR | (18 << 8)) +#define SQLITE_IOERR_SHMSIZE (SQLITE_IOERR | (19 << 8)) +#define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20 << 8)) +#define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21 << 8)) +#define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22 << 8)) +#define SQLITE_IOERR_DELETE_NOENT (SQLITE_IOERR | (23 << 8)) +#define SQLITE_IOERR_MMAP (SQLITE_IOERR | (24 << 8)) +#define SQLITE_IOERR_GETTEMPPATH (SQLITE_IOERR | (25 << 8)) +#define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26 << 8)) +#define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27 << 8)) +#define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28 << 8)) +#define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29 << 8)) +#define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30 << 8)) +#define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31 << 8)) +#define SQLITE_IOERR_DATA (SQLITE_IOERR | (32 << 8)) +#define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33 << 8)) +#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1 << 8)) +#define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2 << 8)) +#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1 << 8)) +#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2 << 8)) +#define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3 << 8)) +#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1 << 8)) +#define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2 << 8)) +#define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3 << 8)) +#define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4 << 8)) +#define SQLITE_CANTOPEN_DIRTYWAL (SQLITE_CANTOPEN | (5 << 8)) /* Not Used */ +#define SQLITE_CANTOPEN_SYMLINK (SQLITE_CANTOPEN | (6 << 8)) +#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1 << 8)) +#define SQLITE_CORRUPT_SEQUENCE (SQLITE_CORRUPT | (2 << 8)) +#define SQLITE_CORRUPT_INDEX (SQLITE_CORRUPT | (3 << 8)) +#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1 << 8)) +#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2 << 8)) +#define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3 << 8)) +#define SQLITE_READONLY_DBMOVED (SQLITE_READONLY | (4 << 8)) +#define SQLITE_READONLY_CANTINIT (SQLITE_READONLY | (5 << 8)) +#define SQLITE_READONLY_DIRECTORY (SQLITE_READONLY | (6 << 8)) +#define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2 << 8)) +#define SQLITE_CONSTRAINT_CHECK (SQLITE_CONSTRAINT | (1 << 8)) +#define SQLITE_CONSTRAINT_COMMITHOOK (SQLITE_CONSTRAINT | (2 << 8)) +#define SQLITE_CONSTRAINT_FOREIGNKEY (SQLITE_CONSTRAINT | (3 << 8)) +#define SQLITE_CONSTRAINT_FUNCTION (SQLITE_CONSTRAINT | (4 << 8)) +#define SQLITE_CONSTRAINT_NOTNULL (SQLITE_CONSTRAINT | (5 << 8)) +#define SQLITE_CONSTRAINT_PRIMARYKEY (SQLITE_CONSTRAINT | (6 << 8)) +#define SQLITE_CONSTRAINT_TRIGGER (SQLITE_CONSTRAINT | (7 << 8)) +#define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8 << 8)) +#define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9 << 8)) +#define SQLITE_CONSTRAINT_ROWID (SQLITE_CONSTRAINT | (10 << 8)) +#define SQLITE_CONSTRAINT_PINNED (SQLITE_CONSTRAINT | (11 << 8)) +#define SQLITE_CONSTRAINT_DATATYPE (SQLITE_CONSTRAINT | (12 << 8)) +#define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1 << 8)) +#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2 << 8)) +#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1 << 8)) +#define SQLITE_AUTH_USER (SQLITE_AUTH | (1 << 8)) +#define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1 << 8)) +#define SQLITE_OK_SYMLINK (SQLITE_OK | (2 << 8)) /* internal use only */ /* ** CAPI3REF: Flags For File Open Operations @@ -588,33 +587,32 @@ SQLITE_API int sqlite3_exec( ** [sqlite3_open_v2()] has historically be a no-op and might become an ** error in future versions of SQLite. */ -#define SQLITE_OPEN_READONLY 0x00000001 /* Ok for sqlite3_open_v2() */ -#define SQLITE_OPEN_READWRITE 0x00000002 /* Ok for sqlite3_open_v2() */ -#define SQLITE_OPEN_CREATE 0x00000004 /* Ok for sqlite3_open_v2() */ -#define SQLITE_OPEN_DELETEONCLOSE 0x00000008 /* VFS only */ -#define SQLITE_OPEN_EXCLUSIVE 0x00000010 /* VFS only */ -#define SQLITE_OPEN_AUTOPROXY 0x00000020 /* VFS only */ -#define SQLITE_OPEN_URI 0x00000040 /* Ok for sqlite3_open_v2() */ -#define SQLITE_OPEN_MEMORY 0x00000080 /* Ok for sqlite3_open_v2() */ -#define SQLITE_OPEN_MAIN_DB 0x00000100 /* VFS only */ -#define SQLITE_OPEN_TEMP_DB 0x00000200 /* VFS only */ -#define SQLITE_OPEN_TRANSIENT_DB 0x00000400 /* VFS only */ -#define SQLITE_OPEN_MAIN_JOURNAL 0x00000800 /* VFS only */ -#define SQLITE_OPEN_TEMP_JOURNAL 0x00001000 /* VFS only */ -#define SQLITE_OPEN_SUBJOURNAL 0x00002000 /* VFS only */ -#define SQLITE_OPEN_SUPER_JOURNAL 0x00004000 /* VFS only */ -#define SQLITE_OPEN_NOMUTEX 0x00008000 /* Ok for sqlite3_open_v2() */ -#define SQLITE_OPEN_FULLMUTEX 0x00010000 /* Ok for sqlite3_open_v2() */ -#define SQLITE_OPEN_SHAREDCACHE 0x00020000 /* Ok for sqlite3_open_v2() */ -#define SQLITE_OPEN_PRIVATECACHE 0x00040000 /* Ok for sqlite3_open_v2() */ -#define SQLITE_OPEN_WAL 0x00080000 /* VFS only */ -#define SQLITE_OPEN_NOFOLLOW 0x01000000 /* Ok for sqlite3_open_v2() */ -#define SQLITE_OPEN_EXRESCODE 0x02000000 /* Extended result codes */ +#define SQLITE_OPEN_READONLY 0x00000001 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_READWRITE 0x00000002 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_CREATE 0x00000004 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_DELETEONCLOSE 0x00000008 /* VFS only */ +#define SQLITE_OPEN_EXCLUSIVE 0x00000010 /* VFS only */ +#define SQLITE_OPEN_AUTOPROXY 0x00000020 /* VFS only */ +#define SQLITE_OPEN_URI 0x00000040 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_MEMORY 0x00000080 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_MAIN_DB 0x00000100 /* VFS only */ +#define SQLITE_OPEN_TEMP_DB 0x00000200 /* VFS only */ +#define SQLITE_OPEN_TRANSIENT_DB 0x00000400 /* VFS only */ +#define SQLITE_OPEN_MAIN_JOURNAL 0x00000800 /* VFS only */ +#define SQLITE_OPEN_TEMP_JOURNAL 0x00001000 /* VFS only */ +#define SQLITE_OPEN_SUBJOURNAL 0x00002000 /* VFS only */ +#define SQLITE_OPEN_SUPER_JOURNAL 0x00004000 /* VFS only */ +#define SQLITE_OPEN_NOMUTEX 0x00008000 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_FULLMUTEX 0x00010000 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_SHAREDCACHE 0x00020000 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_PRIVATECACHE 0x00040000 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_WAL 0x00080000 /* VFS only */ +#define SQLITE_OPEN_NOFOLLOW 0x01000000 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_EXRESCODE 0x02000000 /* Extended result codes */ /* Reserved: 0x00F00000 */ /* Legacy compatibility: */ -#define SQLITE_OPEN_MASTER_JOURNAL 0x00004000 /* VFS only */ - +#define SQLITE_OPEN_MASTER_JOURNAL 0x00004000 /* VFS only */ /* ** CAPI3REF: Device Characteristics @@ -649,21 +647,21 @@ SQLITE_API int sqlite3_exec( ** write operations are bracketed by [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] and ** [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]. */ -#define SQLITE_IOCAP_ATOMIC 0x00000001 -#define SQLITE_IOCAP_ATOMIC512 0x00000002 -#define SQLITE_IOCAP_ATOMIC1K 0x00000004 -#define SQLITE_IOCAP_ATOMIC2K 0x00000008 -#define SQLITE_IOCAP_ATOMIC4K 0x00000010 -#define SQLITE_IOCAP_ATOMIC8K 0x00000020 -#define SQLITE_IOCAP_ATOMIC16K 0x00000040 -#define SQLITE_IOCAP_ATOMIC32K 0x00000080 -#define SQLITE_IOCAP_ATOMIC64K 0x00000100 -#define SQLITE_IOCAP_SAFE_APPEND 0x00000200 -#define SQLITE_IOCAP_SEQUENTIAL 0x00000400 -#define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800 -#define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000 -#define SQLITE_IOCAP_IMMUTABLE 0x00002000 -#define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000 +#define SQLITE_IOCAP_ATOMIC 0x00000001 +#define SQLITE_IOCAP_ATOMIC512 0x00000002 +#define SQLITE_IOCAP_ATOMIC1K 0x00000004 +#define SQLITE_IOCAP_ATOMIC2K 0x00000008 +#define SQLITE_IOCAP_ATOMIC4K 0x00000010 +#define SQLITE_IOCAP_ATOMIC8K 0x00000020 +#define SQLITE_IOCAP_ATOMIC16K 0x00000040 +#define SQLITE_IOCAP_ATOMIC32K 0x00000080 +#define SQLITE_IOCAP_ATOMIC64K 0x00000100 +#define SQLITE_IOCAP_SAFE_APPEND 0x00000200 +#define SQLITE_IOCAP_SEQUENTIAL 0x00000400 +#define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800 +#define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000 +#define SQLITE_IOCAP_IMMUTABLE 0x00002000 +#define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000 /* ** CAPI3REF: File Locking Levels @@ -672,11 +670,11 @@ SQLITE_API int sqlite3_exec( ** argument to calls it makes to the xLock() and xUnlock() methods ** of an [sqlite3_io_methods] object. */ -#define SQLITE_LOCK_NONE 0 -#define SQLITE_LOCK_SHARED 1 -#define SQLITE_LOCK_RESERVED 2 -#define SQLITE_LOCK_PENDING 3 -#define SQLITE_LOCK_EXCLUSIVE 4 +#define SQLITE_LOCK_NONE 0 +#define SQLITE_LOCK_SHARED 1 +#define SQLITE_LOCK_RESERVED 2 +#define SQLITE_LOCK_PENDING 3 +#define SQLITE_LOCK_EXCLUSIVE 4 /* ** CAPI3REF: Synchronization Type Flags @@ -704,146 +702,148 @@ SQLITE_API int sqlite3_exec( ** operating systems natively supported by SQLite, only Mac OSX ** cares about the difference.) */ -#define SQLITE_SYNC_NORMAL 0x00002 -#define SQLITE_SYNC_FULL 0x00003 -#define SQLITE_SYNC_DATAONLY 0x00010 - -/* -** CAPI3REF: OS Interface Open File Handle -** -** An [sqlite3_file] object represents an open file in the -** [sqlite3_vfs | OS interface layer]. Individual OS interface -** implementations will -** want to subclass this object by appending additional fields -** for their own use. The pMethods entry is a pointer to an -** [sqlite3_io_methods] object that defines methods for performing -** I/O operations on the open file. -*/ -typedef struct sqlite3_file sqlite3_file; -struct sqlite3_file { - const struct sqlite3_io_methods *pMethods; /* Methods for an open file */ -}; - -/* -** CAPI3REF: OS Interface File Virtual Methods Object -** -** Every file opened by the [sqlite3_vfs.xOpen] method populates an -** [sqlite3_file] object (or, more commonly, a subclass of the -** [sqlite3_file] object) with a pointer to an instance of this object. -** This object defines the methods used to perform various operations -** against the open file represented by the [sqlite3_file] object. -** -** If the [sqlite3_vfs.xOpen] method sets the sqlite3_file.pMethods element -** to a non-NULL pointer, then the sqlite3_io_methods.xClose method -** may be invoked even if the [sqlite3_vfs.xOpen] reported that it failed. The -** only way to prevent a call to xClose following a failed [sqlite3_vfs.xOpen] -** is for the [sqlite3_vfs.xOpen] to set the sqlite3_file.pMethods element -** to NULL. -** -** The flags argument to xSync may be one of [SQLITE_SYNC_NORMAL] or -** [SQLITE_SYNC_FULL]. The first choice is the normal fsync(). -** The second choice is a Mac OS X style fullsync. The [SQLITE_SYNC_DATAONLY] -** flag may be ORed in to indicate that only the data of the file -** and not its inode needs to be synced. -** -** The integer values to xLock() and xUnlock() are one of -**
    -**
  • [SQLITE_LOCK_NONE], -**
  • [SQLITE_LOCK_SHARED], -**
  • [SQLITE_LOCK_RESERVED], -**
  • [SQLITE_LOCK_PENDING], or -**
  • [SQLITE_LOCK_EXCLUSIVE]. -**
-** xLock() increases the lock. xUnlock() decreases the lock. -** The xCheckReservedLock() method checks whether any database connection, -** either in this process or in some other process, is holding a RESERVED, -** PENDING, or EXCLUSIVE lock on the file. It returns true -** if such a lock exists and false otherwise. -** -** The xFileControl() method is a generic interface that allows custom -** VFS implementations to directly control an open file using the -** [sqlite3_file_control()] interface. The second "op" argument is an -** integer opcode. The third argument is a generic pointer intended to -** point to a structure that may contain arguments or space in which to -** write return values. Potential uses for xFileControl() might be -** functions to enable blocking locks with timeouts, to change the -** locking strategy (for example to use dot-file locks), to inquire -** about the status of a lock, or to break stale locks. The SQLite -** core reserves all opcodes less than 100 for its own use. -** A [file control opcodes | list of opcodes] less than 100 is available. -** Applications that define a custom xFileControl method should use opcodes -** greater than 100 to avoid conflicts. VFS implementations should -** return [SQLITE_NOTFOUND] for file control opcodes that they do not -** recognize. -** -** The xSectorSize() method returns the sector size of the -** device that underlies the file. The sector size is the -** minimum write that can be performed without disturbing -** other bytes in the file. The xDeviceCharacteristics() -** method returns a bit vector describing behaviors of the -** underlying device: -** -**
    -**
  • [SQLITE_IOCAP_ATOMIC] -**
  • [SQLITE_IOCAP_ATOMIC512] -**
  • [SQLITE_IOCAP_ATOMIC1K] -**
  • [SQLITE_IOCAP_ATOMIC2K] -**
  • [SQLITE_IOCAP_ATOMIC4K] -**
  • [SQLITE_IOCAP_ATOMIC8K] -**
  • [SQLITE_IOCAP_ATOMIC16K] -**
  • [SQLITE_IOCAP_ATOMIC32K] -**
  • [SQLITE_IOCAP_ATOMIC64K] -**
  • [SQLITE_IOCAP_SAFE_APPEND] -**
  • [SQLITE_IOCAP_SEQUENTIAL] -**
  • [SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN] -**
  • [SQLITE_IOCAP_POWERSAFE_OVERWRITE] -**
  • [SQLITE_IOCAP_IMMUTABLE] -**
  • [SQLITE_IOCAP_BATCH_ATOMIC] -**
-** -** The SQLITE_IOCAP_ATOMIC property means that all writes of -** any size are atomic. The SQLITE_IOCAP_ATOMICnnn values -** mean that writes of blocks that are nnn bytes in size and -** are aligned to an address which is an integer multiple of -** nnn are atomic. The SQLITE_IOCAP_SAFE_APPEND value means -** that when data is appended to a file, the data is appended -** first then the size of the file is extended, never the other -** way around. The SQLITE_IOCAP_SEQUENTIAL property means that -** information is written to disk in the same order as calls -** to xWrite(). -** -** If xRead() returns SQLITE_IOERR_SHORT_READ it must also fill -** in the unread portions of the buffer with zeros. A VFS that -** fails to zero-fill short reads might seem to work. However, -** failure to zero-fill short reads will eventually lead to -** database corruption. -*/ -typedef struct sqlite3_io_methods sqlite3_io_methods; -struct sqlite3_io_methods { - int iVersion; - int (*xClose)(sqlite3_file*); - int (*xRead)(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); - int (*xWrite)(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst); - int (*xTruncate)(sqlite3_file*, sqlite3_int64 size); - int (*xSync)(sqlite3_file*, int flags); - int (*xFileSize)(sqlite3_file*, sqlite3_int64 *pSize); - int (*xLock)(sqlite3_file*, int); - int (*xUnlock)(sqlite3_file*, int); - int (*xCheckReservedLock)(sqlite3_file*, int *pResOut); - int (*xFileControl)(sqlite3_file*, int op, void *pArg); - int (*xSectorSize)(sqlite3_file*); - int (*xDeviceCharacteristics)(sqlite3_file*); - /* Methods above are valid for version 1 */ - int (*xShmMap)(sqlite3_file*, int iPg, int pgsz, int, void volatile**); - int (*xShmLock)(sqlite3_file*, int offset, int n, int flags); - void (*xShmBarrier)(sqlite3_file*); - int (*xShmUnmap)(sqlite3_file*, int deleteFlag); - /* Methods above are valid for version 2 */ - int (*xFetch)(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp); - int (*xUnfetch)(sqlite3_file*, sqlite3_int64 iOfst, void *p); - /* Methods above are valid for version 3 */ - /* Additional methods may be added in future releases */ -}; +#define SQLITE_SYNC_NORMAL 0x00002 +#define SQLITE_SYNC_FULL 0x00003 +#define SQLITE_SYNC_DATAONLY 0x00010 + + /* + ** CAPI3REF: OS Interface Open File Handle + ** + ** An [sqlite3_file] object represents an open file in the + ** [sqlite3_vfs | OS interface layer]. Individual OS interface + ** implementations will + ** want to subclass this object by appending additional fields + ** for their own use. The pMethods entry is a pointer to an + ** [sqlite3_io_methods] object that defines methods for performing + ** I/O operations on the open file. + */ + typedef struct sqlite3_file sqlite3_file; + struct sqlite3_file + { + const struct sqlite3_io_methods* pMethods; /* Methods for an open file */ + }; + + /* + ** CAPI3REF: OS Interface File Virtual Methods Object + ** + ** Every file opened by the [sqlite3_vfs.xOpen] method populates an + ** [sqlite3_file] object (or, more commonly, a subclass of the + ** [sqlite3_file] object) with a pointer to an instance of this object. + ** This object defines the methods used to perform various operations + ** against the open file represented by the [sqlite3_file] object. + ** + ** If the [sqlite3_vfs.xOpen] method sets the sqlite3_file.pMethods element + ** to a non-NULL pointer, then the sqlite3_io_methods.xClose method + ** may be invoked even if the [sqlite3_vfs.xOpen] reported that it failed. The + ** only way to prevent a call to xClose following a failed [sqlite3_vfs.xOpen] + ** is for the [sqlite3_vfs.xOpen] to set the sqlite3_file.pMethods element + ** to NULL. + ** + ** The flags argument to xSync may be one of [SQLITE_SYNC_NORMAL] or + ** [SQLITE_SYNC_FULL]. The first choice is the normal fsync(). + ** The second choice is a Mac OS X style fullsync. The [SQLITE_SYNC_DATAONLY] + ** flag may be ORed in to indicate that only the data of the file + ** and not its inode needs to be synced. + ** + ** The integer values to xLock() and xUnlock() are one of + **
    + **
  • [SQLITE_LOCK_NONE], + **
  • [SQLITE_LOCK_SHARED], + **
  • [SQLITE_LOCK_RESERVED], + **
  • [SQLITE_LOCK_PENDING], or + **
  • [SQLITE_LOCK_EXCLUSIVE]. + **
+ ** xLock() increases the lock. xUnlock() decreases the lock. + ** The xCheckReservedLock() method checks whether any database connection, + ** either in this process or in some other process, is holding a RESERVED, + ** PENDING, or EXCLUSIVE lock on the file. It returns true + ** if such a lock exists and false otherwise. + ** + ** The xFileControl() method is a generic interface that allows custom + ** VFS implementations to directly control an open file using the + ** [sqlite3_file_control()] interface. The second "op" argument is an + ** integer opcode. The third argument is a generic pointer intended to + ** point to a structure that may contain arguments or space in which to + ** write return values. Potential uses for xFileControl() might be + ** functions to enable blocking locks with timeouts, to change the + ** locking strategy (for example to use dot-file locks), to inquire + ** about the status of a lock, or to break stale locks. The SQLite + ** core reserves all opcodes less than 100 for its own use. + ** A [file control opcodes | list of opcodes] less than 100 is available. + ** Applications that define a custom xFileControl method should use opcodes + ** greater than 100 to avoid conflicts. VFS implementations should + ** return [SQLITE_NOTFOUND] for file control opcodes that they do not + ** recognize. + ** + ** The xSectorSize() method returns the sector size of the + ** device that underlies the file. The sector size is the + ** minimum write that can be performed without disturbing + ** other bytes in the file. The xDeviceCharacteristics() + ** method returns a bit vector describing behaviors of the + ** underlying device: + ** + **
    + **
  • [SQLITE_IOCAP_ATOMIC] + **
  • [SQLITE_IOCAP_ATOMIC512] + **
  • [SQLITE_IOCAP_ATOMIC1K] + **
  • [SQLITE_IOCAP_ATOMIC2K] + **
  • [SQLITE_IOCAP_ATOMIC4K] + **
  • [SQLITE_IOCAP_ATOMIC8K] + **
  • [SQLITE_IOCAP_ATOMIC16K] + **
  • [SQLITE_IOCAP_ATOMIC32K] + **
  • [SQLITE_IOCAP_ATOMIC64K] + **
  • [SQLITE_IOCAP_SAFE_APPEND] + **
  • [SQLITE_IOCAP_SEQUENTIAL] + **
  • [SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN] + **
  • [SQLITE_IOCAP_POWERSAFE_OVERWRITE] + **
  • [SQLITE_IOCAP_IMMUTABLE] + **
  • [SQLITE_IOCAP_BATCH_ATOMIC] + **
+ ** + ** The SQLITE_IOCAP_ATOMIC property means that all writes of + ** any size are atomic. The SQLITE_IOCAP_ATOMICnnn values + ** mean that writes of blocks that are nnn bytes in size and + ** are aligned to an address which is an integer multiple of + ** nnn are atomic. The SQLITE_IOCAP_SAFE_APPEND value means + ** that when data is appended to a file, the data is appended + ** first then the size of the file is extended, never the other + ** way around. The SQLITE_IOCAP_SEQUENTIAL property means that + ** information is written to disk in the same order as calls + ** to xWrite(). + ** + ** If xRead() returns SQLITE_IOERR_SHORT_READ it must also fill + ** in the unread portions of the buffer with zeros. A VFS that + ** fails to zero-fill short reads might seem to work. However, + ** failure to zero-fill short reads will eventually lead to + ** database corruption. + */ + typedef struct sqlite3_io_methods sqlite3_io_methods; + struct sqlite3_io_methods + { + int iVersion; + int (*xClose)(sqlite3_file*); + int (*xRead)(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); + int (*xWrite)(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst); + int (*xTruncate)(sqlite3_file*, sqlite3_int64 size); + int (*xSync)(sqlite3_file*, int flags); + int (*xFileSize)(sqlite3_file*, sqlite3_int64* pSize); + int (*xLock)(sqlite3_file*, int); + int (*xUnlock)(sqlite3_file*, int); + int (*xCheckReservedLock)(sqlite3_file*, int* pResOut); + int (*xFileControl)(sqlite3_file*, int op, void* pArg); + int (*xSectorSize)(sqlite3_file*); + int (*xDeviceCharacteristics)(sqlite3_file*); + /* Methods above are valid for version 1 */ + int (*xShmMap)(sqlite3_file*, int iPg, int pgsz, int, void volatile**); + int (*xShmLock)(sqlite3_file*, int offset, int n, int flags); + void (*xShmBarrier)(sqlite3_file*); + int (*xShmUnmap)(sqlite3_file*, int deleteFlag); + /* Methods above are valid for version 2 */ + int (*xFetch)(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void** pp); + int (*xUnfetch)(sqlite3_file*, sqlite3_int64 iOfst, void* p); + /* Methods above are valid for version 3 */ + /* Additional methods may be added in future releases */ + }; /* ** CAPI3REF: Standard File Control Opcodes @@ -1184,284 +1184,283 @@ struct sqlite3_io_methods { ** Used by the cksmvfs VFS module only. ** */ -#define SQLITE_FCNTL_LOCKSTATE 1 -#define SQLITE_FCNTL_GET_LOCKPROXYFILE 2 -#define SQLITE_FCNTL_SET_LOCKPROXYFILE 3 -#define SQLITE_FCNTL_LAST_ERRNO 4 -#define SQLITE_FCNTL_SIZE_HINT 5 -#define SQLITE_FCNTL_CHUNK_SIZE 6 -#define SQLITE_FCNTL_FILE_POINTER 7 -#define SQLITE_FCNTL_SYNC_OMITTED 8 -#define SQLITE_FCNTL_WIN32_AV_RETRY 9 -#define SQLITE_FCNTL_PERSIST_WAL 10 -#define SQLITE_FCNTL_OVERWRITE 11 -#define SQLITE_FCNTL_VFSNAME 12 -#define SQLITE_FCNTL_POWERSAFE_OVERWRITE 13 -#define SQLITE_FCNTL_PRAGMA 14 -#define SQLITE_FCNTL_BUSYHANDLER 15 -#define SQLITE_FCNTL_TEMPFILENAME 16 -#define SQLITE_FCNTL_MMAP_SIZE 18 -#define SQLITE_FCNTL_TRACE 19 -#define SQLITE_FCNTL_HAS_MOVED 20 -#define SQLITE_FCNTL_SYNC 21 -#define SQLITE_FCNTL_COMMIT_PHASETWO 22 -#define SQLITE_FCNTL_WIN32_SET_HANDLE 23 -#define SQLITE_FCNTL_WAL_BLOCK 24 -#define SQLITE_FCNTL_ZIPVFS 25 -#define SQLITE_FCNTL_RBU 26 -#define SQLITE_FCNTL_VFS_POINTER 27 -#define SQLITE_FCNTL_JOURNAL_POINTER 28 -#define SQLITE_FCNTL_WIN32_GET_HANDLE 29 -#define SQLITE_FCNTL_PDB 30 -#define SQLITE_FCNTL_BEGIN_ATOMIC_WRITE 31 -#define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE 32 -#define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE 33 -#define SQLITE_FCNTL_LOCK_TIMEOUT 34 -#define SQLITE_FCNTL_DATA_VERSION 35 -#define SQLITE_FCNTL_SIZE_LIMIT 36 -#define SQLITE_FCNTL_CKPT_DONE 37 -#define SQLITE_FCNTL_RESERVE_BYTES 38 -#define SQLITE_FCNTL_CKPT_START 39 -#define SQLITE_FCNTL_EXTERNAL_READER 40 -#define SQLITE_FCNTL_CKSM_FILE 41 +#define SQLITE_FCNTL_LOCKSTATE 1 +#define SQLITE_FCNTL_GET_LOCKPROXYFILE 2 +#define SQLITE_FCNTL_SET_LOCKPROXYFILE 3 +#define SQLITE_FCNTL_LAST_ERRNO 4 +#define SQLITE_FCNTL_SIZE_HINT 5 +#define SQLITE_FCNTL_CHUNK_SIZE 6 +#define SQLITE_FCNTL_FILE_POINTER 7 +#define SQLITE_FCNTL_SYNC_OMITTED 8 +#define SQLITE_FCNTL_WIN32_AV_RETRY 9 +#define SQLITE_FCNTL_PERSIST_WAL 10 +#define SQLITE_FCNTL_OVERWRITE 11 +#define SQLITE_FCNTL_VFSNAME 12 +#define SQLITE_FCNTL_POWERSAFE_OVERWRITE 13 +#define SQLITE_FCNTL_PRAGMA 14 +#define SQLITE_FCNTL_BUSYHANDLER 15 +#define SQLITE_FCNTL_TEMPFILENAME 16 +#define SQLITE_FCNTL_MMAP_SIZE 18 +#define SQLITE_FCNTL_TRACE 19 +#define SQLITE_FCNTL_HAS_MOVED 20 +#define SQLITE_FCNTL_SYNC 21 +#define SQLITE_FCNTL_COMMIT_PHASETWO 22 +#define SQLITE_FCNTL_WIN32_SET_HANDLE 23 +#define SQLITE_FCNTL_WAL_BLOCK 24 +#define SQLITE_FCNTL_ZIPVFS 25 +#define SQLITE_FCNTL_RBU 26 +#define SQLITE_FCNTL_VFS_POINTER 27 +#define SQLITE_FCNTL_JOURNAL_POINTER 28 +#define SQLITE_FCNTL_WIN32_GET_HANDLE 29 +#define SQLITE_FCNTL_PDB 30 +#define SQLITE_FCNTL_BEGIN_ATOMIC_WRITE 31 +#define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE 32 +#define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE 33 +#define SQLITE_FCNTL_LOCK_TIMEOUT 34 +#define SQLITE_FCNTL_DATA_VERSION 35 +#define SQLITE_FCNTL_SIZE_LIMIT 36 +#define SQLITE_FCNTL_CKPT_DONE 37 +#define SQLITE_FCNTL_RESERVE_BYTES 38 +#define SQLITE_FCNTL_CKPT_START 39 +#define SQLITE_FCNTL_EXTERNAL_READER 40 +#define SQLITE_FCNTL_CKSM_FILE 41 /* deprecated names */ -#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE -#define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE -#define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO - - -/* -** CAPI3REF: Mutex Handle -** -** The mutex module within SQLite defines [sqlite3_mutex] to be an -** abstract type for a mutex object. The SQLite core never looks -** at the internal representation of an [sqlite3_mutex]. It only -** deals with pointers to the [sqlite3_mutex] object. -** -** Mutexes are created using [sqlite3_mutex_alloc()]. -*/ -typedef struct sqlite3_mutex sqlite3_mutex; - -/* -** CAPI3REF: Loadable Extension Thunk -** -** A pointer to the opaque sqlite3_api_routines structure is passed as -** the third parameter to entry points of [loadable extensions]. This -** structure must be typedefed in order to work around compiler warnings -** on some platforms. -*/ -typedef struct sqlite3_api_routines sqlite3_api_routines; - -/* -** CAPI3REF: OS Interface Object -** -** An instance of the sqlite3_vfs object defines the interface between -** the SQLite core and the underlying operating system. The "vfs" -** in the name of the object stands for "virtual file system". See -** the [VFS | VFS documentation] for further information. -** -** The VFS interface is sometimes extended by adding new methods onto -** the end. Each time such an extension occurs, the iVersion field -** is incremented. The iVersion value started out as 1 in -** SQLite [version 3.5.0] on [dateof:3.5.0], then increased to 2 -** with SQLite [version 3.7.0] on [dateof:3.7.0], and then increased -** to 3 with SQLite [version 3.7.6] on [dateof:3.7.6]. Additional fields -** may be appended to the sqlite3_vfs object and the iVersion value -** may increase again in future versions of SQLite. -** Note that due to an oversight, the structure -** of the sqlite3_vfs object changed in the transition from -** SQLite [version 3.5.9] to [version 3.6.0] on [dateof:3.6.0] -** and yet the iVersion field was not increased. -** -** The szOsFile field is the size of the subclassed [sqlite3_file] -** structure used by this VFS. mxPathname is the maximum length of -** a pathname in this VFS. -** -** Registered sqlite3_vfs objects are kept on a linked list formed by -** the pNext pointer. The [sqlite3_vfs_register()] -** and [sqlite3_vfs_unregister()] interfaces manage this list -** in a thread-safe way. The [sqlite3_vfs_find()] interface -** searches the list. Neither the application code nor the VFS -** implementation should use the pNext pointer. -** -** The pNext field is the only field in the sqlite3_vfs -** structure that SQLite will ever modify. SQLite will only access -** or modify this field while holding a particular static mutex. -** The application should never modify anything within the sqlite3_vfs -** object once the object has been registered. -** -** The zName field holds the name of the VFS module. The name must -** be unique across all VFS modules. -** -** [[sqlite3_vfs.xOpen]] -** ^SQLite guarantees that the zFilename parameter to xOpen -** is either a NULL pointer or string obtained -** from xFullPathname() with an optional suffix added. -** ^If a suffix is added to the zFilename parameter, it will -** consist of a single "-" character followed by no more than -** 11 alphanumeric and/or "-" characters. -** ^SQLite further guarantees that -** the string will be valid and unchanged until xClose() is -** called. Because of the previous sentence, -** the [sqlite3_file] can safely store a pointer to the -** filename if it needs to remember the filename for some reason. -** If the zFilename parameter to xOpen is a NULL pointer then xOpen -** must invent its own temporary name for the file. ^Whenever the -** xFilename parameter is NULL it will also be the case that the -** flags parameter will include [SQLITE_OPEN_DELETEONCLOSE]. -** -** The flags argument to xOpen() includes all bits set in -** the flags argument to [sqlite3_open_v2()]. Or if [sqlite3_open()] -** or [sqlite3_open16()] is used, then flags includes at least -** [SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]. -** If xOpen() opens a file read-only then it sets *pOutFlags to -** include [SQLITE_OPEN_READONLY]. Other bits in *pOutFlags may be set. -** -** ^(SQLite will also add one of the following flags to the xOpen() -** call, depending on the object being opened: -** -**
    -**
  • [SQLITE_OPEN_MAIN_DB] -**
  • [SQLITE_OPEN_MAIN_JOURNAL] -**
  • [SQLITE_OPEN_TEMP_DB] -**
  • [SQLITE_OPEN_TEMP_JOURNAL] -**
  • [SQLITE_OPEN_TRANSIENT_DB] -**
  • [SQLITE_OPEN_SUBJOURNAL] -**
  • [SQLITE_OPEN_SUPER_JOURNAL] -**
  • [SQLITE_OPEN_WAL] -**
)^ -** -** The file I/O implementation can use the object type flags to -** change the way it deals with files. For example, an application -** that does not care about crash recovery or rollback might make -** the open of a journal file a no-op. Writes to this journal would -** also be no-ops, and any attempt to read the journal would return -** SQLITE_IOERR. Or the implementation might recognize that a database -** file will be doing page-aligned sector reads and writes in a random -** order and set up its I/O subsystem accordingly. -** -** SQLite might also add one of the following flags to the xOpen method: -** -**
    -**
  • [SQLITE_OPEN_DELETEONCLOSE] -**
  • [SQLITE_OPEN_EXCLUSIVE] -**
-** -** The [SQLITE_OPEN_DELETEONCLOSE] flag means the file should be -** deleted when it is closed. ^The [SQLITE_OPEN_DELETEONCLOSE] -** will be set for TEMP databases and their journals, transient -** databases, and subjournals. -** -** ^The [SQLITE_OPEN_EXCLUSIVE] flag is always used in conjunction -** with the [SQLITE_OPEN_CREATE] flag, which are both directly -** analogous to the O_EXCL and O_CREAT flags of the POSIX open() -** API. The SQLITE_OPEN_EXCLUSIVE flag, when paired with the -** SQLITE_OPEN_CREATE, is used to indicate that file should always -** be created, and that it is an error if it already exists. -** It is not used to indicate the file should be opened -** for exclusive access. -** -** ^At least szOsFile bytes of memory are allocated by SQLite -** to hold the [sqlite3_file] structure passed as the third -** argument to xOpen. The xOpen method does not have to -** allocate the structure; it should just fill it in. Note that -** the xOpen method must set the sqlite3_file.pMethods to either -** a valid [sqlite3_io_methods] object or to NULL. xOpen must do -** this even if the open fails. SQLite expects that the sqlite3_file.pMethods -** element will be valid after xOpen returns regardless of the success -** or failure of the xOpen call. -** -** [[sqlite3_vfs.xAccess]] -** ^The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS] -** to test for the existence of a file, or [SQLITE_ACCESS_READWRITE] to -** test whether a file is readable and writable, or [SQLITE_ACCESS_READ] -** to test whether a file is at least readable. The SQLITE_ACCESS_READ -** flag is never actually used and is not implemented in the built-in -** VFSes of SQLite. The file is named by the second argument and can be a -** directory. The xAccess method returns [SQLITE_OK] on success or some -** non-zero error code if there is an I/O error or if the name of -** the file given in the second argument is illegal. If SQLITE_OK -** is returned, then non-zero or zero is written into *pResOut to indicate -** whether or not the file is accessible. -** -** ^SQLite will always allocate at least mxPathname+1 bytes for the -** output buffer xFullPathname. The exact size of the output buffer -** is also passed as a parameter to both methods. If the output buffer -** is not large enough, [SQLITE_CANTOPEN] should be returned. Since this is -** handled as a fatal error by SQLite, vfs implementations should endeavor -** to prevent this by setting mxPathname to a sufficiently large value. -** -** The xRandomness(), xSleep(), xCurrentTime(), and xCurrentTimeInt64() -** interfaces are not strictly a part of the filesystem, but they are -** included in the VFS structure for completeness. -** The xRandomness() function attempts to return nBytes bytes -** of good-quality randomness into zOut. The return value is -** the actual number of bytes of randomness obtained. -** The xSleep() method causes the calling thread to sleep for at -** least the number of microseconds given. ^The xCurrentTime() -** method returns a Julian Day Number for the current date and time as -** a floating point value. -** ^The xCurrentTimeInt64() method returns, as an integer, the Julian -** Day Number multiplied by 86400000 (the number of milliseconds in -** a 24-hour day). -** ^SQLite will use the xCurrentTimeInt64() method to get the current -** date and time if that method is available (if iVersion is 2 or -** greater and the function pointer is not NULL) and will fall back -** to xCurrentTime() if xCurrentTimeInt64() is unavailable. -** -** ^The xSetSystemCall(), xGetSystemCall(), and xNestSystemCall() interfaces -** are not used by the SQLite core. These optional interfaces are provided -** by some VFSes to facilitate testing of the VFS code. By overriding -** system calls with functions under its control, a test program can -** simulate faults and error conditions that would otherwise be difficult -** or impossible to induce. The set of system calls that can be overridden -** varies from one VFS to another, and from one version of the same VFS to the -** next. Applications that use these interfaces must be prepared for any -** or all of these interfaces to be NULL or for their behavior to change -** from one release to the next. Applications must not attempt to access -** any of these methods if the iVersion of the VFS is less than 3. -*/ -typedef struct sqlite3_vfs sqlite3_vfs; -typedef void (*sqlite3_syscall_ptr)(void); -struct sqlite3_vfs { - int iVersion; /* Structure version number (currently 3) */ - int szOsFile; /* Size of subclassed sqlite3_file */ - int mxPathname; /* Maximum file pathname length */ - sqlite3_vfs *pNext; /* Next registered VFS */ - const char *zName; /* Name of this virtual file system */ - void *pAppData; /* Pointer to application-specific data */ - int (*xOpen)(sqlite3_vfs*, const char *zName, sqlite3_file*, - int flags, int *pOutFlags); - int (*xDelete)(sqlite3_vfs*, const char *zName, int syncDir); - int (*xAccess)(sqlite3_vfs*, const char *zName, int flags, int *pResOut); - int (*xFullPathname)(sqlite3_vfs*, const char *zName, int nOut, char *zOut); - void *(*xDlOpen)(sqlite3_vfs*, const char *zFilename); - void (*xDlError)(sqlite3_vfs*, int nByte, char *zErrMsg); - void (*(*xDlSym)(sqlite3_vfs*,void*, const char *zSymbol))(void); - void (*xDlClose)(sqlite3_vfs*, void*); - int (*xRandomness)(sqlite3_vfs*, int nByte, char *zOut); - int (*xSleep)(sqlite3_vfs*, int microseconds); - int (*xCurrentTime)(sqlite3_vfs*, double*); - int (*xGetLastError)(sqlite3_vfs*, int, char *); - /* - ** The methods above are in version 1 of the sqlite_vfs object - ** definition. Those that follow are added in version 2 or later - */ - int (*xCurrentTimeInt64)(sqlite3_vfs*, sqlite3_int64*); - /* - ** The methods above are in versions 1 and 2 of the sqlite_vfs object. - ** Those below are for version 3 and greater. - */ - int (*xSetSystemCall)(sqlite3_vfs*, const char *zName, sqlite3_syscall_ptr); - sqlite3_syscall_ptr (*xGetSystemCall)(sqlite3_vfs*, const char *zName); - const char *(*xNextSystemCall)(sqlite3_vfs*, const char *zName); - /* - ** The methods above are in versions 1 through 3 of the sqlite_vfs object. - ** New fields may be appended in future versions. The iVersion - ** value will increment whenever this happens. - */ -}; +#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE +#define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE +#define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO + + /* + ** CAPI3REF: Mutex Handle + ** + ** The mutex module within SQLite defines [sqlite3_mutex] to be an + ** abstract type for a mutex object. The SQLite core never looks + ** at the internal representation of an [sqlite3_mutex]. It only + ** deals with pointers to the [sqlite3_mutex] object. + ** + ** Mutexes are created using [sqlite3_mutex_alloc()]. + */ + typedef struct sqlite3_mutex sqlite3_mutex; + + /* + ** CAPI3REF: Loadable Extension Thunk + ** + ** A pointer to the opaque sqlite3_api_routines structure is passed as + ** the third parameter to entry points of [loadable extensions]. This + ** structure must be typedefed in order to work around compiler warnings + ** on some platforms. + */ + typedef struct sqlite3_api_routines sqlite3_api_routines; + + /* + ** CAPI3REF: OS Interface Object + ** + ** An instance of the sqlite3_vfs object defines the interface between + ** the SQLite core and the underlying operating system. The "vfs" + ** in the name of the object stands for "virtual file system". See + ** the [VFS | VFS documentation] for further information. + ** + ** The VFS interface is sometimes extended by adding new methods onto + ** the end. Each time such an extension occurs, the iVersion field + ** is incremented. The iVersion value started out as 1 in + ** SQLite [version 3.5.0] on [dateof:3.5.0], then increased to 2 + ** with SQLite [version 3.7.0] on [dateof:3.7.0], and then increased + ** to 3 with SQLite [version 3.7.6] on [dateof:3.7.6]. Additional fields + ** may be appended to the sqlite3_vfs object and the iVersion value + ** may increase again in future versions of SQLite. + ** Note that due to an oversight, the structure + ** of the sqlite3_vfs object changed in the transition from + ** SQLite [version 3.5.9] to [version 3.6.0] on [dateof:3.6.0] + ** and yet the iVersion field was not increased. + ** + ** The szOsFile field is the size of the subclassed [sqlite3_file] + ** structure used by this VFS. mxPathname is the maximum length of + ** a pathname in this VFS. + ** + ** Registered sqlite3_vfs objects are kept on a linked list formed by + ** the pNext pointer. The [sqlite3_vfs_register()] + ** and [sqlite3_vfs_unregister()] interfaces manage this list + ** in a thread-safe way. The [sqlite3_vfs_find()] interface + ** searches the list. Neither the application code nor the VFS + ** implementation should use the pNext pointer. + ** + ** The pNext field is the only field in the sqlite3_vfs + ** structure that SQLite will ever modify. SQLite will only access + ** or modify this field while holding a particular static mutex. + ** The application should never modify anything within the sqlite3_vfs + ** object once the object has been registered. + ** + ** The zName field holds the name of the VFS module. The name must + ** be unique across all VFS modules. + ** + ** [[sqlite3_vfs.xOpen]] + ** ^SQLite guarantees that the zFilename parameter to xOpen + ** is either a NULL pointer or string obtained + ** from xFullPathname() with an optional suffix added. + ** ^If a suffix is added to the zFilename parameter, it will + ** consist of a single "-" character followed by no more than + ** 11 alphanumeric and/or "-" characters. + ** ^SQLite further guarantees that + ** the string will be valid and unchanged until xClose() is + ** called. Because of the previous sentence, + ** the [sqlite3_file] can safely store a pointer to the + ** filename if it needs to remember the filename for some reason. + ** If the zFilename parameter to xOpen is a NULL pointer then xOpen + ** must invent its own temporary name for the file. ^Whenever the + ** xFilename parameter is NULL it will also be the case that the + ** flags parameter will include [SQLITE_OPEN_DELETEONCLOSE]. + ** + ** The flags argument to xOpen() includes all bits set in + ** the flags argument to [sqlite3_open_v2()]. Or if [sqlite3_open()] + ** or [sqlite3_open16()] is used, then flags includes at least + ** [SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]. + ** If xOpen() opens a file read-only then it sets *pOutFlags to + ** include [SQLITE_OPEN_READONLY]. Other bits in *pOutFlags may be set. + ** + ** ^(SQLite will also add one of the following flags to the xOpen() + ** call, depending on the object being opened: + ** + **
    + **
  • [SQLITE_OPEN_MAIN_DB] + **
  • [SQLITE_OPEN_MAIN_JOURNAL] + **
  • [SQLITE_OPEN_TEMP_DB] + **
  • [SQLITE_OPEN_TEMP_JOURNAL] + **
  • [SQLITE_OPEN_TRANSIENT_DB] + **
  • [SQLITE_OPEN_SUBJOURNAL] + **
  • [SQLITE_OPEN_SUPER_JOURNAL] + **
  • [SQLITE_OPEN_WAL] + **
)^ + ** + ** The file I/O implementation can use the object type flags to + ** change the way it deals with files. For example, an application + ** that does not care about crash recovery or rollback might make + ** the open of a journal file a no-op. Writes to this journal would + ** also be no-ops, and any attempt to read the journal would return + ** SQLITE_IOERR. Or the implementation might recognize that a database + ** file will be doing page-aligned sector reads and writes in a random + ** order and set up its I/O subsystem accordingly. + ** + ** SQLite might also add one of the following flags to the xOpen method: + ** + **
    + **
  • [SQLITE_OPEN_DELETEONCLOSE] + **
  • [SQLITE_OPEN_EXCLUSIVE] + **
+ ** + ** The [SQLITE_OPEN_DELETEONCLOSE] flag means the file should be + ** deleted when it is closed. ^The [SQLITE_OPEN_DELETEONCLOSE] + ** will be set for TEMP databases and their journals, transient + ** databases, and subjournals. + ** + ** ^The [SQLITE_OPEN_EXCLUSIVE] flag is always used in conjunction + ** with the [SQLITE_OPEN_CREATE] flag, which are both directly + ** analogous to the O_EXCL and O_CREAT flags of the POSIX open() + ** API. The SQLITE_OPEN_EXCLUSIVE flag, when paired with the + ** SQLITE_OPEN_CREATE, is used to indicate that file should always + ** be created, and that it is an error if it already exists. + ** It is not used to indicate the file should be opened + ** for exclusive access. + ** + ** ^At least szOsFile bytes of memory are allocated by SQLite + ** to hold the [sqlite3_file] structure passed as the third + ** argument to xOpen. The xOpen method does not have to + ** allocate the structure; it should just fill it in. Note that + ** the xOpen method must set the sqlite3_file.pMethods to either + ** a valid [sqlite3_io_methods] object or to NULL. xOpen must do + ** this even if the open fails. SQLite expects that the sqlite3_file.pMethods + ** element will be valid after xOpen returns regardless of the success + ** or failure of the xOpen call. + ** + ** [[sqlite3_vfs.xAccess]] + ** ^The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS] + ** to test for the existence of a file, or [SQLITE_ACCESS_READWRITE] to + ** test whether a file is readable and writable, or [SQLITE_ACCESS_READ] + ** to test whether a file is at least readable. The SQLITE_ACCESS_READ + ** flag is never actually used and is not implemented in the built-in + ** VFSes of SQLite. The file is named by the second argument and can be a + ** directory. The xAccess method returns [SQLITE_OK] on success or some + ** non-zero error code if there is an I/O error or if the name of + ** the file given in the second argument is illegal. If SQLITE_OK + ** is returned, then non-zero or zero is written into *pResOut to indicate + ** whether or not the file is accessible. + ** + ** ^SQLite will always allocate at least mxPathname+1 bytes for the + ** output buffer xFullPathname. The exact size of the output buffer + ** is also passed as a parameter to both methods. If the output buffer + ** is not large enough, [SQLITE_CANTOPEN] should be returned. Since this is + ** handled as a fatal error by SQLite, vfs implementations should endeavor + ** to prevent this by setting mxPathname to a sufficiently large value. + ** + ** The xRandomness(), xSleep(), xCurrentTime(), and xCurrentTimeInt64() + ** interfaces are not strictly a part of the filesystem, but they are + ** included in the VFS structure for completeness. + ** The xRandomness() function attempts to return nBytes bytes + ** of good-quality randomness into zOut. The return value is + ** the actual number of bytes of randomness obtained. + ** The xSleep() method causes the calling thread to sleep for at + ** least the number of microseconds given. ^The xCurrentTime() + ** method returns a Julian Day Number for the current date and time as + ** a floating point value. + ** ^The xCurrentTimeInt64() method returns, as an integer, the Julian + ** Day Number multiplied by 86400000 (the number of milliseconds in + ** a 24-hour day). + ** ^SQLite will use the xCurrentTimeInt64() method to get the current + ** date and time if that method is available (if iVersion is 2 or + ** greater and the function pointer is not NULL) and will fall back + ** to xCurrentTime() if xCurrentTimeInt64() is unavailable. + ** + ** ^The xSetSystemCall(), xGetSystemCall(), and xNestSystemCall() interfaces + ** are not used by the SQLite core. These optional interfaces are provided + ** by some VFSes to facilitate testing of the VFS code. By overriding + ** system calls with functions under its control, a test program can + ** simulate faults and error conditions that would otherwise be difficult + ** or impossible to induce. The set of system calls that can be overridden + ** varies from one VFS to another, and from one version of the same VFS to the + ** next. Applications that use these interfaces must be prepared for any + ** or all of these interfaces to be NULL or for their behavior to change + ** from one release to the next. Applications must not attempt to access + ** any of these methods if the iVersion of the VFS is less than 3. + */ + typedef struct sqlite3_vfs sqlite3_vfs; + typedef void (*sqlite3_syscall_ptr)(void); + struct sqlite3_vfs + { + int iVersion; /* Structure version number (currently 3) */ + int szOsFile; /* Size of subclassed sqlite3_file */ + int mxPathname; /* Maximum file pathname length */ + sqlite3_vfs* pNext; /* Next registered VFS */ + const char* zName; /* Name of this virtual file system */ + void* pAppData; /* Pointer to application-specific data */ + int (*xOpen)(sqlite3_vfs*, const char* zName, sqlite3_file*, int flags, int* pOutFlags); + int (*xDelete)(sqlite3_vfs*, const char* zName, int syncDir); + int (*xAccess)(sqlite3_vfs*, const char* zName, int flags, int* pResOut); + int (*xFullPathname)(sqlite3_vfs*, const char* zName, int nOut, char* zOut); + void* (*xDlOpen)(sqlite3_vfs*, const char* zFilename); + void (*xDlError)(sqlite3_vfs*, int nByte, char* zErrMsg); + void (*(*xDlSym)(sqlite3_vfs*, void*, const char* zSymbol))(void); + void (*xDlClose)(sqlite3_vfs*, void*); + int (*xRandomness)(sqlite3_vfs*, int nByte, char* zOut); + int (*xSleep)(sqlite3_vfs*, int microseconds); + int (*xCurrentTime)(sqlite3_vfs*, double*); + int (*xGetLastError)(sqlite3_vfs*, int, char*); + /* + ** The methods above are in version 1 of the sqlite_vfs object + ** definition. Those that follow are added in version 2 or later + */ + int (*xCurrentTimeInt64)(sqlite3_vfs*, sqlite3_int64*); + /* + ** The methods above are in versions 1 and 2 of the sqlite_vfs object. + ** Those below are for version 3 and greater. + */ + int (*xSetSystemCall)(sqlite3_vfs*, const char* zName, sqlite3_syscall_ptr); + sqlite3_syscall_ptr (*xGetSystemCall)(sqlite3_vfs*, const char* zName); + const char* (*xNextSystemCall)(sqlite3_vfs*, const char* zName); + /* + ** The methods above are in versions 1 through 3 of the sqlite_vfs object. + ** New fields may be appended in future versions. The iVersion + ** value will increment whenever this happens. + */ + }; /* ** CAPI3REF: Flags for the xAccess VFS method @@ -1483,9 +1482,9 @@ struct sqlite3_vfs { ** currently unused, though it might be used in a future release of ** SQLite. */ -#define SQLITE_ACCESS_EXISTS 0 -#define SQLITE_ACCESS_READWRITE 1 /* Used by PRAGMA temp_store_directory */ -#define SQLITE_ACCESS_READ 2 /* Unused */ +#define SQLITE_ACCESS_EXISTS 0 +#define SQLITE_ACCESS_READWRITE 1 /* Used by PRAGMA temp_store_directory */ +#define SQLITE_ACCESS_READ 2 /* Unused */ /* ** CAPI3REF: Flags for the xShmLock VFS method @@ -1509,10 +1508,10 @@ struct sqlite3_vfs { ** between unlocked and EXCLUSIVE. It cannot transition between SHARED ** and EXCLUSIVE. */ -#define SQLITE_SHM_UNLOCK 1 -#define SQLITE_SHM_LOCK 2 -#define SQLITE_SHM_SHARED 4 -#define SQLITE_SHM_EXCLUSIVE 8 +#define SQLITE_SHM_UNLOCK 1 +#define SQLITE_SHM_LOCK 2 +#define SQLITE_SHM_SHARED 4 +#define SQLITE_SHM_EXCLUSIVE 8 /* ** CAPI3REF: Maximum xShmLock index @@ -1522,215 +1521,215 @@ struct sqlite3_vfs { ** The SQLite core will never attempt to acquire or release a ** lock outside of this range */ -#define SQLITE_SHM_NLOCK 8 - - -/* -** CAPI3REF: Initialize The SQLite Library -** -** ^The sqlite3_initialize() routine initializes the -** SQLite library. ^The sqlite3_shutdown() routine -** deallocates any resources that were allocated by sqlite3_initialize(). -** These routines are designed to aid in process initialization and -** shutdown on embedded systems. Workstation applications using -** SQLite normally do not need to invoke either of these routines. -** -** A call to sqlite3_initialize() is an "effective" call if it is -** the first time sqlite3_initialize() is invoked during the lifetime of -** the process, or if it is the first time sqlite3_initialize() is invoked -** following a call to sqlite3_shutdown(). ^(Only an effective call -** of sqlite3_initialize() does any initialization. All other calls -** are harmless no-ops.)^ -** -** A call to sqlite3_shutdown() is an "effective" call if it is the first -** call to sqlite3_shutdown() since the last sqlite3_initialize(). ^(Only -** an effective call to sqlite3_shutdown() does any deinitialization. -** All other valid calls to sqlite3_shutdown() are harmless no-ops.)^ -** -** The sqlite3_initialize() interface is threadsafe, but sqlite3_shutdown() -** is not. The sqlite3_shutdown() interface must only be called from a -** single thread. All open [database connections] must be closed and all -** other SQLite resources must be deallocated prior to invoking -** sqlite3_shutdown(). -** -** Among other things, ^sqlite3_initialize() will invoke -** sqlite3_os_init(). Similarly, ^sqlite3_shutdown() -** will invoke sqlite3_os_end(). -** -** ^The sqlite3_initialize() routine returns [SQLITE_OK] on success. -** ^If for some reason, sqlite3_initialize() is unable to initialize -** the library (perhaps it is unable to allocate a needed resource such -** as a mutex) it returns an [error code] other than [SQLITE_OK]. -** -** ^The sqlite3_initialize() routine is called internally by many other -** SQLite interfaces so that an application usually does not need to -** invoke sqlite3_initialize() directly. For example, [sqlite3_open()] -** calls sqlite3_initialize() so the SQLite library will be automatically -** initialized when [sqlite3_open()] is called if it has not be initialized -** already. ^However, if SQLite is compiled with the [SQLITE_OMIT_AUTOINIT] -** compile-time option, then the automatic calls to sqlite3_initialize() -** are omitted and the application must call sqlite3_initialize() directly -** prior to using any other SQLite interface. For maximum portability, -** it is recommended that applications always invoke sqlite3_initialize() -** directly prior to using any other SQLite interface. Future releases -** of SQLite may require this. In other words, the behavior exhibited -** when SQLite is compiled with [SQLITE_OMIT_AUTOINIT] might become the -** default behavior in some future release of SQLite. -** -** The sqlite3_os_init() routine does operating-system specific -** initialization of the SQLite library. The sqlite3_os_end() -** routine undoes the effect of sqlite3_os_init(). Typical tasks -** performed by these routines include allocation or deallocation -** of static resources, initialization of global variables, -** setting up a default [sqlite3_vfs] module, or setting up -** a default configuration using [sqlite3_config()]. -** -** The application should never invoke either sqlite3_os_init() -** or sqlite3_os_end() directly. The application should only invoke -** sqlite3_initialize() and sqlite3_shutdown(). The sqlite3_os_init() -** interface is called automatically by sqlite3_initialize() and -** sqlite3_os_end() is called by sqlite3_shutdown(). Appropriate -** implementations for sqlite3_os_init() and sqlite3_os_end() -** are built into SQLite when it is compiled for Unix, Windows, or OS/2. -** When [custom builds | built for other platforms] -** (using the [SQLITE_OS_OTHER=1] compile-time -** option) the application must supply a suitable implementation for -** sqlite3_os_init() and sqlite3_os_end(). An application-supplied -** implementation of sqlite3_os_init() or sqlite3_os_end() -** must return [SQLITE_OK] on success and some other [error code] upon -** failure. -*/ -SQLITE_API int sqlite3_initialize(void); -SQLITE_API int sqlite3_shutdown(void); -SQLITE_API int sqlite3_os_init(void); -SQLITE_API int sqlite3_os_end(void); - -/* -** CAPI3REF: Configuring The SQLite Library -** -** The sqlite3_config() interface is used to make global configuration -** changes to SQLite in order to tune SQLite to the specific needs of -** the application. The default configuration is recommended for most -** applications and so this routine is usually not necessary. It is -** provided to support rare applications with unusual needs. -** -** The sqlite3_config() interface is not threadsafe. The application -** must ensure that no other SQLite interfaces are invoked by other -** threads while sqlite3_config() is running. -** -** The sqlite3_config() interface -** may only be invoked prior to library initialization using -** [sqlite3_initialize()] or after shutdown by [sqlite3_shutdown()]. -** ^If sqlite3_config() is called after [sqlite3_initialize()] and before -** [sqlite3_shutdown()] then it will return SQLITE_MISUSE. -** Note, however, that ^sqlite3_config() can be called as part of the -** implementation of an application-defined [sqlite3_os_init()]. -** -** The first argument to sqlite3_config() is an integer -** [configuration option] that determines -** what property of SQLite is to be configured. Subsequent arguments -** vary depending on the [configuration option] -** in the first argument. -** -** ^When a configuration option is set, sqlite3_config() returns [SQLITE_OK]. -** ^If the option is unknown or SQLite is unable to set the option -** then this routine returns a non-zero [error code]. -*/ -SQLITE_API int sqlite3_config(int, ...); - -/* -** CAPI3REF: Configure database connections -** METHOD: sqlite3 -** -** The sqlite3_db_config() interface is used to make configuration -** changes to a [database connection]. The interface is similar to -** [sqlite3_config()] except that the changes apply to a single -** [database connection] (specified in the first argument). -** -** The second argument to sqlite3_db_config(D,V,...) is the -** [SQLITE_DBCONFIG_LOOKASIDE | configuration verb] - an integer code -** that indicates what aspect of the [database connection] is being configured. -** Subsequent arguments vary depending on the configuration verb. -** -** ^Calls to sqlite3_db_config() return SQLITE_OK if and only if -** the call is considered successful. -*/ -SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...); - -/* -** CAPI3REF: Memory Allocation Routines -** -** An instance of this object defines the interface between SQLite -** and low-level memory allocation routines. -** -** This object is used in only one place in the SQLite interface. -** A pointer to an instance of this object is the argument to -** [sqlite3_config()] when the configuration option is -** [SQLITE_CONFIG_MALLOC] or [SQLITE_CONFIG_GETMALLOC]. -** By creating an instance of this object -** and passing it to [sqlite3_config]([SQLITE_CONFIG_MALLOC]) -** during configuration, an application can specify an alternative -** memory allocation subsystem for SQLite to use for all of its -** dynamic memory needs. -** -** Note that SQLite comes with several [built-in memory allocators] -** that are perfectly adequate for the overwhelming majority of applications -** and that this object is only useful to a tiny minority of applications -** with specialized memory allocation requirements. This object is -** also used during testing of SQLite in order to specify an alternative -** memory allocator that simulates memory out-of-memory conditions in -** order to verify that SQLite recovers gracefully from such -** conditions. -** -** The xMalloc, xRealloc, and xFree methods must work like the -** malloc(), realloc() and free() functions from the standard C library. -** ^SQLite guarantees that the second argument to -** xRealloc is always a value returned by a prior call to xRoundup. -** -** xSize should return the allocated size of a memory allocation -** previously obtained from xMalloc or xRealloc. The allocated size -** is always at least as big as the requested size but may be larger. -** -** The xRoundup method returns what would be the allocated size of -** a memory allocation given a particular requested size. Most memory -** allocators round up memory allocations at least to the next multiple -** of 8. Some allocators round up to a larger multiple or to a power of 2. -** Every memory allocation request coming in through [sqlite3_malloc()] -** or [sqlite3_realloc()] first calls xRoundup. If xRoundup returns 0, -** that causes the corresponding memory allocation to fail. -** -** The xInit method initializes the memory allocator. For example, -** it might allocate any required mutexes or initialize internal data -** structures. The xShutdown method is invoked (indirectly) by -** [sqlite3_shutdown()] and should deallocate any resources acquired -** by xInit. The pAppData pointer is used as the only parameter to -** xInit and xShutdown. -** -** SQLite holds the [SQLITE_MUTEX_STATIC_MAIN] mutex when it invokes -** the xInit method, so the xInit method need not be threadsafe. The -** xShutdown method is only called from [sqlite3_shutdown()] so it does -** not need to be threadsafe either. For all other methods, SQLite -** holds the [SQLITE_MUTEX_STATIC_MEM] mutex as long as the -** [SQLITE_CONFIG_MEMSTATUS] configuration option is turned on (which -** it is by default) and so the methods are automatically serialized. -** However, if [SQLITE_CONFIG_MEMSTATUS] is disabled, then the other -** methods must be threadsafe or else make their own arrangements for -** serialization. -** -** SQLite will never invoke xInit() more than once without an intervening -** call to xShutdown(). -*/ -typedef struct sqlite3_mem_methods sqlite3_mem_methods; -struct sqlite3_mem_methods { - void *(*xMalloc)(int); /* Memory allocation function */ - void (*xFree)(void*); /* Free a prior allocation */ - void *(*xRealloc)(void*,int); /* Resize an allocation */ - int (*xSize)(void*); /* Return the size of an allocation */ - int (*xRoundup)(int); /* Round up request size to allocation size */ - int (*xInit)(void*); /* Initialize the memory allocator */ - void (*xShutdown)(void*); /* Deinitialize the memory allocator */ - void *pAppData; /* Argument to xInit() and xShutdown() */ -}; +#define SQLITE_SHM_NLOCK 8 + + /* + ** CAPI3REF: Initialize The SQLite Library + ** + ** ^The sqlite3_initialize() routine initializes the + ** SQLite library. ^The sqlite3_shutdown() routine + ** deallocates any resources that were allocated by sqlite3_initialize(). + ** These routines are designed to aid in process initialization and + ** shutdown on embedded systems. Workstation applications using + ** SQLite normally do not need to invoke either of these routines. + ** + ** A call to sqlite3_initialize() is an "effective" call if it is + ** the first time sqlite3_initialize() is invoked during the lifetime of + ** the process, or if it is the first time sqlite3_initialize() is invoked + ** following a call to sqlite3_shutdown(). ^(Only an effective call + ** of sqlite3_initialize() does any initialization. All other calls + ** are harmless no-ops.)^ + ** + ** A call to sqlite3_shutdown() is an "effective" call if it is the first + ** call to sqlite3_shutdown() since the last sqlite3_initialize(). ^(Only + ** an effective call to sqlite3_shutdown() does any deinitialization. + ** All other valid calls to sqlite3_shutdown() are harmless no-ops.)^ + ** + ** The sqlite3_initialize() interface is threadsafe, but sqlite3_shutdown() + ** is not. The sqlite3_shutdown() interface must only be called from a + ** single thread. All open [database connections] must be closed and all + ** other SQLite resources must be deallocated prior to invoking + ** sqlite3_shutdown(). + ** + ** Among other things, ^sqlite3_initialize() will invoke + ** sqlite3_os_init(). Similarly, ^sqlite3_shutdown() + ** will invoke sqlite3_os_end(). + ** + ** ^The sqlite3_initialize() routine returns [SQLITE_OK] on success. + ** ^If for some reason, sqlite3_initialize() is unable to initialize + ** the library (perhaps it is unable to allocate a needed resource such + ** as a mutex) it returns an [error code] other than [SQLITE_OK]. + ** + ** ^The sqlite3_initialize() routine is called internally by many other + ** SQLite interfaces so that an application usually does not need to + ** invoke sqlite3_initialize() directly. For example, [sqlite3_open()] + ** calls sqlite3_initialize() so the SQLite library will be automatically + ** initialized when [sqlite3_open()] is called if it has not be initialized + ** already. ^However, if SQLite is compiled with the [SQLITE_OMIT_AUTOINIT] + ** compile-time option, then the automatic calls to sqlite3_initialize() + ** are omitted and the application must call sqlite3_initialize() directly + ** prior to using any other SQLite interface. For maximum portability, + ** it is recommended that applications always invoke sqlite3_initialize() + ** directly prior to using any other SQLite interface. Future releases + ** of SQLite may require this. In other words, the behavior exhibited + ** when SQLite is compiled with [SQLITE_OMIT_AUTOINIT] might become the + ** default behavior in some future release of SQLite. + ** + ** The sqlite3_os_init() routine does operating-system specific + ** initialization of the SQLite library. The sqlite3_os_end() + ** routine undoes the effect of sqlite3_os_init(). Typical tasks + ** performed by these routines include allocation or deallocation + ** of static resources, initialization of global variables, + ** setting up a default [sqlite3_vfs] module, or setting up + ** a default configuration using [sqlite3_config()]. + ** + ** The application should never invoke either sqlite3_os_init() + ** or sqlite3_os_end() directly. The application should only invoke + ** sqlite3_initialize() and sqlite3_shutdown(). The sqlite3_os_init() + ** interface is called automatically by sqlite3_initialize() and + ** sqlite3_os_end() is called by sqlite3_shutdown(). Appropriate + ** implementations for sqlite3_os_init() and sqlite3_os_end() + ** are built into SQLite when it is compiled for Unix, Windows, or OS/2. + ** When [custom builds | built for other platforms] + ** (using the [SQLITE_OS_OTHER=1] compile-time + ** option) the application must supply a suitable implementation for + ** sqlite3_os_init() and sqlite3_os_end(). An application-supplied + ** implementation of sqlite3_os_init() or sqlite3_os_end() + ** must return [SQLITE_OK] on success and some other [error code] upon + ** failure. + */ + SQLITE_API int sqlite3_initialize(void); + SQLITE_API int sqlite3_shutdown(void); + SQLITE_API int sqlite3_os_init(void); + SQLITE_API int sqlite3_os_end(void); + + /* + ** CAPI3REF: Configuring The SQLite Library + ** + ** The sqlite3_config() interface is used to make global configuration + ** changes to SQLite in order to tune SQLite to the specific needs of + ** the application. The default configuration is recommended for most + ** applications and so this routine is usually not necessary. It is + ** provided to support rare applications with unusual needs. + ** + ** The sqlite3_config() interface is not threadsafe. The application + ** must ensure that no other SQLite interfaces are invoked by other + ** threads while sqlite3_config() is running. + ** + ** The sqlite3_config() interface + ** may only be invoked prior to library initialization using + ** [sqlite3_initialize()] or after shutdown by [sqlite3_shutdown()]. + ** ^If sqlite3_config() is called after [sqlite3_initialize()] and before + ** [sqlite3_shutdown()] then it will return SQLITE_MISUSE. + ** Note, however, that ^sqlite3_config() can be called as part of the + ** implementation of an application-defined [sqlite3_os_init()]. + ** + ** The first argument to sqlite3_config() is an integer + ** [configuration option] that determines + ** what property of SQLite is to be configured. Subsequent arguments + ** vary depending on the [configuration option] + ** in the first argument. + ** + ** ^When a configuration option is set, sqlite3_config() returns [SQLITE_OK]. + ** ^If the option is unknown or SQLite is unable to set the option + ** then this routine returns a non-zero [error code]. + */ + SQLITE_API int sqlite3_config(int, ...); + + /* + ** CAPI3REF: Configure database connections + ** METHOD: sqlite3 + ** + ** The sqlite3_db_config() interface is used to make configuration + ** changes to a [database connection]. The interface is similar to + ** [sqlite3_config()] except that the changes apply to a single + ** [database connection] (specified in the first argument). + ** + ** The second argument to sqlite3_db_config(D,V,...) is the + ** [SQLITE_DBCONFIG_LOOKASIDE | configuration verb] - an integer code + ** that indicates what aspect of the [database connection] is being configured. + ** Subsequent arguments vary depending on the configuration verb. + ** + ** ^Calls to sqlite3_db_config() return SQLITE_OK if and only if + ** the call is considered successful. + */ + SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...); + + /* + ** CAPI3REF: Memory Allocation Routines + ** + ** An instance of this object defines the interface between SQLite + ** and low-level memory allocation routines. + ** + ** This object is used in only one place in the SQLite interface. + ** A pointer to an instance of this object is the argument to + ** [sqlite3_config()] when the configuration option is + ** [SQLITE_CONFIG_MALLOC] or [SQLITE_CONFIG_GETMALLOC]. + ** By creating an instance of this object + ** and passing it to [sqlite3_config]([SQLITE_CONFIG_MALLOC]) + ** during configuration, an application can specify an alternative + ** memory allocation subsystem for SQLite to use for all of its + ** dynamic memory needs. + ** + ** Note that SQLite comes with several [built-in memory allocators] + ** that are perfectly adequate for the overwhelming majority of applications + ** and that this object is only useful to a tiny minority of applications + ** with specialized memory allocation requirements. This object is + ** also used during testing of SQLite in order to specify an alternative + ** memory allocator that simulates memory out-of-memory conditions in + ** order to verify that SQLite recovers gracefully from such + ** conditions. + ** + ** The xMalloc, xRealloc, and xFree methods must work like the + ** malloc(), realloc() and free() functions from the standard C library. + ** ^SQLite guarantees that the second argument to + ** xRealloc is always a value returned by a prior call to xRoundup. + ** + ** xSize should return the allocated size of a memory allocation + ** previously obtained from xMalloc or xRealloc. The allocated size + ** is always at least as big as the requested size but may be larger. + ** + ** The xRoundup method returns what would be the allocated size of + ** a memory allocation given a particular requested size. Most memory + ** allocators round up memory allocations at least to the next multiple + ** of 8. Some allocators round up to a larger multiple or to a power of 2. + ** Every memory allocation request coming in through [sqlite3_malloc()] + ** or [sqlite3_realloc()] first calls xRoundup. If xRoundup returns 0, + ** that causes the corresponding memory allocation to fail. + ** + ** The xInit method initializes the memory allocator. For example, + ** it might allocate any required mutexes or initialize internal data + ** structures. The xShutdown method is invoked (indirectly) by + ** [sqlite3_shutdown()] and should deallocate any resources acquired + ** by xInit. The pAppData pointer is used as the only parameter to + ** xInit and xShutdown. + ** + ** SQLite holds the [SQLITE_MUTEX_STATIC_MAIN] mutex when it invokes + ** the xInit method, so the xInit method need not be threadsafe. The + ** xShutdown method is only called from [sqlite3_shutdown()] so it does + ** not need to be threadsafe either. For all other methods, SQLite + ** holds the [SQLITE_MUTEX_STATIC_MEM] mutex as long as the + ** [SQLITE_CONFIG_MEMSTATUS] configuration option is turned on (which + ** it is by default) and so the methods are automatically serialized. + ** However, if [SQLITE_CONFIG_MEMSTATUS] is disabled, then the other + ** methods must be threadsafe or else make their own arrangements for + ** serialization. + ** + ** SQLite will never invoke xInit() more than once without an intervening + ** call to xShutdown(). + */ + typedef struct sqlite3_mem_methods sqlite3_mem_methods; + struct sqlite3_mem_methods + { + void* (*xMalloc)(int); /* Memory allocation function */ + void (*xFree)(void*); /* Free a prior allocation */ + void* (*xRealloc)(void*, int); /* Resize an allocation */ + int (*xSize)(void*); /* Return the size of an allocation */ + int (*xRoundup)(int); /* Round up request size to allocation size */ + int (*xInit)(void*); /* Initialize the memory allocator */ + void (*xShutdown)(void*); /* Deinitialize the memory allocator */ + void* pAppData; /* Argument to xInit() and xShutdown() */ + }; /* ** CAPI3REF: Configuration Options @@ -2085,35 +2084,35 @@ struct sqlite3_mem_methods { ** compile-time option is not set, then the default maximum is 1073741824. ** */ -#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ -#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */ -#define SQLITE_CONFIG_SERIALIZED 3 /* nil */ -#define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */ -#define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */ -#define SQLITE_CONFIG_SCRATCH 6 /* No longer used */ -#define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */ -#define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */ -#define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */ -#define SQLITE_CONFIG_MUTEX 10 /* sqlite3_mutex_methods* */ -#define SQLITE_CONFIG_GETMUTEX 11 /* sqlite3_mutex_methods* */ +#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ +#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */ +#define SQLITE_CONFIG_SERIALIZED 3 /* nil */ +#define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */ +#define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */ +#define SQLITE_CONFIG_SCRATCH 6 /* No longer used */ +#define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */ +#define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */ +#define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */ +#define SQLITE_CONFIG_MUTEX 10 /* sqlite3_mutex_methods* */ +#define SQLITE_CONFIG_GETMUTEX 11 /* sqlite3_mutex_methods* */ /* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */ -#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */ -#define SQLITE_CONFIG_PCACHE 14 /* no-op */ -#define SQLITE_CONFIG_GETPCACHE 15 /* no-op */ -#define SQLITE_CONFIG_LOG 16 /* xFunc, void* */ -#define SQLITE_CONFIG_URI 17 /* int */ -#define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */ -#define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */ -#define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */ -#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */ -#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */ -#define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */ -#define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */ -#define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */ -#define SQLITE_CONFIG_STMTJRNL_SPILL 26 /* int nByte */ -#define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */ -#define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */ -#define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlite3_int64 */ +#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */ +#define SQLITE_CONFIG_PCACHE 14 /* no-op */ +#define SQLITE_CONFIG_GETPCACHE 15 /* no-op */ +#define SQLITE_CONFIG_LOG 16 /* xFunc, void* */ +#define SQLITE_CONFIG_URI 17 /* int */ +#define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */ +#define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */ +#define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */ +#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */ +#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */ +#define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */ +#define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */ +#define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */ +#define SQLITE_CONFIG_STMTJRNL_SPILL 26 /* int nByte */ +#define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */ +#define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */ +#define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlite3_int64 */ /* ** CAPI3REF: Database Connection Configuration Options @@ -2396,722 +2395,719 @@ struct sqlite3_mem_methods { ** ** */ -#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */ -#define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */ -#define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */ -#define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */ +#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */ +#define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */ +#define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */ +#define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER 1004 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1005 /* int int* */ -#define SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE 1006 /* int int* */ -#define SQLITE_DBCONFIG_ENABLE_QPSG 1007 /* int int* */ -#define SQLITE_DBCONFIG_TRIGGER_EQP 1008 /* int int* */ -#define SQLITE_DBCONFIG_RESET_DATABASE 1009 /* int int* */ -#define SQLITE_DBCONFIG_DEFENSIVE 1010 /* int int* */ -#define SQLITE_DBCONFIG_WRITABLE_SCHEMA 1011 /* int int* */ -#define SQLITE_DBCONFIG_LEGACY_ALTER_TABLE 1012 /* int int* */ -#define SQLITE_DBCONFIG_DQS_DML 1013 /* int int* */ -#define SQLITE_DBCONFIG_DQS_DDL 1014 /* int int* */ -#define SQLITE_DBCONFIG_ENABLE_VIEW 1015 /* int int* */ -#define SQLITE_DBCONFIG_LEGACY_FILE_FORMAT 1016 /* int int* */ -#define SQLITE_DBCONFIG_TRUSTED_SCHEMA 1017 /* int int* */ -#define SQLITE_DBCONFIG_MAX 1017 /* Largest DBCONFIG */ - -/* -** CAPI3REF: Enable Or Disable Extended Result Codes -** METHOD: sqlite3 -** -** ^The sqlite3_extended_result_codes() routine enables or disables the -** [extended result codes] feature of SQLite. ^The extended result -** codes are disabled by default for historical compatibility. -*/ -SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff); - -/* -** CAPI3REF: Last Insert Rowid -** METHOD: sqlite3 -** -** ^Each entry in most SQLite tables (except for [WITHOUT ROWID] tables) -** has a unique 64-bit signed -** integer key called the [ROWID | "rowid"]. ^The rowid is always available -** as an undeclared column named ROWID, OID, or _ROWID_ as long as those -** names are not also used by explicitly declared columns. ^If -** the table has a column of type [INTEGER PRIMARY KEY] then that column -** is another alias for the rowid. -** -** ^The sqlite3_last_insert_rowid(D) interface usually returns the [rowid] of -** the most recent successful [INSERT] into a rowid table or [virtual table] -** on database connection D. ^Inserts into [WITHOUT ROWID] tables are not -** recorded. ^If no successful [INSERT]s into rowid tables have ever occurred -** on the database connection D, then sqlite3_last_insert_rowid(D) returns -** zero. -** -** As well as being set automatically as rows are inserted into database -** tables, the value returned by this function may be set explicitly by -** [sqlite3_set_last_insert_rowid()] -** -** Some virtual table implementations may INSERT rows into rowid tables as -** part of committing a transaction (e.g. to flush data accumulated in memory -** to disk). In this case subsequent calls to this function return the rowid -** associated with these internal INSERT operations, which leads to -** unintuitive results. Virtual table implementations that do write to rowid -** tables in this way can avoid this problem by restoring the original -** rowid value using [sqlite3_set_last_insert_rowid()] before returning -** control to the user. -** -** ^(If an [INSERT] occurs within a trigger then this routine will -** return the [rowid] of the inserted row as long as the trigger is -** running. Once the trigger program ends, the value returned -** by this routine reverts to what it was before the trigger was fired.)^ -** -** ^An [INSERT] that fails due to a constraint violation is not a -** successful [INSERT] and does not change the value returned by this -** routine. ^Thus INSERT OR FAIL, INSERT OR IGNORE, INSERT OR ROLLBACK, -** and INSERT OR ABORT make no changes to the return value of this -** routine when their insertion fails. ^(When INSERT OR REPLACE -** encounters a constraint violation, it does not fail. The -** INSERT continues to completion after deleting rows that caused -** the constraint problem so INSERT OR REPLACE will always change -** the return value of this interface.)^ -** -** ^For the purposes of this routine, an [INSERT] is considered to -** be successful even if it is subsequently rolled back. -** -** This function is accessible to SQL statements via the -** [last_insert_rowid() SQL function]. -** -** If a separate thread performs a new [INSERT] on the same -** database connection while the [sqlite3_last_insert_rowid()] -** function is running and thus changes the last insert [rowid], -** then the value returned by [sqlite3_last_insert_rowid()] is -** unpredictable and might not equal either the old or the new -** last insert [rowid]. -*/ -SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*); - -/* -** CAPI3REF: Set the Last Insert Rowid value. -** METHOD: sqlite3 -** -** The sqlite3_set_last_insert_rowid(D, R) method allows the application to -** set the value returned by calling sqlite3_last_insert_rowid(D) to R -** without inserting a row into the database. -*/ -SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64); - -/* -** CAPI3REF: Count The Number Of Rows Modified -** METHOD: sqlite3 -** -** ^These functions return the number of rows modified, inserted or -** deleted by the most recently completed INSERT, UPDATE or DELETE -** statement on the database connection specified by the only parameter. -** The two functions are identical except for the type of the return value -** and that if the number of rows modified by the most recent INSERT, UPDATE -** or DELETE is greater than the maximum value supported by type "int", then -** the return value of sqlite3_changes() is undefined. ^Executing any other -** type of SQL statement does not modify the value returned by these functions. -** -** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are -** considered - auxiliary changes caused by [CREATE TRIGGER | triggers], -** [foreign key actions] or [REPLACE] constraint resolution are not counted. -** -** Changes to a view that are intercepted by -** [INSTEAD OF trigger | INSTEAD OF triggers] are not counted. ^The value -** returned by sqlite3_changes() immediately after an INSERT, UPDATE or -** DELETE statement run on a view is always zero. Only changes made to real -** tables are counted. -** -** Things are more complicated if the sqlite3_changes() function is -** executed while a trigger program is running. This may happen if the -** program uses the [changes() SQL function], or if some other callback -** function invokes sqlite3_changes() directly. Essentially: -** -**
    -**
  • ^(Before entering a trigger program the value returned by -** sqlite3_changes() function is saved. After the trigger program -** has finished, the original value is restored.)^ -** -**
  • ^(Within a trigger program each INSERT, UPDATE and DELETE -** statement sets the value returned by sqlite3_changes() -** upon completion as normal. Of course, this value will not include -** any changes performed by sub-triggers, as the sqlite3_changes() -** value will be saved and restored after each sub-trigger has run.)^ -**
-** -** ^This means that if the changes() SQL function (or similar) is used -** by the first INSERT, UPDATE or DELETE statement within a trigger, it -** returns the value as set when the calling statement began executing. -** ^If it is used by the second or subsequent such statement within a trigger -** program, the value returned reflects the number of rows modified by the -** previous INSERT, UPDATE or DELETE statement within the same trigger. -** -** If a separate thread makes changes on the same database connection -** while [sqlite3_changes()] is running then the value returned -** is unpredictable and not meaningful. -** -** See also: -**
    -**
  • the [sqlite3_total_changes()] interface -**
  • the [count_changes pragma] -**
  • the [changes() SQL function] -**
  • the [data_version pragma] -**
-*/ -SQLITE_API int sqlite3_changes(sqlite3*); -SQLITE_API sqlite3_int64 sqlite3_changes64(sqlite3*); - -/* -** CAPI3REF: Total Number Of Rows Modified -** METHOD: sqlite3 -** -** ^These functions return the total number of rows inserted, modified or -** deleted by all [INSERT], [UPDATE] or [DELETE] statements completed -** since the database connection was opened, including those executed as -** part of trigger programs. The two functions are identical except for the -** type of the return value and that if the number of rows modified by the -** connection exceeds the maximum value supported by type "int", then -** the return value of sqlite3_total_changes() is undefined. ^Executing -** any other type of SQL statement does not affect the value returned by -** sqlite3_total_changes(). -** -** ^Changes made as part of [foreign key actions] are included in the -** count, but those made as part of REPLACE constraint resolution are -** not. ^Changes to a view that are intercepted by INSTEAD OF triggers -** are not counted. -** -** The [sqlite3_total_changes(D)] interface only reports the number -** of rows that changed due to SQL statement run against database -** connection D. Any changes by other database connections are ignored. -** To detect changes against a database file from other database -** connections use the [PRAGMA data_version] command or the -** [SQLITE_FCNTL_DATA_VERSION] [file control]. -** -** If a separate thread makes changes on the same database connection -** while [sqlite3_total_changes()] is running then the value -** returned is unpredictable and not meaningful. -** -** See also: -**
    -**
  • the [sqlite3_changes()] interface -**
  • the [count_changes pragma] -**
  • the [changes() SQL function] -**
  • the [data_version pragma] -**
  • the [SQLITE_FCNTL_DATA_VERSION] [file control] -**
-*/ -SQLITE_API int sqlite3_total_changes(sqlite3*); -SQLITE_API sqlite3_int64 sqlite3_total_changes64(sqlite3*); - -/* -** CAPI3REF: Interrupt A Long-Running Query -** METHOD: sqlite3 -** -** ^This function causes any pending database operation to abort and -** return at its earliest opportunity. This routine is typically -** called in response to a user action such as pressing "Cancel" -** or Ctrl-C where the user wants a long query operation to halt -** immediately. -** -** ^It is safe to call this routine from a thread different from the -** thread that is currently running the database operation. But it -** is not safe to call this routine with a [database connection] that -** is closed or might close before sqlite3_interrupt() returns. -** -** ^If an SQL operation is very nearly finished at the time when -** sqlite3_interrupt() is called, then it might not have an opportunity -** to be interrupted and might continue to completion. -** -** ^An SQL operation that is interrupted will return [SQLITE_INTERRUPT]. -** ^If the interrupted SQL operation is an INSERT, UPDATE, or DELETE -** that is inside an explicit transaction, then the entire transaction -** will be rolled back automatically. -** -** ^The sqlite3_interrupt(D) call is in effect until all currently running -** SQL statements on [database connection] D complete. ^Any new SQL statements -** that are started after the sqlite3_interrupt() call and before the -** running statement count reaches zero are interrupted as if they had been -** running prior to the sqlite3_interrupt() call. ^New SQL statements -** that are started after the running statement count reaches zero are -** not effected by the sqlite3_interrupt(). -** ^A call to sqlite3_interrupt(D) that occurs when there are no running -** SQL statements is a no-op and has no effect on SQL statements -** that are started after the sqlite3_interrupt() call returns. -*/ -SQLITE_API void sqlite3_interrupt(sqlite3*); - -/* -** CAPI3REF: Determine If An SQL Statement Is Complete -** -** These routines are useful during command-line input to determine if the -** currently entered text seems to form a complete SQL statement or -** if additional input is needed before sending the text into -** SQLite for parsing. ^These routines return 1 if the input string -** appears to be a complete SQL statement. ^A statement is judged to be -** complete if it ends with a semicolon token and is not a prefix of a -** well-formed CREATE TRIGGER statement. ^Semicolons that are embedded within -** string literals or quoted identifier names or comments are not -** independent tokens (they are part of the token in which they are -** embedded) and thus do not count as a statement terminator. ^Whitespace -** and comments that follow the final semicolon are ignored. -** -** ^These routines return 0 if the statement is incomplete. ^If a -** memory allocation fails, then SQLITE_NOMEM is returned. -** -** ^These routines do not parse the SQL statements thus -** will not detect syntactically incorrect SQL. -** -** ^(If SQLite has not been initialized using [sqlite3_initialize()] prior -** to invoking sqlite3_complete16() then sqlite3_initialize() is invoked -** automatically by sqlite3_complete16(). If that initialization fails, -** then the return value from sqlite3_complete16() will be non-zero -** regardless of whether or not the input SQL is complete.)^ -** -** The input to [sqlite3_complete()] must be a zero-terminated -** UTF-8 string. -** -** The input to [sqlite3_complete16()] must be a zero-terminated -** UTF-16 string in native byte order. -*/ -SQLITE_API int sqlite3_complete(const char *sql); -SQLITE_API int sqlite3_complete16(const void *sql); - -/* -** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors -** KEYWORDS: {busy-handler callback} {busy handler} -** METHOD: sqlite3 -** -** ^The sqlite3_busy_handler(D,X,P) routine sets a callback function X -** that might be invoked with argument P whenever -** an attempt is made to access a database table associated with -** [database connection] D when another thread -** or process has the table locked. -** The sqlite3_busy_handler() interface is used to implement -** [sqlite3_busy_timeout()] and [PRAGMA busy_timeout]. -** -** ^If the busy callback is NULL, then [SQLITE_BUSY] -** is returned immediately upon encountering the lock. ^If the busy callback -** is not NULL, then the callback might be invoked with two arguments. -** -** ^The first argument to the busy handler is a copy of the void* pointer which -** is the third argument to sqlite3_busy_handler(). ^The second argument to -** the busy handler callback is the number of times that the busy handler has -** been invoked previously for the same locking event. ^If the -** busy callback returns 0, then no additional attempts are made to -** access the database and [SQLITE_BUSY] is returned -** to the application. -** ^If the callback returns non-zero, then another attempt -** is made to access the database and the cycle repeats. -** -** The presence of a busy handler does not guarantee that it will be invoked -** when there is lock contention. ^If SQLite determines that invoking the busy -** handler could result in a deadlock, it will go ahead and return [SQLITE_BUSY] -** to the application instead of invoking the -** busy handler. -** Consider a scenario where one process is holding a read lock that -** it is trying to promote to a reserved lock and -** a second process is holding a reserved lock that it is trying -** to promote to an exclusive lock. The first process cannot proceed -** because it is blocked by the second and the second process cannot -** proceed because it is blocked by the first. If both processes -** invoke the busy handlers, neither will make any progress. Therefore, -** SQLite returns [SQLITE_BUSY] for the first process, hoping that this -** will induce the first process to release its read lock and allow -** the second process to proceed. -** -** ^The default busy callback is NULL. -** -** ^(There can only be a single busy handler defined for each -** [database connection]. Setting a new busy handler clears any -** previously set handler.)^ ^Note that calling [sqlite3_busy_timeout()] -** or evaluating [PRAGMA busy_timeout=N] will change the -** busy handler and thus clear any previously set busy handler. -** -** The busy callback should not take any actions which modify the -** database connection that invoked the busy handler. In other words, -** the busy handler is not reentrant. Any such actions -** result in undefined behavior. -** -** A busy handler must not close the database connection -** or [prepared statement] that invoked the busy handler. -*/ -SQLITE_API int sqlite3_busy_handler(sqlite3*,int(*)(void*,int),void*); - -/* -** CAPI3REF: Set A Busy Timeout -** METHOD: sqlite3 -** -** ^This routine sets a [sqlite3_busy_handler | busy handler] that sleeps -** for a specified amount of time when a table is locked. ^The handler -** will sleep multiple times until at least "ms" milliseconds of sleeping -** have accumulated. ^After at least "ms" milliseconds of sleeping, -** the handler returns 0 which causes [sqlite3_step()] to return -** [SQLITE_BUSY]. -** -** ^Calling this routine with an argument less than or equal to zero -** turns off all busy handlers. -** -** ^(There can only be a single busy handler for a particular -** [database connection] at any given moment. If another busy handler -** was defined (using [sqlite3_busy_handler()]) prior to calling -** this routine, that other busy handler is cleared.)^ -** -** See also: [PRAGMA busy_timeout] -*/ -SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms); - -/* -** CAPI3REF: Convenience Routines For Running Queries -** METHOD: sqlite3 -** -** This is a legacy interface that is preserved for backwards compatibility. -** Use of this interface is not recommended. -** -** Definition: A result table is memory data structure created by the -** [sqlite3_get_table()] interface. A result table records the -** complete query results from one or more queries. -** -** The table conceptually has a number of rows and columns. But -** these numbers are not part of the result table itself. These -** numbers are obtained separately. Let N be the number of rows -** and M be the number of columns. -** -** A result table is an array of pointers to zero-terminated UTF-8 strings. -** There are (N+1)*M elements in the array. The first M pointers point -** to zero-terminated strings that contain the names of the columns. -** The remaining entries all point to query results. NULL values result -** in NULL pointers. All other values are in their UTF-8 zero-terminated -** string representation as returned by [sqlite3_column_text()]. -** -** A result table might consist of one or more memory allocations. -** It is not safe to pass a result table directly to [sqlite3_free()]. -** A result table should be deallocated using [sqlite3_free_table()]. -** -** ^(As an example of the result table format, suppose a query result -** is as follows: -** -**
-**        Name        | Age
-**        -----------------------
-**        Alice       | 43
-**        Bob         | 28
-**        Cindy       | 21
-** 
-** -** There are two columns (M==2) and three rows (N==3). Thus the -** result table has 8 entries. Suppose the result table is stored -** in an array named azResult. Then azResult holds this content: -** -**
-**        azResult[0] = "Name";
-**        azResult[1] = "Age";
-**        azResult[2] = "Alice";
-**        azResult[3] = "43";
-**        azResult[4] = "Bob";
-**        azResult[5] = "28";
-**        azResult[6] = "Cindy";
-**        azResult[7] = "21";
-** 
)^ -** -** ^The sqlite3_get_table() function evaluates one or more -** semicolon-separated SQL statements in the zero-terminated UTF-8 -** string of its 2nd parameter and returns a result table to the -** pointer given in its 3rd parameter. -** -** After the application has finished with the result from sqlite3_get_table(), -** it must pass the result table pointer to sqlite3_free_table() in order to -** release the memory that was malloced. Because of the way the -** [sqlite3_malloc()] happens within sqlite3_get_table(), the calling -** function must not try to call [sqlite3_free()] directly. Only -** [sqlite3_free_table()] is able to release the memory properly and safely. -** -** The sqlite3_get_table() interface is implemented as a wrapper around -** [sqlite3_exec()]. The sqlite3_get_table() routine does not have access -** to any internal data structures of SQLite. It uses only the public -** interface defined here. As a consequence, errors that occur in the -** wrapper layer outside of the internal [sqlite3_exec()] call are not -** reflected in subsequent calls to [sqlite3_errcode()] or -** [sqlite3_errmsg()]. -*/ -SQLITE_API int sqlite3_get_table( - sqlite3 *db, /* An open database */ - const char *zSql, /* SQL to be evaluated */ - char ***pazResult, /* Results of the query */ - int *pnRow, /* Number of result rows written here */ - int *pnColumn, /* Number of result columns written here */ - char **pzErrmsg /* Error msg written here */ -); -SQLITE_API void sqlite3_free_table(char **result); - -/* -** CAPI3REF: Formatted String Printing Functions -** -** These routines are work-alikes of the "printf()" family of functions -** from the standard C library. -** These routines understand most of the common formatting options from -** the standard library printf() -** plus some additional non-standard formats ([%q], [%Q], [%w], and [%z]). -** See the [built-in printf()] documentation for details. -** -** ^The sqlite3_mprintf() and sqlite3_vmprintf() routines write their -** results into memory obtained from [sqlite3_malloc64()]. -** The strings returned by these two routines should be -** released by [sqlite3_free()]. ^Both routines return a -** NULL pointer if [sqlite3_malloc64()] is unable to allocate enough -** memory to hold the resulting string. -** -** ^(The sqlite3_snprintf() routine is similar to "snprintf()" from -** the standard C library. The result is written into the -** buffer supplied as the second parameter whose size is given by -** the first parameter. Note that the order of the -** first two parameters is reversed from snprintf().)^ This is an -** historical accident that cannot be fixed without breaking -** backwards compatibility. ^(Note also that sqlite3_snprintf() -** returns a pointer to its buffer instead of the number of -** characters actually written into the buffer.)^ We admit that -** the number of characters written would be a more useful return -** value but we cannot change the implementation of sqlite3_snprintf() -** now without breaking compatibility. -** -** ^As long as the buffer size is greater than zero, sqlite3_snprintf() -** guarantees that the buffer is always zero-terminated. ^The first -** parameter "n" is the total size of the buffer, including space for -** the zero terminator. So the longest string that can be completely -** written will be n-1 characters. -** -** ^The sqlite3_vsnprintf() routine is a varargs version of sqlite3_snprintf(). -** -** See also: [built-in printf()], [printf() SQL function] -*/ -SQLITE_API char *sqlite3_mprintf(const char*,...); -SQLITE_API char *sqlite3_vmprintf(const char*, va_list); -SQLITE_API char *sqlite3_snprintf(int,char*,const char*, ...); -SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list); - -/* -** CAPI3REF: Memory Allocation Subsystem -** -** The SQLite core uses these three routines for all of its own -** internal memory allocation needs. "Core" in the previous sentence -** does not include operating-system specific [VFS] implementation. The -** Windows VFS uses native malloc() and free() for some operations. -** -** ^The sqlite3_malloc() routine returns a pointer to a block -** of memory at least N bytes in length, where N is the parameter. -** ^If sqlite3_malloc() is unable to obtain sufficient free -** memory, it returns a NULL pointer. ^If the parameter N to -** sqlite3_malloc() is zero or negative then sqlite3_malloc() returns -** a NULL pointer. -** -** ^The sqlite3_malloc64(N) routine works just like -** sqlite3_malloc(N) except that N is an unsigned 64-bit integer instead -** of a signed 32-bit integer. -** -** ^Calling sqlite3_free() with a pointer previously returned -** by sqlite3_malloc() or sqlite3_realloc() releases that memory so -** that it might be reused. ^The sqlite3_free() routine is -** a no-op if is called with a NULL pointer. Passing a NULL pointer -** to sqlite3_free() is harmless. After being freed, memory -** should neither be read nor written. Even reading previously freed -** memory might result in a segmentation fault or other severe error. -** Memory corruption, a segmentation fault, or other severe error -** might result if sqlite3_free() is called with a non-NULL pointer that -** was not obtained from sqlite3_malloc() or sqlite3_realloc(). -** -** ^The sqlite3_realloc(X,N) interface attempts to resize a -** prior memory allocation X to be at least N bytes. -** ^If the X parameter to sqlite3_realloc(X,N) -** is a NULL pointer then its behavior is identical to calling -** sqlite3_malloc(N). -** ^If the N parameter to sqlite3_realloc(X,N) is zero or -** negative then the behavior is exactly the same as calling -** sqlite3_free(X). -** ^sqlite3_realloc(X,N) returns a pointer to a memory allocation -** of at least N bytes in size or NULL if insufficient memory is available. -** ^If M is the size of the prior allocation, then min(N,M) bytes -** of the prior allocation are copied into the beginning of buffer returned -** by sqlite3_realloc(X,N) and the prior allocation is freed. -** ^If sqlite3_realloc(X,N) returns NULL and N is positive, then the -** prior allocation is not freed. -** -** ^The sqlite3_realloc64(X,N) interfaces works the same as -** sqlite3_realloc(X,N) except that N is a 64-bit unsigned integer instead -** of a 32-bit signed integer. -** -** ^If X is a memory allocation previously obtained from sqlite3_malloc(), -** sqlite3_malloc64(), sqlite3_realloc(), or sqlite3_realloc64(), then -** sqlite3_msize(X) returns the size of that memory allocation in bytes. -** ^The value returned by sqlite3_msize(X) might be larger than the number -** of bytes requested when X was allocated. ^If X is a NULL pointer then -** sqlite3_msize(X) returns zero. If X points to something that is not -** the beginning of memory allocation, or if it points to a formerly -** valid memory allocation that has now been freed, then the behavior -** of sqlite3_msize(X) is undefined and possibly harmful. -** -** ^The memory returned by sqlite3_malloc(), sqlite3_realloc(), -** sqlite3_malloc64(), and sqlite3_realloc64() -** is always aligned to at least an 8 byte boundary, or to a -** 4 byte boundary if the [SQLITE_4_BYTE_ALIGNED_MALLOC] compile-time -** option is used. -** -** The pointer arguments to [sqlite3_free()] and [sqlite3_realloc()] -** must be either NULL or else pointers obtained from a prior -** invocation of [sqlite3_malloc()] or [sqlite3_realloc()] that have -** not yet been released. -** -** The application must not read or write any part of -** a block of memory after it has been released using -** [sqlite3_free()] or [sqlite3_realloc()]. -*/ -SQLITE_API void *sqlite3_malloc(int); -SQLITE_API void *sqlite3_malloc64(sqlite3_uint64); -SQLITE_API void *sqlite3_realloc(void*, int); -SQLITE_API void *sqlite3_realloc64(void*, sqlite3_uint64); -SQLITE_API void sqlite3_free(void*); -SQLITE_API sqlite3_uint64 sqlite3_msize(void*); - -/* -** CAPI3REF: Memory Allocator Statistics -** -** SQLite provides these two interfaces for reporting on the status -** of the [sqlite3_malloc()], [sqlite3_free()], and [sqlite3_realloc()] -** routines, which form the built-in memory allocation subsystem. -** -** ^The [sqlite3_memory_used()] routine returns the number of bytes -** of memory currently outstanding (malloced but not freed). -** ^The [sqlite3_memory_highwater()] routine returns the maximum -** value of [sqlite3_memory_used()] since the high-water mark -** was last reset. ^The values returned by [sqlite3_memory_used()] and -** [sqlite3_memory_highwater()] include any overhead -** added by SQLite in its implementation of [sqlite3_malloc()], -** but not overhead added by the any underlying system library -** routines that [sqlite3_malloc()] may call. -** -** ^The memory high-water mark is reset to the current value of -** [sqlite3_memory_used()] if and only if the parameter to -** [sqlite3_memory_highwater()] is true. ^The value returned -** by [sqlite3_memory_highwater(1)] is the high-water mark -** prior to the reset. -*/ -SQLITE_API sqlite3_int64 sqlite3_memory_used(void); -SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag); - -/* -** CAPI3REF: Pseudo-Random Number Generator -** -** SQLite contains a high-quality pseudo-random number generator (PRNG) used to -** select random [ROWID | ROWIDs] when inserting new records into a table that -** already uses the largest possible [ROWID]. The PRNG is also used for -** the built-in random() and randomblob() SQL functions. This interface allows -** applications to access the same PRNG for other purposes. -** -** ^A call to this routine stores N bytes of randomness into buffer P. -** ^The P parameter can be a NULL pointer. -** -** ^If this routine has not been previously called or if the previous -** call had N less than one or a NULL pointer for P, then the PRNG is -** seeded using randomness obtained from the xRandomness method of -** the default [sqlite3_vfs] object. -** ^If the previous call to this routine had an N of 1 or more and a -** non-NULL P then the pseudo-randomness is generated -** internally and without recourse to the [sqlite3_vfs] xRandomness -** method. -*/ -SQLITE_API void sqlite3_randomness(int N, void *P); - -/* -** CAPI3REF: Compile-Time Authorization Callbacks -** METHOD: sqlite3 -** KEYWORDS: {authorizer callback} -** -** ^This routine registers an authorizer callback with a particular -** [database connection], supplied in the first argument. -** ^The authorizer callback is invoked as SQL statements are being compiled -** by [sqlite3_prepare()] or its variants [sqlite3_prepare_v2()], -** [sqlite3_prepare_v3()], [sqlite3_prepare16()], [sqlite3_prepare16_v2()], -** and [sqlite3_prepare16_v3()]. ^At various -** points during the compilation process, as logic is being created -** to perform various actions, the authorizer callback is invoked to -** see if those actions are allowed. ^The authorizer callback should -** return [SQLITE_OK] to allow the action, [SQLITE_IGNORE] to disallow the -** specific action but allow the SQL statement to continue to be -** compiled, or [SQLITE_DENY] to cause the entire SQL statement to be -** rejected with an error. ^If the authorizer callback returns -** any value other than [SQLITE_IGNORE], [SQLITE_OK], or [SQLITE_DENY] -** then the [sqlite3_prepare_v2()] or equivalent call that triggered -** the authorizer will fail with an error message. -** -** When the callback returns [SQLITE_OK], that means the operation -** requested is ok. ^When the callback returns [SQLITE_DENY], the -** [sqlite3_prepare_v2()] or equivalent call that triggered the -** authorizer will fail with an error message explaining that -** access is denied. -** -** ^The first parameter to the authorizer callback is a copy of the third -** parameter to the sqlite3_set_authorizer() interface. ^The second parameter -** to the callback is an integer [SQLITE_COPY | action code] that specifies -** the particular action to be authorized. ^The third through sixth parameters -** to the callback are either NULL pointers or zero-terminated strings -** that contain additional details about the action to be authorized. -** Applications must always be prepared to encounter a NULL pointer in any -** of the third through the sixth parameters of the authorization callback. -** -** ^If the action code is [SQLITE_READ] -** and the callback returns [SQLITE_IGNORE] then the -** [prepared statement] statement is constructed to substitute -** a NULL value in place of the table column that would have -** been read if [SQLITE_OK] had been returned. The [SQLITE_IGNORE] -** return can be used to deny an untrusted user access to individual -** columns of a table. -** ^When a table is referenced by a [SELECT] but no column values are -** extracted from that table (for example in a query like -** "SELECT count(*) FROM tab") then the [SQLITE_READ] authorizer callback -** is invoked once for that table with a column name that is an empty string. -** ^If the action code is [SQLITE_DELETE] and the callback returns -** [SQLITE_IGNORE] then the [DELETE] operation proceeds but the -** [truncate optimization] is disabled and all rows are deleted individually. -** -** An authorizer is used when [sqlite3_prepare | preparing] -** SQL statements from an untrusted source, to ensure that the SQL statements -** do not try to access data they are not allowed to see, or that they do not -** try to execute malicious statements that damage the database. For -** example, an application may allow a user to enter arbitrary -** SQL queries for evaluation by a database. But the application does -** not want the user to be able to make arbitrary changes to the -** database. An authorizer could then be put in place while the -** user-entered SQL is being [sqlite3_prepare | prepared] that -** disallows everything except [SELECT] statements. -** -** Applications that need to process SQL from untrusted sources -** might also consider lowering resource limits using [sqlite3_limit()] -** and limiting database size using the [max_page_count] [PRAGMA] -** in addition to using an authorizer. -** -** ^(Only a single authorizer can be in place on a database connection -** at a time. Each call to sqlite3_set_authorizer overrides the -** previous call.)^ ^Disable the authorizer by installing a NULL callback. -** The authorizer is disabled by default. -** -** The authorizer callback must not do anything that will modify -** the database connection that invoked the authorizer callback. -** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their -** database connections for the meaning of "modify" in this paragraph. -** -** ^When [sqlite3_prepare_v2()] is used to prepare a statement, the -** statement might be re-prepared during [sqlite3_step()] due to a -** schema change. Hence, the application should ensure that the -** correct authorizer callback remains in place during the [sqlite3_step()]. -** -** ^Note that the authorizer callback is invoked only during -** [sqlite3_prepare()] or its variants. Authorization is not -** performed during statement evaluation in [sqlite3_step()], unless -** as stated in the previous paragraph, sqlite3_step() invokes -** sqlite3_prepare_v2() to reprepare a statement after a schema change. -*/ -SQLITE_API int sqlite3_set_authorizer( - sqlite3*, - int (*xAuth)(void*,int,const char*,const char*,const char*,const char*), - void *pUserData -); +#define SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE 1006 /* int int* */ +#define SQLITE_DBCONFIG_ENABLE_QPSG 1007 /* int int* */ +#define SQLITE_DBCONFIG_TRIGGER_EQP 1008 /* int int* */ +#define SQLITE_DBCONFIG_RESET_DATABASE 1009 /* int int* */ +#define SQLITE_DBCONFIG_DEFENSIVE 1010 /* int int* */ +#define SQLITE_DBCONFIG_WRITABLE_SCHEMA 1011 /* int int* */ +#define SQLITE_DBCONFIG_LEGACY_ALTER_TABLE 1012 /* int int* */ +#define SQLITE_DBCONFIG_DQS_DML 1013 /* int int* */ +#define SQLITE_DBCONFIG_DQS_DDL 1014 /* int int* */ +#define SQLITE_DBCONFIG_ENABLE_VIEW 1015 /* int int* */ +#define SQLITE_DBCONFIG_LEGACY_FILE_FORMAT 1016 /* int int* */ +#define SQLITE_DBCONFIG_TRUSTED_SCHEMA 1017 /* int int* */ +#define SQLITE_DBCONFIG_MAX 1017 /* Largest DBCONFIG */ + + /* + ** CAPI3REF: Enable Or Disable Extended Result Codes + ** METHOD: sqlite3 + ** + ** ^The sqlite3_extended_result_codes() routine enables or disables the + ** [extended result codes] feature of SQLite. ^The extended result + ** codes are disabled by default for historical compatibility. + */ + SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff); + + /* + ** CAPI3REF: Last Insert Rowid + ** METHOD: sqlite3 + ** + ** ^Each entry in most SQLite tables (except for [WITHOUT ROWID] tables) + ** has a unique 64-bit signed + ** integer key called the [ROWID | "rowid"]. ^The rowid is always available + ** as an undeclared column named ROWID, OID, or _ROWID_ as long as those + ** names are not also used by explicitly declared columns. ^If + ** the table has a column of type [INTEGER PRIMARY KEY] then that column + ** is another alias for the rowid. + ** + ** ^The sqlite3_last_insert_rowid(D) interface usually returns the [rowid] of + ** the most recent successful [INSERT] into a rowid table or [virtual table] + ** on database connection D. ^Inserts into [WITHOUT ROWID] tables are not + ** recorded. ^If no successful [INSERT]s into rowid tables have ever occurred + ** on the database connection D, then sqlite3_last_insert_rowid(D) returns + ** zero. + ** + ** As well as being set automatically as rows are inserted into database + ** tables, the value returned by this function may be set explicitly by + ** [sqlite3_set_last_insert_rowid()] + ** + ** Some virtual table implementations may INSERT rows into rowid tables as + ** part of committing a transaction (e.g. to flush data accumulated in memory + ** to disk). In this case subsequent calls to this function return the rowid + ** associated with these internal INSERT operations, which leads to + ** unintuitive results. Virtual table implementations that do write to rowid + ** tables in this way can avoid this problem by restoring the original + ** rowid value using [sqlite3_set_last_insert_rowid()] before returning + ** control to the user. + ** + ** ^(If an [INSERT] occurs within a trigger then this routine will + ** return the [rowid] of the inserted row as long as the trigger is + ** running. Once the trigger program ends, the value returned + ** by this routine reverts to what it was before the trigger was fired.)^ + ** + ** ^An [INSERT] that fails due to a constraint violation is not a + ** successful [INSERT] and does not change the value returned by this + ** routine. ^Thus INSERT OR FAIL, INSERT OR IGNORE, INSERT OR ROLLBACK, + ** and INSERT OR ABORT make no changes to the return value of this + ** routine when their insertion fails. ^(When INSERT OR REPLACE + ** encounters a constraint violation, it does not fail. The + ** INSERT continues to completion after deleting rows that caused + ** the constraint problem so INSERT OR REPLACE will always change + ** the return value of this interface.)^ + ** + ** ^For the purposes of this routine, an [INSERT] is considered to + ** be successful even if it is subsequently rolled back. + ** + ** This function is accessible to SQL statements via the + ** [last_insert_rowid() SQL function]. + ** + ** If a separate thread performs a new [INSERT] on the same + ** database connection while the [sqlite3_last_insert_rowid()] + ** function is running and thus changes the last insert [rowid], + ** then the value returned by [sqlite3_last_insert_rowid()] is + ** unpredictable and might not equal either the old or the new + ** last insert [rowid]. + */ + SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*); + + /* + ** CAPI3REF: Set the Last Insert Rowid value. + ** METHOD: sqlite3 + ** + ** The sqlite3_set_last_insert_rowid(D, R) method allows the application to + ** set the value returned by calling sqlite3_last_insert_rowid(D) to R + ** without inserting a row into the database. + */ + SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3*, sqlite3_int64); + + /* + ** CAPI3REF: Count The Number Of Rows Modified + ** METHOD: sqlite3 + ** + ** ^These functions return the number of rows modified, inserted or + ** deleted by the most recently completed INSERT, UPDATE or DELETE + ** statement on the database connection specified by the only parameter. + ** The two functions are identical except for the type of the return value + ** and that if the number of rows modified by the most recent INSERT, UPDATE + ** or DELETE is greater than the maximum value supported by type "int", then + ** the return value of sqlite3_changes() is undefined. ^Executing any other + ** type of SQL statement does not modify the value returned by these functions. + ** + ** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are + ** considered - auxiliary changes caused by [CREATE TRIGGER | triggers], + ** [foreign key actions] or [REPLACE] constraint resolution are not counted. + ** + ** Changes to a view that are intercepted by + ** [INSTEAD OF trigger | INSTEAD OF triggers] are not counted. ^The value + ** returned by sqlite3_changes() immediately after an INSERT, UPDATE or + ** DELETE statement run on a view is always zero. Only changes made to real + ** tables are counted. + ** + ** Things are more complicated if the sqlite3_changes() function is + ** executed while a trigger program is running. This may happen if the + ** program uses the [changes() SQL function], or if some other callback + ** function invokes sqlite3_changes() directly. Essentially: + ** + **
    + **
  • ^(Before entering a trigger program the value returned by + ** sqlite3_changes() function is saved. After the trigger program + ** has finished, the original value is restored.)^ + ** + **
  • ^(Within a trigger program each INSERT, UPDATE and DELETE + ** statement sets the value returned by sqlite3_changes() + ** upon completion as normal. Of course, this value will not include + ** any changes performed by sub-triggers, as the sqlite3_changes() + ** value will be saved and restored after each sub-trigger has run.)^ + **
+ ** + ** ^This means that if the changes() SQL function (or similar) is used + ** by the first INSERT, UPDATE or DELETE statement within a trigger, it + ** returns the value as set when the calling statement began executing. + ** ^If it is used by the second or subsequent such statement within a trigger + ** program, the value returned reflects the number of rows modified by the + ** previous INSERT, UPDATE or DELETE statement within the same trigger. + ** + ** If a separate thread makes changes on the same database connection + ** while [sqlite3_changes()] is running then the value returned + ** is unpredictable and not meaningful. + ** + ** See also: + **
    + **
  • the [sqlite3_total_changes()] interface + **
  • the [count_changes pragma] + **
  • the [changes() SQL function] + **
  • the [data_version pragma] + **
+ */ + SQLITE_API int sqlite3_changes(sqlite3*); + SQLITE_API sqlite3_int64 sqlite3_changes64(sqlite3*); + + /* + ** CAPI3REF: Total Number Of Rows Modified + ** METHOD: sqlite3 + ** + ** ^These functions return the total number of rows inserted, modified or + ** deleted by all [INSERT], [UPDATE] or [DELETE] statements completed + ** since the database connection was opened, including those executed as + ** part of trigger programs. The two functions are identical except for the + ** type of the return value and that if the number of rows modified by the + ** connection exceeds the maximum value supported by type "int", then + ** the return value of sqlite3_total_changes() is undefined. ^Executing + ** any other type of SQL statement does not affect the value returned by + ** sqlite3_total_changes(). + ** + ** ^Changes made as part of [foreign key actions] are included in the + ** count, but those made as part of REPLACE constraint resolution are + ** not. ^Changes to a view that are intercepted by INSTEAD OF triggers + ** are not counted. + ** + ** The [sqlite3_total_changes(D)] interface only reports the number + ** of rows that changed due to SQL statement run against database + ** connection D. Any changes by other database connections are ignored. + ** To detect changes against a database file from other database + ** connections use the [PRAGMA data_version] command or the + ** [SQLITE_FCNTL_DATA_VERSION] [file control]. + ** + ** If a separate thread makes changes on the same database connection + ** while [sqlite3_total_changes()] is running then the value + ** returned is unpredictable and not meaningful. + ** + ** See also: + **
    + **
  • the [sqlite3_changes()] interface + **
  • the [count_changes pragma] + **
  • the [changes() SQL function] + **
  • the [data_version pragma] + **
  • the [SQLITE_FCNTL_DATA_VERSION] [file control] + **
+ */ + SQLITE_API int sqlite3_total_changes(sqlite3*); + SQLITE_API sqlite3_int64 sqlite3_total_changes64(sqlite3*); + + /* + ** CAPI3REF: Interrupt A Long-Running Query + ** METHOD: sqlite3 + ** + ** ^This function causes any pending database operation to abort and + ** return at its earliest opportunity. This routine is typically + ** called in response to a user action such as pressing "Cancel" + ** or Ctrl-C where the user wants a long query operation to halt + ** immediately. + ** + ** ^It is safe to call this routine from a thread different from the + ** thread that is currently running the database operation. But it + ** is not safe to call this routine with a [database connection] that + ** is closed or might close before sqlite3_interrupt() returns. + ** + ** ^If an SQL operation is very nearly finished at the time when + ** sqlite3_interrupt() is called, then it might not have an opportunity + ** to be interrupted and might continue to completion. + ** + ** ^An SQL operation that is interrupted will return [SQLITE_INTERRUPT]. + ** ^If the interrupted SQL operation is an INSERT, UPDATE, or DELETE + ** that is inside an explicit transaction, then the entire transaction + ** will be rolled back automatically. + ** + ** ^The sqlite3_interrupt(D) call is in effect until all currently running + ** SQL statements on [database connection] D complete. ^Any new SQL statements + ** that are started after the sqlite3_interrupt() call and before the + ** running statement count reaches zero are interrupted as if they had been + ** running prior to the sqlite3_interrupt() call. ^New SQL statements + ** that are started after the running statement count reaches zero are + ** not effected by the sqlite3_interrupt(). + ** ^A call to sqlite3_interrupt(D) that occurs when there are no running + ** SQL statements is a no-op and has no effect on SQL statements + ** that are started after the sqlite3_interrupt() call returns. + */ + SQLITE_API void sqlite3_interrupt(sqlite3*); + + /* + ** CAPI3REF: Determine If An SQL Statement Is Complete + ** + ** These routines are useful during command-line input to determine if the + ** currently entered text seems to form a complete SQL statement or + ** if additional input is needed before sending the text into + ** SQLite for parsing. ^These routines return 1 if the input string + ** appears to be a complete SQL statement. ^A statement is judged to be + ** complete if it ends with a semicolon token and is not a prefix of a + ** well-formed CREATE TRIGGER statement. ^Semicolons that are embedded within + ** string literals or quoted identifier names or comments are not + ** independent tokens (they are part of the token in which they are + ** embedded) and thus do not count as a statement terminator. ^Whitespace + ** and comments that follow the final semicolon are ignored. + ** + ** ^These routines return 0 if the statement is incomplete. ^If a + ** memory allocation fails, then SQLITE_NOMEM is returned. + ** + ** ^These routines do not parse the SQL statements thus + ** will not detect syntactically incorrect SQL. + ** + ** ^(If SQLite has not been initialized using [sqlite3_initialize()] prior + ** to invoking sqlite3_complete16() then sqlite3_initialize() is invoked + ** automatically by sqlite3_complete16(). If that initialization fails, + ** then the return value from sqlite3_complete16() will be non-zero + ** regardless of whether or not the input SQL is complete.)^ + ** + ** The input to [sqlite3_complete()] must be a zero-terminated + ** UTF-8 string. + ** + ** The input to [sqlite3_complete16()] must be a zero-terminated + ** UTF-16 string in native byte order. + */ + SQLITE_API int sqlite3_complete(const char* sql); + SQLITE_API int sqlite3_complete16(const void* sql); + + /* + ** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors + ** KEYWORDS: {busy-handler callback} {busy handler} + ** METHOD: sqlite3 + ** + ** ^The sqlite3_busy_handler(D,X,P) routine sets a callback function X + ** that might be invoked with argument P whenever + ** an attempt is made to access a database table associated with + ** [database connection] D when another thread + ** or process has the table locked. + ** The sqlite3_busy_handler() interface is used to implement + ** [sqlite3_busy_timeout()] and [PRAGMA busy_timeout]. + ** + ** ^If the busy callback is NULL, then [SQLITE_BUSY] + ** is returned immediately upon encountering the lock. ^If the busy callback + ** is not NULL, then the callback might be invoked with two arguments. + ** + ** ^The first argument to the busy handler is a copy of the void* pointer which + ** is the third argument to sqlite3_busy_handler(). ^The second argument to + ** the busy handler callback is the number of times that the busy handler has + ** been invoked previously for the same locking event. ^If the + ** busy callback returns 0, then no additional attempts are made to + ** access the database and [SQLITE_BUSY] is returned + ** to the application. + ** ^If the callback returns non-zero, then another attempt + ** is made to access the database and the cycle repeats. + ** + ** The presence of a busy handler does not guarantee that it will be invoked + ** when there is lock contention. ^If SQLite determines that invoking the busy + ** handler could result in a deadlock, it will go ahead and return [SQLITE_BUSY] + ** to the application instead of invoking the + ** busy handler. + ** Consider a scenario where one process is holding a read lock that + ** it is trying to promote to a reserved lock and + ** a second process is holding a reserved lock that it is trying + ** to promote to an exclusive lock. The first process cannot proceed + ** because it is blocked by the second and the second process cannot + ** proceed because it is blocked by the first. If both processes + ** invoke the busy handlers, neither will make any progress. Therefore, + ** SQLite returns [SQLITE_BUSY] for the first process, hoping that this + ** will induce the first process to release its read lock and allow + ** the second process to proceed. + ** + ** ^The default busy callback is NULL. + ** + ** ^(There can only be a single busy handler defined for each + ** [database connection]. Setting a new busy handler clears any + ** previously set handler.)^ ^Note that calling [sqlite3_busy_timeout()] + ** or evaluating [PRAGMA busy_timeout=N] will change the + ** busy handler and thus clear any previously set busy handler. + ** + ** The busy callback should not take any actions which modify the + ** database connection that invoked the busy handler. In other words, + ** the busy handler is not reentrant. Any such actions + ** result in undefined behavior. + ** + ** A busy handler must not close the database connection + ** or [prepared statement] that invoked the busy handler. + */ + SQLITE_API int sqlite3_busy_handler(sqlite3*, int (*)(void*, int), void*); + + /* + ** CAPI3REF: Set A Busy Timeout + ** METHOD: sqlite3 + ** + ** ^This routine sets a [sqlite3_busy_handler | busy handler] that sleeps + ** for a specified amount of time when a table is locked. ^The handler + ** will sleep multiple times until at least "ms" milliseconds of sleeping + ** have accumulated. ^After at least "ms" milliseconds of sleeping, + ** the handler returns 0 which causes [sqlite3_step()] to return + ** [SQLITE_BUSY]. + ** + ** ^Calling this routine with an argument less than or equal to zero + ** turns off all busy handlers. + ** + ** ^(There can only be a single busy handler for a particular + ** [database connection] at any given moment. If another busy handler + ** was defined (using [sqlite3_busy_handler()]) prior to calling + ** this routine, that other busy handler is cleared.)^ + ** + ** See also: [PRAGMA busy_timeout] + */ + SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms); + + /* + ** CAPI3REF: Convenience Routines For Running Queries + ** METHOD: sqlite3 + ** + ** This is a legacy interface that is preserved for backwards compatibility. + ** Use of this interface is not recommended. + ** + ** Definition: A result table is memory data structure created by the + ** [sqlite3_get_table()] interface. A result table records the + ** complete query results from one or more queries. + ** + ** The table conceptually has a number of rows and columns. But + ** these numbers are not part of the result table itself. These + ** numbers are obtained separately. Let N be the number of rows + ** and M be the number of columns. + ** + ** A result table is an array of pointers to zero-terminated UTF-8 strings. + ** There are (N+1)*M elements in the array. The first M pointers point + ** to zero-terminated strings that contain the names of the columns. + ** The remaining entries all point to query results. NULL values result + ** in NULL pointers. All other values are in their UTF-8 zero-terminated + ** string representation as returned by [sqlite3_column_text()]. + ** + ** A result table might consist of one or more memory allocations. + ** It is not safe to pass a result table directly to [sqlite3_free()]. + ** A result table should be deallocated using [sqlite3_free_table()]. + ** + ** ^(As an example of the result table format, suppose a query result + ** is as follows: + ** + **
+    **        Name        | Age
+    **        -----------------------
+    **        Alice       | 43
+    **        Bob         | 28
+    **        Cindy       | 21
+    ** 
+ ** + ** There are two columns (M==2) and three rows (N==3). Thus the + ** result table has 8 entries. Suppose the result table is stored + ** in an array named azResult. Then azResult holds this content: + ** + **
+    **        azResult[0] = "Name";
+    **        azResult[1] = "Age";
+    **        azResult[2] = "Alice";
+    **        azResult[3] = "43";
+    **        azResult[4] = "Bob";
+    **        azResult[5] = "28";
+    **        azResult[6] = "Cindy";
+    **        azResult[7] = "21";
+    ** 
)^ + ** + ** ^The sqlite3_get_table() function evaluates one or more + ** semicolon-separated SQL statements in the zero-terminated UTF-8 + ** string of its 2nd parameter and returns a result table to the + ** pointer given in its 3rd parameter. + ** + ** After the application has finished with the result from sqlite3_get_table(), + ** it must pass the result table pointer to sqlite3_free_table() in order to + ** release the memory that was malloced. Because of the way the + ** [sqlite3_malloc()] happens within sqlite3_get_table(), the calling + ** function must not try to call [sqlite3_free()] directly. Only + ** [sqlite3_free_table()] is able to release the memory properly and safely. + ** + ** The sqlite3_get_table() interface is implemented as a wrapper around + ** [sqlite3_exec()]. The sqlite3_get_table() routine does not have access + ** to any internal data structures of SQLite. It uses only the public + ** interface defined here. As a consequence, errors that occur in the + ** wrapper layer outside of the internal [sqlite3_exec()] call are not + ** reflected in subsequent calls to [sqlite3_errcode()] or + ** [sqlite3_errmsg()]. + */ + SQLITE_API int sqlite3_get_table(sqlite3* db, /* An open database */ + const char* zSql, /* SQL to be evaluated */ + char*** pazResult, /* Results of the query */ + int* pnRow, /* Number of result rows written here */ + int* pnColumn, /* Number of result columns written here */ + char** pzErrmsg /* Error msg written here */ + ); + SQLITE_API void sqlite3_free_table(char** result); + + /* + ** CAPI3REF: Formatted String Printing Functions + ** + ** These routines are work-alikes of the "printf()" family of functions + ** from the standard C library. + ** These routines understand most of the common formatting options from + ** the standard library printf() + ** plus some additional non-standard formats ([%q], [%Q], [%w], and [%z]). + ** See the [built-in printf()] documentation for details. + ** + ** ^The sqlite3_mprintf() and sqlite3_vmprintf() routines write their + ** results into memory obtained from [sqlite3_malloc64()]. + ** The strings returned by these two routines should be + ** released by [sqlite3_free()]. ^Both routines return a + ** NULL pointer if [sqlite3_malloc64()] is unable to allocate enough + ** memory to hold the resulting string. + ** + ** ^(The sqlite3_snprintf() routine is similar to "snprintf()" from + ** the standard C library. The result is written into the + ** buffer supplied as the second parameter whose size is given by + ** the first parameter. Note that the order of the + ** first two parameters is reversed from snprintf().)^ This is an + ** historical accident that cannot be fixed without breaking + ** backwards compatibility. ^(Note also that sqlite3_snprintf() + ** returns a pointer to its buffer instead of the number of + ** characters actually written into the buffer.)^ We admit that + ** the number of characters written would be a more useful return + ** value but we cannot change the implementation of sqlite3_snprintf() + ** now without breaking compatibility. + ** + ** ^As long as the buffer size is greater than zero, sqlite3_snprintf() + ** guarantees that the buffer is always zero-terminated. ^The first + ** parameter "n" is the total size of the buffer, including space for + ** the zero terminator. So the longest string that can be completely + ** written will be n-1 characters. + ** + ** ^The sqlite3_vsnprintf() routine is a varargs version of sqlite3_snprintf(). + ** + ** See also: [built-in printf()], [printf() SQL function] + */ + SQLITE_API char* sqlite3_mprintf(const char*, ...); + SQLITE_API char* sqlite3_vmprintf(const char*, va_list); + SQLITE_API char* sqlite3_snprintf(int, char*, const char*, ...); + SQLITE_API char* sqlite3_vsnprintf(int, char*, const char*, va_list); + + /* + ** CAPI3REF: Memory Allocation Subsystem + ** + ** The SQLite core uses these three routines for all of its own + ** internal memory allocation needs. "Core" in the previous sentence + ** does not include operating-system specific [VFS] implementation. The + ** Windows VFS uses native malloc() and free() for some operations. + ** + ** ^The sqlite3_malloc() routine returns a pointer to a block + ** of memory at least N bytes in length, where N is the parameter. + ** ^If sqlite3_malloc() is unable to obtain sufficient free + ** memory, it returns a NULL pointer. ^If the parameter N to + ** sqlite3_malloc() is zero or negative then sqlite3_malloc() returns + ** a NULL pointer. + ** + ** ^The sqlite3_malloc64(N) routine works just like + ** sqlite3_malloc(N) except that N is an unsigned 64-bit integer instead + ** of a signed 32-bit integer. + ** + ** ^Calling sqlite3_free() with a pointer previously returned + ** by sqlite3_malloc() or sqlite3_realloc() releases that memory so + ** that it might be reused. ^The sqlite3_free() routine is + ** a no-op if is called with a NULL pointer. Passing a NULL pointer + ** to sqlite3_free() is harmless. After being freed, memory + ** should neither be read nor written. Even reading previously freed + ** memory might result in a segmentation fault or other severe error. + ** Memory corruption, a segmentation fault, or other severe error + ** might result if sqlite3_free() is called with a non-NULL pointer that + ** was not obtained from sqlite3_malloc() or sqlite3_realloc(). + ** + ** ^The sqlite3_realloc(X,N) interface attempts to resize a + ** prior memory allocation X to be at least N bytes. + ** ^If the X parameter to sqlite3_realloc(X,N) + ** is a NULL pointer then its behavior is identical to calling + ** sqlite3_malloc(N). + ** ^If the N parameter to sqlite3_realloc(X,N) is zero or + ** negative then the behavior is exactly the same as calling + ** sqlite3_free(X). + ** ^sqlite3_realloc(X,N) returns a pointer to a memory allocation + ** of at least N bytes in size or NULL if insufficient memory is available. + ** ^If M is the size of the prior allocation, then min(N,M) bytes + ** of the prior allocation are copied into the beginning of buffer returned + ** by sqlite3_realloc(X,N) and the prior allocation is freed. + ** ^If sqlite3_realloc(X,N) returns NULL and N is positive, then the + ** prior allocation is not freed. + ** + ** ^The sqlite3_realloc64(X,N) interfaces works the same as + ** sqlite3_realloc(X,N) except that N is a 64-bit unsigned integer instead + ** of a 32-bit signed integer. + ** + ** ^If X is a memory allocation previously obtained from sqlite3_malloc(), + ** sqlite3_malloc64(), sqlite3_realloc(), or sqlite3_realloc64(), then + ** sqlite3_msize(X) returns the size of that memory allocation in bytes. + ** ^The value returned by sqlite3_msize(X) might be larger than the number + ** of bytes requested when X was allocated. ^If X is a NULL pointer then + ** sqlite3_msize(X) returns zero. If X points to something that is not + ** the beginning of memory allocation, or if it points to a formerly + ** valid memory allocation that has now been freed, then the behavior + ** of sqlite3_msize(X) is undefined and possibly harmful. + ** + ** ^The memory returned by sqlite3_malloc(), sqlite3_realloc(), + ** sqlite3_malloc64(), and sqlite3_realloc64() + ** is always aligned to at least an 8 byte boundary, or to a + ** 4 byte boundary if the [SQLITE_4_BYTE_ALIGNED_MALLOC] compile-time + ** option is used. + ** + ** The pointer arguments to [sqlite3_free()] and [sqlite3_realloc()] + ** must be either NULL or else pointers obtained from a prior + ** invocation of [sqlite3_malloc()] or [sqlite3_realloc()] that have + ** not yet been released. + ** + ** The application must not read or write any part of + ** a block of memory after it has been released using + ** [sqlite3_free()] or [sqlite3_realloc()]. + */ + SQLITE_API void* sqlite3_malloc(int); + SQLITE_API void* sqlite3_malloc64(sqlite3_uint64); + SQLITE_API void* sqlite3_realloc(void*, int); + SQLITE_API void* sqlite3_realloc64(void*, sqlite3_uint64); + SQLITE_API void sqlite3_free(void*); + SQLITE_API sqlite3_uint64 sqlite3_msize(void*); + + /* + ** CAPI3REF: Memory Allocator Statistics + ** + ** SQLite provides these two interfaces for reporting on the status + ** of the [sqlite3_malloc()], [sqlite3_free()], and [sqlite3_realloc()] + ** routines, which form the built-in memory allocation subsystem. + ** + ** ^The [sqlite3_memory_used()] routine returns the number of bytes + ** of memory currently outstanding (malloced but not freed). + ** ^The [sqlite3_memory_highwater()] routine returns the maximum + ** value of [sqlite3_memory_used()] since the high-water mark + ** was last reset. ^The values returned by [sqlite3_memory_used()] and + ** [sqlite3_memory_highwater()] include any overhead + ** added by SQLite in its implementation of [sqlite3_malloc()], + ** but not overhead added by the any underlying system library + ** routines that [sqlite3_malloc()] may call. + ** + ** ^The memory high-water mark is reset to the current value of + ** [sqlite3_memory_used()] if and only if the parameter to + ** [sqlite3_memory_highwater()] is true. ^The value returned + ** by [sqlite3_memory_highwater(1)] is the high-water mark + ** prior to the reset. + */ + SQLITE_API sqlite3_int64 sqlite3_memory_used(void); + SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag); + + /* + ** CAPI3REF: Pseudo-Random Number Generator + ** + ** SQLite contains a high-quality pseudo-random number generator (PRNG) used to + ** select random [ROWID | ROWIDs] when inserting new records into a table that + ** already uses the largest possible [ROWID]. The PRNG is also used for + ** the built-in random() and randomblob() SQL functions. This interface allows + ** applications to access the same PRNG for other purposes. + ** + ** ^A call to this routine stores N bytes of randomness into buffer P. + ** ^The P parameter can be a NULL pointer. + ** + ** ^If this routine has not been previously called or if the previous + ** call had N less than one or a NULL pointer for P, then the PRNG is + ** seeded using randomness obtained from the xRandomness method of + ** the default [sqlite3_vfs] object. + ** ^If the previous call to this routine had an N of 1 or more and a + ** non-NULL P then the pseudo-randomness is generated + ** internally and without recourse to the [sqlite3_vfs] xRandomness + ** method. + */ + SQLITE_API void sqlite3_randomness(int N, void* P); + + /* + ** CAPI3REF: Compile-Time Authorization Callbacks + ** METHOD: sqlite3 + ** KEYWORDS: {authorizer callback} + ** + ** ^This routine registers an authorizer callback with a particular + ** [database connection], supplied in the first argument. + ** ^The authorizer callback is invoked as SQL statements are being compiled + ** by [sqlite3_prepare()] or its variants [sqlite3_prepare_v2()], + ** [sqlite3_prepare_v3()], [sqlite3_prepare16()], [sqlite3_prepare16_v2()], + ** and [sqlite3_prepare16_v3()]. ^At various + ** points during the compilation process, as logic is being created + ** to perform various actions, the authorizer callback is invoked to + ** see if those actions are allowed. ^The authorizer callback should + ** return [SQLITE_OK] to allow the action, [SQLITE_IGNORE] to disallow the + ** specific action but allow the SQL statement to continue to be + ** compiled, or [SQLITE_DENY] to cause the entire SQL statement to be + ** rejected with an error. ^If the authorizer callback returns + ** any value other than [SQLITE_IGNORE], [SQLITE_OK], or [SQLITE_DENY] + ** then the [sqlite3_prepare_v2()] or equivalent call that triggered + ** the authorizer will fail with an error message. + ** + ** When the callback returns [SQLITE_OK], that means the operation + ** requested is ok. ^When the callback returns [SQLITE_DENY], the + ** [sqlite3_prepare_v2()] or equivalent call that triggered the + ** authorizer will fail with an error message explaining that + ** access is denied. + ** + ** ^The first parameter to the authorizer callback is a copy of the third + ** parameter to the sqlite3_set_authorizer() interface. ^The second parameter + ** to the callback is an integer [SQLITE_COPY | action code] that specifies + ** the particular action to be authorized. ^The third through sixth parameters + ** to the callback are either NULL pointers or zero-terminated strings + ** that contain additional details about the action to be authorized. + ** Applications must always be prepared to encounter a NULL pointer in any + ** of the third through the sixth parameters of the authorization callback. + ** + ** ^If the action code is [SQLITE_READ] + ** and the callback returns [SQLITE_IGNORE] then the + ** [prepared statement] statement is constructed to substitute + ** a NULL value in place of the table column that would have + ** been read if [SQLITE_OK] had been returned. The [SQLITE_IGNORE] + ** return can be used to deny an untrusted user access to individual + ** columns of a table. + ** ^When a table is referenced by a [SELECT] but no column values are + ** extracted from that table (for example in a query like + ** "SELECT count(*) FROM tab") then the [SQLITE_READ] authorizer callback + ** is invoked once for that table with a column name that is an empty string. + ** ^If the action code is [SQLITE_DELETE] and the callback returns + ** [SQLITE_IGNORE] then the [DELETE] operation proceeds but the + ** [truncate optimization] is disabled and all rows are deleted individually. + ** + ** An authorizer is used when [sqlite3_prepare | preparing] + ** SQL statements from an untrusted source, to ensure that the SQL statements + ** do not try to access data they are not allowed to see, or that they do not + ** try to execute malicious statements that damage the database. For + ** example, an application may allow a user to enter arbitrary + ** SQL queries for evaluation by a database. But the application does + ** not want the user to be able to make arbitrary changes to the + ** database. An authorizer could then be put in place while the + ** user-entered SQL is being [sqlite3_prepare | prepared] that + ** disallows everything except [SELECT] statements. + ** + ** Applications that need to process SQL from untrusted sources + ** might also consider lowering resource limits using [sqlite3_limit()] + ** and limiting database size using the [max_page_count] [PRAGMA] + ** in addition to using an authorizer. + ** + ** ^(Only a single authorizer can be in place on a database connection + ** at a time. Each call to sqlite3_set_authorizer overrides the + ** previous call.)^ ^Disable the authorizer by installing a NULL callback. + ** The authorizer is disabled by default. + ** + ** The authorizer callback must not do anything that will modify + ** the database connection that invoked the authorizer callback. + ** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their + ** database connections for the meaning of "modify" in this paragraph. + ** + ** ^When [sqlite3_prepare_v2()] is used to prepare a statement, the + ** statement might be re-prepared during [sqlite3_step()] due to a + ** schema change. Hence, the application should ensure that the + ** correct authorizer callback remains in place during the [sqlite3_step()]. + ** + ** ^Note that the authorizer callback is invoked only during + ** [sqlite3_prepare()] or its variants. Authorization is not + ** performed during statement evaluation in [sqlite3_step()], unless + ** as stated in the previous paragraph, sqlite3_step() invokes + ** sqlite3_prepare_v2() to reprepare a statement after a schema change. + */ + SQLITE_API int sqlite3_set_authorizer(sqlite3*, + int (*xAuth)(void*, int, const char*, const char*, const char*, const char*), + void* pUserData); /* ** CAPI3REF: Authorizer Return Codes @@ -3125,8 +3121,8 @@ SQLITE_API int sqlite3_set_authorizer( ** Note that SQLITE_IGNORE is also used as a [conflict resolution mode] ** returned from the [sqlite3_vtab_on_conflict()] interface. */ -#define SQLITE_DENY 1 /* Abort the SQL statement with an error */ -#define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */ +#define SQLITE_DENY 1 /* Abort the SQL statement with an error */ +#define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */ /* ** CAPI3REF: Authorizer Action Codes @@ -3148,77 +3144,76 @@ SQLITE_API int sqlite3_set_authorizer( ** top-level SQL code. */ /******************************************* 3rd ************ 4th ***********/ -#define SQLITE_CREATE_INDEX 1 /* Index Name Table Name */ -#define SQLITE_CREATE_TABLE 2 /* Table Name NULL */ -#define SQLITE_CREATE_TEMP_INDEX 3 /* Index Name Table Name */ -#define SQLITE_CREATE_TEMP_TABLE 4 /* Table Name NULL */ -#define SQLITE_CREATE_TEMP_TRIGGER 5 /* Trigger Name Table Name */ -#define SQLITE_CREATE_TEMP_VIEW 6 /* View Name NULL */ -#define SQLITE_CREATE_TRIGGER 7 /* Trigger Name Table Name */ -#define SQLITE_CREATE_VIEW 8 /* View Name NULL */ -#define SQLITE_DELETE 9 /* Table Name NULL */ -#define SQLITE_DROP_INDEX 10 /* Index Name Table Name */ -#define SQLITE_DROP_TABLE 11 /* Table Name NULL */ -#define SQLITE_DROP_TEMP_INDEX 12 /* Index Name Table Name */ -#define SQLITE_DROP_TEMP_TABLE 13 /* Table Name NULL */ -#define SQLITE_DROP_TEMP_TRIGGER 14 /* Trigger Name Table Name */ -#define SQLITE_DROP_TEMP_VIEW 15 /* View Name NULL */ -#define SQLITE_DROP_TRIGGER 16 /* Trigger Name Table Name */ -#define SQLITE_DROP_VIEW 17 /* View Name NULL */ -#define SQLITE_INSERT 18 /* Table Name NULL */ -#define SQLITE_PRAGMA 19 /* Pragma Name 1st arg or NULL */ -#define SQLITE_READ 20 /* Table Name Column Name */ -#define SQLITE_SELECT 21 /* NULL NULL */ -#define SQLITE_TRANSACTION 22 /* Operation NULL */ -#define SQLITE_UPDATE 23 /* Table Name Column Name */ -#define SQLITE_ATTACH 24 /* Filename NULL */ -#define SQLITE_DETACH 25 /* Database Name NULL */ -#define SQLITE_ALTER_TABLE 26 /* Database Name Table Name */ -#define SQLITE_REINDEX 27 /* Index Name NULL */ -#define SQLITE_ANALYZE 28 /* Table Name NULL */ -#define SQLITE_CREATE_VTABLE 29 /* Table Name Module Name */ -#define SQLITE_DROP_VTABLE 30 /* Table Name Module Name */ -#define SQLITE_FUNCTION 31 /* NULL Function Name */ -#define SQLITE_SAVEPOINT 32 /* Operation Savepoint Name */ -#define SQLITE_COPY 0 /* No longer used */ -#define SQLITE_RECURSIVE 33 /* NULL NULL */ - -/* -** CAPI3REF: Tracing And Profiling Functions -** METHOD: sqlite3 -** -** These routines are deprecated. Use the [sqlite3_trace_v2()] interface -** instead of the routines described here. -** -** These routines register callback functions that can be used for -** tracing and profiling the execution of SQL statements. -** -** ^The callback function registered by sqlite3_trace() is invoked at -** various times when an SQL statement is being run by [sqlite3_step()]. -** ^The sqlite3_trace() callback is invoked with a UTF-8 rendering of the -** SQL statement text as the statement first begins executing. -** ^(Additional sqlite3_trace() callbacks might occur -** as each triggered subprogram is entered. The callbacks for triggers -** contain a UTF-8 SQL comment that identifies the trigger.)^ -** -** The [SQLITE_TRACE_SIZE_LIMIT] compile-time option can be used to limit -** the length of [bound parameter] expansion in the output of sqlite3_trace(). -** -** ^The callback function registered by sqlite3_profile() is invoked -** as each SQL statement finishes. ^The profile callback contains -** the original statement text and an estimate of wall-clock time -** of how long that statement took to run. ^The profile callback -** time is in units of nanoseconds, however the current implementation -** is only capable of millisecond resolution so the six least significant -** digits in the time are meaningless. Future versions of SQLite -** might provide greater resolution on the profiler callback. Invoking -** either [sqlite3_trace()] or [sqlite3_trace_v2()] will cancel the -** profile callback. -*/ -SQLITE_API SQLITE_DEPRECATED void *sqlite3_trace(sqlite3*, - void(*xTrace)(void*,const char*), void*); -SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*, - void(*xProfile)(void*,const char*,sqlite3_uint64), void*); +#define SQLITE_CREATE_INDEX 1 /* Index Name Table Name */ +#define SQLITE_CREATE_TABLE 2 /* Table Name NULL */ +#define SQLITE_CREATE_TEMP_INDEX 3 /* Index Name Table Name */ +#define SQLITE_CREATE_TEMP_TABLE 4 /* Table Name NULL */ +#define SQLITE_CREATE_TEMP_TRIGGER 5 /* Trigger Name Table Name */ +#define SQLITE_CREATE_TEMP_VIEW 6 /* View Name NULL */ +#define SQLITE_CREATE_TRIGGER 7 /* Trigger Name Table Name */ +#define SQLITE_CREATE_VIEW 8 /* View Name NULL */ +#define SQLITE_DELETE 9 /* Table Name NULL */ +#define SQLITE_DROP_INDEX 10 /* Index Name Table Name */ +#define SQLITE_DROP_TABLE 11 /* Table Name NULL */ +#define SQLITE_DROP_TEMP_INDEX 12 /* Index Name Table Name */ +#define SQLITE_DROP_TEMP_TABLE 13 /* Table Name NULL */ +#define SQLITE_DROP_TEMP_TRIGGER 14 /* Trigger Name Table Name */ +#define SQLITE_DROP_TEMP_VIEW 15 /* View Name NULL */ +#define SQLITE_DROP_TRIGGER 16 /* Trigger Name Table Name */ +#define SQLITE_DROP_VIEW 17 /* View Name NULL */ +#define SQLITE_INSERT 18 /* Table Name NULL */ +#define SQLITE_PRAGMA 19 /* Pragma Name 1st arg or NULL */ +#define SQLITE_READ 20 /* Table Name Column Name */ +#define SQLITE_SELECT 21 /* NULL NULL */ +#define SQLITE_TRANSACTION 22 /* Operation NULL */ +#define SQLITE_UPDATE 23 /* Table Name Column Name */ +#define SQLITE_ATTACH 24 /* Filename NULL */ +#define SQLITE_DETACH 25 /* Database Name NULL */ +#define SQLITE_ALTER_TABLE 26 /* Database Name Table Name */ +#define SQLITE_REINDEX 27 /* Index Name NULL */ +#define SQLITE_ANALYZE 28 /* Table Name NULL */ +#define SQLITE_CREATE_VTABLE 29 /* Table Name Module Name */ +#define SQLITE_DROP_VTABLE 30 /* Table Name Module Name */ +#define SQLITE_FUNCTION 31 /* NULL Function Name */ +#define SQLITE_SAVEPOINT 32 /* Operation Savepoint Name */ +#define SQLITE_COPY 0 /* No longer used */ +#define SQLITE_RECURSIVE 33 /* NULL NULL */ + + /* + ** CAPI3REF: Tracing And Profiling Functions + ** METHOD: sqlite3 + ** + ** These routines are deprecated. Use the [sqlite3_trace_v2()] interface + ** instead of the routines described here. + ** + ** These routines register callback functions that can be used for + ** tracing and profiling the execution of SQL statements. + ** + ** ^The callback function registered by sqlite3_trace() is invoked at + ** various times when an SQL statement is being run by [sqlite3_step()]. + ** ^The sqlite3_trace() callback is invoked with a UTF-8 rendering of the + ** SQL statement text as the statement first begins executing. + ** ^(Additional sqlite3_trace() callbacks might occur + ** as each triggered subprogram is entered. The callbacks for triggers + ** contain a UTF-8 SQL comment that identifies the trigger.)^ + ** + ** The [SQLITE_TRACE_SIZE_LIMIT] compile-time option can be used to limit + ** the length of [bound parameter] expansion in the output of sqlite3_trace(). + ** + ** ^The callback function registered by sqlite3_profile() is invoked + ** as each SQL statement finishes. ^The profile callback contains + ** the original statement text and an estimate of wall-clock time + ** of how long that statement took to run. ^The profile callback + ** time is in units of nanoseconds, however the current implementation + ** is only capable of millisecond resolution so the six least significant + ** digits in the time are meaningless. Future versions of SQLite + ** might provide greater resolution on the profiler callback. Invoking + ** either [sqlite3_trace()] or [sqlite3_trace_v2()] will cancel the + ** profile callback. + */ + SQLITE_API SQLITE_DEPRECATED void* sqlite3_trace(sqlite3*, void (*xTrace)(void*, const char*), void*); + SQLITE_API SQLITE_DEPRECATED void* + sqlite3_profile(sqlite3*, void (*xProfile)(void*, const char*, sqlite3_uint64), void*); /* ** CAPI3REF: SQL Trace Event Codes @@ -3272,675 +3267,666 @@ SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*, ** and the X argument is unused. ** */ -#define SQLITE_TRACE_STMT 0x01 -#define SQLITE_TRACE_PROFILE 0x02 -#define SQLITE_TRACE_ROW 0x04 -#define SQLITE_TRACE_CLOSE 0x08 - -/* -** CAPI3REF: SQL Trace Hook -** METHOD: sqlite3 -** -** ^The sqlite3_trace_v2(D,M,X,P) interface registers a trace callback -** function X against [database connection] D, using property mask M -** and context pointer P. ^If the X callback is -** NULL or if the M mask is zero, then tracing is disabled. The -** M argument should be the bitwise OR-ed combination of -** zero or more [SQLITE_TRACE] constants. -** -** ^Each call to either sqlite3_trace() or sqlite3_trace_v2() overrides -** (cancels) any prior calls to sqlite3_trace() or sqlite3_trace_v2(). -** -** ^The X callback is invoked whenever any of the events identified by -** mask M occur. ^The integer return value from the callback is currently -** ignored, though this may change in future releases. Callback -** implementations should return zero to ensure future compatibility. -** -** ^A trace callback is invoked with four arguments: callback(T,C,P,X). -** ^The T argument is one of the [SQLITE_TRACE] -** constants to indicate why the callback was invoked. -** ^The C argument is a copy of the context pointer. -** The P and X arguments are pointers whose meanings depend on T. -** -** The sqlite3_trace_v2() interface is intended to replace the legacy -** interfaces [sqlite3_trace()] and [sqlite3_profile()], both of which -** are deprecated. -*/ -SQLITE_API int sqlite3_trace_v2( - sqlite3*, - unsigned uMask, - int(*xCallback)(unsigned,void*,void*,void*), - void *pCtx -); - -/* -** CAPI3REF: Query Progress Callbacks -** METHOD: sqlite3 -** -** ^The sqlite3_progress_handler(D,N,X,P) interface causes the callback -** function X to be invoked periodically during long running calls to -** [sqlite3_exec()], [sqlite3_step()] and [sqlite3_get_table()] for -** database connection D. An example use for this -** interface is to keep a GUI updated during a large query. -** -** ^The parameter P is passed through as the only parameter to the -** callback function X. ^The parameter N is the approximate number of -** [virtual machine instructions] that are evaluated between successive -** invocations of the callback X. ^If N is less than one then the progress -** handler is disabled. -** -** ^Only a single progress handler may be defined at one time per -** [database connection]; setting a new progress handler cancels the -** old one. ^Setting parameter X to NULL disables the progress handler. -** ^The progress handler is also disabled by setting N to a value less -** than 1. -** -** ^If the progress callback returns non-zero, the operation is -** interrupted. This feature can be used to implement a -** "Cancel" button on a GUI progress dialog box. -** -** The progress handler callback must not do anything that will modify -** the database connection that invoked the progress handler. -** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their -** database connections for the meaning of "modify" in this paragraph. -** -*/ -SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); - -/* -** CAPI3REF: Opening A New Database Connection -** CONSTRUCTOR: sqlite3 -** -** ^These routines open an SQLite database file as specified by the -** filename argument. ^The filename argument is interpreted as UTF-8 for -** sqlite3_open() and sqlite3_open_v2() and as UTF-16 in the native byte -** order for sqlite3_open16(). ^(A [database connection] handle is usually -** returned in *ppDb, even if an error occurs. The only exception is that -** if SQLite is unable to allocate memory to hold the [sqlite3] object, -** a NULL will be written into *ppDb instead of a pointer to the [sqlite3] -** object.)^ ^(If the database is opened (and/or created) successfully, then -** [SQLITE_OK] is returned. Otherwise an [error code] is returned.)^ ^The -** [sqlite3_errmsg()] or [sqlite3_errmsg16()] routines can be used to obtain -** an English language description of the error following a failure of any -** of the sqlite3_open() routines. -** -** ^The default encoding will be UTF-8 for databases created using -** sqlite3_open() or sqlite3_open_v2(). ^The default encoding for databases -** created using sqlite3_open16() will be UTF-16 in the native byte order. -** -** Whether or not an error occurs when it is opened, resources -** associated with the [database connection] handle should be released by -** passing it to [sqlite3_close()] when it is no longer required. -** -** The sqlite3_open_v2() interface works like sqlite3_open() -** except that it accepts two additional parameters for additional control -** over the new database connection. ^(The flags parameter to -** sqlite3_open_v2() must include, at a minimum, one of the following -** three flag combinations:)^ -** -**
-** ^(
[SQLITE_OPEN_READONLY]
-**
The database is opened in read-only mode. If the database does not -** already exist, an error is returned.
)^ -** -** ^(
[SQLITE_OPEN_READWRITE]
-**
The database is opened for reading and writing if possible, or reading -** only if the file is write protected by the operating system. In either -** case the database must already exist, otherwise an error is returned.
)^ -** -** ^(
[SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]
-**
The database is opened for reading and writing, and is created if -** it does not already exist. This is the behavior that is always used for -** sqlite3_open() and sqlite3_open16().
)^ -**
-** -** In addition to the required flags, the following optional flags are -** also supported: -** -**
-** ^(
[SQLITE_OPEN_URI]
-**
The filename can be interpreted as a URI if this flag is set.
)^ -** -** ^(
[SQLITE_OPEN_MEMORY]
-**
The database will be opened as an in-memory database. The database -** is named by the "filename" argument for the purposes of cache-sharing, -** if shared cache mode is enabled, but the "filename" is otherwise ignored. -**
)^ -** -** ^(
[SQLITE_OPEN_NOMUTEX]
-**
The new database connection will use the "multi-thread" -** [threading mode].)^ This means that separate threads are allowed -** to use SQLite at the same time, as long as each thread is using -** a different [database connection]. -** -** ^(
[SQLITE_OPEN_FULLMUTEX]
-**
The new database connection will use the "serialized" -** [threading mode].)^ This means the multiple threads can safely -** attempt to use the same database connection at the same time. -** (Mutexes will block any actual concurrency, but in this mode -** there is no harm in trying.) -** -** ^(
[SQLITE_OPEN_SHAREDCACHE]
-**
The database is opened [shared cache] enabled, overriding -** the default shared cache setting provided by -** [sqlite3_enable_shared_cache()].)^ -** -** ^(
[SQLITE_OPEN_PRIVATECACHE]
-**
The database is opened [shared cache] disabled, overriding -** the default shared cache setting provided by -** [sqlite3_enable_shared_cache()].)^ -** -** [[OPEN_EXRESCODE]] ^(
[SQLITE_OPEN_EXRESCODE]
-**
The database connection comes up in "extended result code mode". -** In other words, the database behaves has if -** [sqlite3_extended_result_codes(db,1)] where called on the database -** connection as soon as the connection is created. In addition to setting -** the extended result code mode, this flag also causes [sqlite3_open_v2()] -** to return an extended result code.
-** -** [[OPEN_NOFOLLOW]] ^(
[SQLITE_OPEN_NOFOLLOW]
-**
The database filename is not allowed to be a symbolic link
-**
)^ -** -** If the 3rd parameter to sqlite3_open_v2() is not one of the -** required combinations shown above optionally combined with other -** [SQLITE_OPEN_READONLY | SQLITE_OPEN_* bits] -** then the behavior is undefined. Historic versions of SQLite -** have silently ignored surplus bits in the flags parameter to -** sqlite3_open_v2(), however that behavior might not be carried through -** into future versions of SQLite and so applications should not rely -** upon it. Note in particular that the SQLITE_OPEN_EXCLUSIVE flag is a no-op -** for sqlite3_open_v2(). The SQLITE_OPEN_EXCLUSIVE does *not* cause -** the open to fail if the database already exists. The SQLITE_OPEN_EXCLUSIVE -** flag is intended for use by the [sqlite3_vfs|VFS interface] only, and not -** by sqlite3_open_v2(). -** -** ^The fourth parameter to sqlite3_open_v2() is the name of the -** [sqlite3_vfs] object that defines the operating system interface that -** the new database connection should use. ^If the fourth parameter is -** a NULL pointer then the default [sqlite3_vfs] object is used. -** -** ^If the filename is ":memory:", then a private, temporary in-memory database -** is created for the connection. ^This in-memory database will vanish when -** the database connection is closed. Future versions of SQLite might -** make use of additional special filenames that begin with the ":" character. -** It is recommended that when a database filename actually does begin with -** a ":" character you should prefix the filename with a pathname such as -** "./" to avoid ambiguity. -** -** ^If the filename is an empty string, then a private, temporary -** on-disk database will be created. ^This private database will be -** automatically deleted as soon as the database connection is closed. -** -** [[URI filenames in sqlite3_open()]]

URI Filenames

-** -** ^If [URI filename] interpretation is enabled, and the filename argument -** begins with "file:", then the filename is interpreted as a URI. ^URI -** filename interpretation is enabled if the [SQLITE_OPEN_URI] flag is -** set in the third argument to sqlite3_open_v2(), or if it has -** been enabled globally using the [SQLITE_CONFIG_URI] option with the -** [sqlite3_config()] method or by the [SQLITE_USE_URI] compile-time option. -** URI filename interpretation is turned off -** by default, but future releases of SQLite might enable URI filename -** interpretation by default. See "[URI filenames]" for additional -** information. -** -** URI filenames are parsed according to RFC 3986. ^If the URI contains an -** authority, then it must be either an empty string or the string -** "localhost". ^If the authority is not an empty string or "localhost", an -** error is returned to the caller. ^The fragment component of a URI, if -** present, is ignored. -** -** ^SQLite uses the path component of the URI as the name of the disk file -** which contains the database. ^If the path begins with a '/' character, -** then it is interpreted as an absolute path. ^If the path does not begin -** with a '/' (meaning that the authority section is omitted from the URI) -** then the path is interpreted as a relative path. -** ^(On windows, the first component of an absolute path -** is a drive specification (e.g. "C:").)^ -** -** [[core URI query parameters]] -** The query component of a URI may contain parameters that are interpreted -** either by SQLite itself, or by a [VFS | custom VFS implementation]. -** SQLite and its built-in [VFSes] interpret the -** following query parameters: -** -**
    -**
  • vfs: ^The "vfs" parameter may be used to specify the name of -** a VFS object that provides the operating system interface that should -** be used to access the database file on disk. ^If this option is set to -** an empty string the default VFS object is used. ^Specifying an unknown -** VFS is an error. ^If sqlite3_open_v2() is used and the vfs option is -** present, then the VFS specified by the option takes precedence over -** the value passed as the fourth parameter to sqlite3_open_v2(). -** -**
  • mode: ^(The mode parameter may be set to either "ro", "rw", -** "rwc", or "memory". Attempting to set it to any other value is -** an error)^. -** ^If "ro" is specified, then the database is opened for read-only -** access, just as if the [SQLITE_OPEN_READONLY] flag had been set in the -** third argument to sqlite3_open_v2(). ^If the mode option is set to -** "rw", then the database is opened for read-write (but not create) -** access, as if SQLITE_OPEN_READWRITE (but not SQLITE_OPEN_CREATE) had -** been set. ^Value "rwc" is equivalent to setting both -** SQLITE_OPEN_READWRITE and SQLITE_OPEN_CREATE. ^If the mode option is -** set to "memory" then a pure [in-memory database] that never reads -** or writes from disk is used. ^It is an error to specify a value for -** the mode parameter that is less restrictive than that specified by -** the flags passed in the third parameter to sqlite3_open_v2(). -** -**
  • cache: ^The cache parameter may be set to either "shared" or -** "private". ^Setting it to "shared" is equivalent to setting the -** SQLITE_OPEN_SHAREDCACHE bit in the flags argument passed to -** sqlite3_open_v2(). ^Setting the cache parameter to "private" is -** equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit. -** ^If sqlite3_open_v2() is used and the "cache" parameter is present in -** a URI filename, its value overrides any behavior requested by setting -** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag. -** -**
  • psow: ^The psow parameter indicates whether or not the -** [powersafe overwrite] property does or does not apply to the -** storage media on which the database file resides. -** -**
  • nolock: ^The nolock parameter is a boolean query parameter -** which if set disables file locking in rollback journal modes. This -** is useful for accessing a database on a filesystem that does not -** support locking. Caution: Database corruption might result if two -** or more processes write to the same database and any one of those -** processes uses nolock=1. -** -**
  • immutable: ^The immutable parameter is a boolean query -** parameter that indicates that the database file is stored on -** read-only media. ^When immutable is set, SQLite assumes that the -** database file cannot be changed, even by a process with higher -** privilege, and so the database is opened read-only and all locking -** and change detection is disabled. Caution: Setting the immutable -** property on a database file that does in fact change can result -** in incorrect query results and/or [SQLITE_CORRUPT] errors. -** See also: [SQLITE_IOCAP_IMMUTABLE]. -** -**
-** -** ^Specifying an unknown parameter in the query component of a URI is not an -** error. Future versions of SQLite might understand additional query -** parameters. See "[query parameters with special meaning to SQLite]" for -** additional information. -** -** [[URI filename examples]]

URI filename examples

-** -** -**
URI filenames Results -**
file:data.db -** Open the file "data.db" in the current directory. -**
file:/home/fred/data.db
-** file:///home/fred/data.db
-** file://localhost/home/fred/data.db
-** Open the database file "/home/fred/data.db". -**
file://darkstar/home/fred/data.db -** An error. "darkstar" is not a recognized authority. -**
-** file:///C:/Documents%20and%20Settings/fred/Desktop/data.db -** Windows only: Open the file "data.db" on fred's desktop on drive -** C:. Note that the %20 escaping in this example is not strictly -** necessary - space characters can be used literally -** in URI filenames. -**
file:data.db?mode=ro&cache=private -** Open file "data.db" in the current directory for read-only access. -** Regardless of whether or not shared-cache mode is enabled by -** default, use a private cache. -**
file:/home/fred/data.db?vfs=unix-dotfile -** Open file "/home/fred/data.db". Use the special VFS "unix-dotfile" -** that uses dot-files in place of posix advisory locking. -**
file:data.db?mode=readonly -** An error. "readonly" is not a valid option for the "mode" parameter. -** Use "ro" instead: "file:data.db?mode=ro". -**
-** -** ^URI hexadecimal escape sequences (%HH) are supported within the path and -** query components of a URI. A hexadecimal escape sequence consists of a -** percent sign - "%" - followed by exactly two hexadecimal digits -** specifying an octet value. ^Before the path or query components of a -** URI filename are interpreted, they are encoded using UTF-8 and all -** hexadecimal escape sequences replaced by a single byte containing the -** corresponding octet. If this process generates an invalid UTF-8 encoding, -** the results are undefined. -** -** Note to Windows users: The encoding used for the filename argument -** of sqlite3_open() and sqlite3_open_v2() must be UTF-8, not whatever -** codepage is currently defined. Filenames containing international -** characters must be converted to UTF-8 prior to passing them into -** sqlite3_open() or sqlite3_open_v2(). -** -** Note to Windows Runtime users: The temporary directory must be set -** prior to calling sqlite3_open() or sqlite3_open_v2(). Otherwise, various -** features that require the use of temporary files may fail. -** -** See also: [sqlite3_temp_directory] -*/ -SQLITE_API int sqlite3_open( - const char *filename, /* Database filename (UTF-8) */ - sqlite3 **ppDb /* OUT: SQLite db handle */ -); -SQLITE_API int sqlite3_open16( - const void *filename, /* Database filename (UTF-16) */ - sqlite3 **ppDb /* OUT: SQLite db handle */ -); -SQLITE_API int sqlite3_open_v2( - const char *filename, /* Database filename (UTF-8) */ - sqlite3 **ppDb, /* OUT: SQLite db handle */ - int flags, /* Flags */ - const char *zVfs /* Name of VFS module to use */ -); - -/* -** CAPI3REF: Obtain Values For URI Parameters -** -** These are utility routines, useful to [VFS|custom VFS implementations], -** that check if a database file was a URI that contained a specific query -** parameter, and if so obtains the value of that query parameter. -** -** The first parameter to these interfaces (hereafter referred to -** as F) must be one of: -**
    -**
  • A database filename pointer created by the SQLite core and -** passed into the xOpen() method of a VFS implemention, or -**
  • A filename obtained from [sqlite3_db_filename()], or -**
  • A new filename constructed using [sqlite3_create_filename()]. -**
-** If the F parameter is not one of the above, then the behavior is -** undefined and probably undesirable. Older versions of SQLite were -** more tolerant of invalid F parameters than newer versions. -** -** If F is a suitable filename (as described in the previous paragraph) -** and if P is the name of the query parameter, then -** sqlite3_uri_parameter(F,P) returns the value of the P -** parameter if it exists or a NULL pointer if P does not appear as a -** query parameter on F. If P is a query parameter of F and it -** has no explicit value, then sqlite3_uri_parameter(F,P) returns -** a pointer to an empty string. -** -** The sqlite3_uri_boolean(F,P,B) routine assumes that P is a boolean -** parameter and returns true (1) or false (0) according to the value -** of P. The sqlite3_uri_boolean(F,P,B) routine returns true (1) if the -** value of query parameter P is one of "yes", "true", or "on" in any -** case or if the value begins with a non-zero number. The -** sqlite3_uri_boolean(F,P,B) routines returns false (0) if the value of -** query parameter P is one of "no", "false", or "off" in any case or -** if the value begins with a numeric zero. If P is not a query -** parameter on F or if the value of P does not match any of the -** above, then sqlite3_uri_boolean(F,P,B) returns (B!=0). -** -** The sqlite3_uri_int64(F,P,D) routine converts the value of P into a -** 64-bit signed integer and returns that integer, or D if P does not -** exist. If the value of P is something other than an integer, then -** zero is returned. -** -** The sqlite3_uri_key(F,N) returns a pointer to the name (not -** the value) of the N-th query parameter for filename F, or a NULL -** pointer if N is less than zero or greater than the number of query -** parameters minus 1. The N value is zero-based so N should be 0 to obtain -** the name of the first query parameter, 1 for the second parameter, and -** so forth. -** -** If F is a NULL pointer, then sqlite3_uri_parameter(F,P) returns NULL and -** sqlite3_uri_boolean(F,P,B) returns B. If F is not a NULL pointer and -** is not a database file pathname pointer that the SQLite core passed -** into the xOpen VFS method, then the behavior of this routine is undefined -** and probably undesirable. -** -** Beginning with SQLite [version 3.31.0] ([dateof:3.31.0]) the input F -** parameter can also be the name of a rollback journal file or WAL file -** in addition to the main database file. Prior to version 3.31.0, these -** routines would only work if F was the name of the main database file. -** When the F parameter is the name of the rollback journal or WAL file, -** it has access to all the same query parameters as were found on the -** main database file. -** -** See the [URI filename] documentation for additional information. -*/ -SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam); -SQLITE_API int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault); -SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64); -SQLITE_API const char *sqlite3_uri_key(const char *zFilename, int N); - -/* -** CAPI3REF: Translate filenames -** -** These routines are available to [VFS|custom VFS implementations] for -** translating filenames between the main database file, the journal file, -** and the WAL file. -** -** If F is the name of an sqlite database file, journal file, or WAL file -** passed by the SQLite core into the VFS, then sqlite3_filename_database(F) -** returns the name of the corresponding database file. -** -** If F is the name of an sqlite database file, journal file, or WAL file -** passed by the SQLite core into the VFS, or if F is a database filename -** obtained from [sqlite3_db_filename()], then sqlite3_filename_journal(F) -** returns the name of the corresponding rollback journal file. -** -** If F is the name of an sqlite database file, journal file, or WAL file -** that was passed by the SQLite core into the VFS, or if F is a database -** filename obtained from [sqlite3_db_filename()], then -** sqlite3_filename_wal(F) returns the name of the corresponding -** WAL file. -** -** In all of the above, if F is not the name of a database, journal or WAL -** filename passed into the VFS from the SQLite core and F is not the -** return value from [sqlite3_db_filename()], then the result is -** undefined and is likely a memory access violation. -*/ -SQLITE_API const char *sqlite3_filename_database(const char*); -SQLITE_API const char *sqlite3_filename_journal(const char*); -SQLITE_API const char *sqlite3_filename_wal(const char*); - -/* -** CAPI3REF: Database File Corresponding To A Journal -** -** ^If X is the name of a rollback or WAL-mode journal file that is -** passed into the xOpen method of [sqlite3_vfs], then -** sqlite3_database_file_object(X) returns a pointer to the [sqlite3_file] -** object that represents the main database file. -** -** This routine is intended for use in custom [VFS] implementations -** only. It is not a general-purpose interface. -** The argument sqlite3_file_object(X) must be a filename pointer that -** has been passed into [sqlite3_vfs].xOpen method where the -** flags parameter to xOpen contains one of the bits -** [SQLITE_OPEN_MAIN_JOURNAL] or [SQLITE_OPEN_WAL]. Any other use -** of this routine results in undefined and probably undesirable -** behavior. -*/ -SQLITE_API sqlite3_file *sqlite3_database_file_object(const char*); - -/* -** CAPI3REF: Create and Destroy VFS Filenames -** -** These interfces are provided for use by [VFS shim] implementations and -** are not useful outside of that context. -** -** The sqlite3_create_filename(D,J,W,N,P) allocates memory to hold a version of -** database filename D with corresponding journal file J and WAL file W and -** with N URI parameters key/values pairs in the array P. The result from -** sqlite3_create_filename(D,J,W,N,P) is a pointer to a database filename that -** is safe to pass to routines like: -**
    -**
  • [sqlite3_uri_parameter()], -**
  • [sqlite3_uri_boolean()], -**
  • [sqlite3_uri_int64()], -**
  • [sqlite3_uri_key()], -**
  • [sqlite3_filename_database()], -**
  • [sqlite3_filename_journal()], or -**
  • [sqlite3_filename_wal()]. -**
-** If a memory allocation error occurs, sqlite3_create_filename() might -** return a NULL pointer. The memory obtained from sqlite3_create_filename(X) -** must be released by a corresponding call to sqlite3_free_filename(Y). -** -** The P parameter in sqlite3_create_filename(D,J,W,N,P) should be an array -** of 2*N pointers to strings. Each pair of pointers in this array corresponds -** to a key and value for a query parameter. The P parameter may be a NULL -** pointer if N is zero. None of the 2*N pointers in the P array may be -** NULL pointers and key pointers should not be empty strings. -** None of the D, J, or W parameters to sqlite3_create_filename(D,J,W,N,P) may -** be NULL pointers, though they can be empty strings. -** -** The sqlite3_free_filename(Y) routine releases a memory allocation -** previously obtained from sqlite3_create_filename(). Invoking -** sqlite3_free_filename(Y) where Y is a NULL pointer is a harmless no-op. -** -** If the Y parameter to sqlite3_free_filename(Y) is anything other -** than a NULL pointer or a pointer previously acquired from -** sqlite3_create_filename(), then bad things such as heap -** corruption or segfaults may occur. The value Y should not be -** used again after sqlite3_free_filename(Y) has been called. This means -** that if the [sqlite3_vfs.xOpen()] method of a VFS has been called using Y, -** then the corresponding [sqlite3_module.xClose() method should also be -** invoked prior to calling sqlite3_free_filename(Y). -*/ -SQLITE_API char *sqlite3_create_filename( - const char *zDatabase, - const char *zJournal, - const char *zWal, - int nParam, - const char **azParam -); -SQLITE_API void sqlite3_free_filename(char*); - -/* -** CAPI3REF: Error Codes And Messages -** METHOD: sqlite3 -** -** ^If the most recent sqlite3_* API call associated with -** [database connection] D failed, then the sqlite3_errcode(D) interface -** returns the numeric [result code] or [extended result code] for that -** API call. -** ^The sqlite3_extended_errcode() -** interface is the same except that it always returns the -** [extended result code] even when extended result codes are -** disabled. -** -** The values returned by sqlite3_errcode() and/or -** sqlite3_extended_errcode() might change with each API call. -** Except, there are some interfaces that are guaranteed to never -** change the value of the error code. The error-code preserving -** interfaces include the following: -** -**
    -**
  • sqlite3_errcode() -**
  • sqlite3_extended_errcode() -**
  • sqlite3_errmsg() -**
  • sqlite3_errmsg16() -**
  • sqlite3_error_offset() -**
-** -** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language -** text that describes the error, as either UTF-8 or UTF-16 respectively. -** ^(Memory to hold the error message string is managed internally. -** The application does not need to worry about freeing the result. -** However, the error string might be overwritten or deallocated by -** subsequent calls to other SQLite interface functions.)^ -** -** ^The sqlite3_errstr() interface returns the English-language text -** that describes the [result code], as UTF-8. -** ^(Memory to hold the error message string is managed internally -** and must not be freed by the application)^. -** -** ^If the most recent error references a specific token in the input -** SQL, the sqlite3_error_offset() interface returns the byte offset -** of the start of that token. ^The byte offset returned by -** sqlite3_error_offset() assumes that the input SQL is UTF8. -** ^If the most recent error does not reference a specific token in the input -** SQL, then the sqlite3_error_offset() function returns -1. -** -** When the serialized [threading mode] is in use, it might be the -** case that a second error occurs on a separate thread in between -** the time of the first error and the call to these interfaces. -** When that happens, the second error will be reported since these -** interfaces always report the most recent result. To avoid -** this, each thread can obtain exclusive use of the [database connection] D -** by invoking [sqlite3_mutex_enter]([sqlite3_db_mutex](D)) before beginning -** to use D and invoking [sqlite3_mutex_leave]([sqlite3_db_mutex](D)) after -** all calls to the interfaces listed here are completed. -** -** If an interface fails with SQLITE_MISUSE, that means the interface -** was invoked incorrectly by the application. In that case, the -** error code and message may or may not be set. -*/ -SQLITE_API int sqlite3_errcode(sqlite3 *db); -SQLITE_API int sqlite3_extended_errcode(sqlite3 *db); -SQLITE_API const char *sqlite3_errmsg(sqlite3*); -SQLITE_API const void *sqlite3_errmsg16(sqlite3*); -SQLITE_API const char *sqlite3_errstr(int); -SQLITE_API int sqlite3_error_offset(sqlite3 *db); - -/* -** CAPI3REF: Prepared Statement Object -** KEYWORDS: {prepared statement} {prepared statements} -** -** An instance of this object represents a single SQL statement that -** has been compiled into binary form and is ready to be evaluated. -** -** Think of each SQL statement as a separate computer program. The -** original SQL text is source code. A prepared statement object -** is the compiled object code. All SQL must be converted into a -** prepared statement before it can be run. -** -** The life-cycle of a prepared statement object usually goes like this: -** -**
    -**
  1. Create the prepared statement object using [sqlite3_prepare_v2()]. -**
  2. Bind values to [parameters] using the sqlite3_bind_*() -** interfaces. -**
  3. Run the SQL by calling [sqlite3_step()] one or more times. -**
  4. Reset the prepared statement using [sqlite3_reset()] then go back -** to step 2. Do this zero or more times. -**
  5. Destroy the object using [sqlite3_finalize()]. -**
-*/ -typedef struct sqlite3_stmt sqlite3_stmt; - -/* -** CAPI3REF: Run-time Limits -** METHOD: sqlite3 -** -** ^(This interface allows the size of various constructs to be limited -** on a connection by connection basis. The first parameter is the -** [database connection] whose limit is to be set or queried. The -** second parameter is one of the [limit categories] that define a -** class of constructs to be size limited. The third parameter is the -** new limit for that construct.)^ -** -** ^If the new limit is a negative number, the limit is unchanged. -** ^(For each limit category SQLITE_LIMIT_NAME there is a -** [limits | hard upper bound] -** set at compile-time by a C preprocessor macro called -** [limits | SQLITE_MAX_NAME]. -** (The "_LIMIT_" in the name is changed to "_MAX_".))^ -** ^Attempts to increase a limit above its hard upper bound are -** silently truncated to the hard upper bound. -** -** ^Regardless of whether or not the limit was changed, the -** [sqlite3_limit()] interface returns the prior value of the limit. -** ^Hence, to find the current value of a limit without changing it, -** simply invoke this interface with the third parameter set to -1. -** -** Run-time limits are intended for use in applications that manage -** both their own internal database and also databases that are controlled -** by untrusted external sources. An example application might be a -** web browser that has its own databases for storing history and -** separate databases controlled by JavaScript applications downloaded -** off the Internet. The internal databases can be given the -** large, default limits. Databases managed by external sources can -** be given much smaller limits designed to prevent a denial of service -** attack. Developers might also want to use the [sqlite3_set_authorizer()] -** interface to further control untrusted SQL. The size of the database -** created by an untrusted script can be contained using the -** [max_page_count] [PRAGMA]. -** -** New run-time limit categories may be added in future releases. -*/ -SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); +#define SQLITE_TRACE_STMT 0x01 +#define SQLITE_TRACE_PROFILE 0x02 +#define SQLITE_TRACE_ROW 0x04 +#define SQLITE_TRACE_CLOSE 0x08 + + /* + ** CAPI3REF: SQL Trace Hook + ** METHOD: sqlite3 + ** + ** ^The sqlite3_trace_v2(D,M,X,P) interface registers a trace callback + ** function X against [database connection] D, using property mask M + ** and context pointer P. ^If the X callback is + ** NULL or if the M mask is zero, then tracing is disabled. The + ** M argument should be the bitwise OR-ed combination of + ** zero or more [SQLITE_TRACE] constants. + ** + ** ^Each call to either sqlite3_trace() or sqlite3_trace_v2() overrides + ** (cancels) any prior calls to sqlite3_trace() or sqlite3_trace_v2(). + ** + ** ^The X callback is invoked whenever any of the events identified by + ** mask M occur. ^The integer return value from the callback is currently + ** ignored, though this may change in future releases. Callback + ** implementations should return zero to ensure future compatibility. + ** + ** ^A trace callback is invoked with four arguments: callback(T,C,P,X). + ** ^The T argument is one of the [SQLITE_TRACE] + ** constants to indicate why the callback was invoked. + ** ^The C argument is a copy of the context pointer. + ** The P and X arguments are pointers whose meanings depend on T. + ** + ** The sqlite3_trace_v2() interface is intended to replace the legacy + ** interfaces [sqlite3_trace()] and [sqlite3_profile()], both of which + ** are deprecated. + */ + SQLITE_API int + sqlite3_trace_v2(sqlite3*, unsigned uMask, int (*xCallback)(unsigned, void*, void*, void*), void* pCtx); + + /* + ** CAPI3REF: Query Progress Callbacks + ** METHOD: sqlite3 + ** + ** ^The sqlite3_progress_handler(D,N,X,P) interface causes the callback + ** function X to be invoked periodically during long running calls to + ** [sqlite3_exec()], [sqlite3_step()] and [sqlite3_get_table()] for + ** database connection D. An example use for this + ** interface is to keep a GUI updated during a large query. + ** + ** ^The parameter P is passed through as the only parameter to the + ** callback function X. ^The parameter N is the approximate number of + ** [virtual machine instructions] that are evaluated between successive + ** invocations of the callback X. ^If N is less than one then the progress + ** handler is disabled. + ** + ** ^Only a single progress handler may be defined at one time per + ** [database connection]; setting a new progress handler cancels the + ** old one. ^Setting parameter X to NULL disables the progress handler. + ** ^The progress handler is also disabled by setting N to a value less + ** than 1. + ** + ** ^If the progress callback returns non-zero, the operation is + ** interrupted. This feature can be used to implement a + ** "Cancel" button on a GUI progress dialog box. + ** + ** The progress handler callback must not do anything that will modify + ** the database connection that invoked the progress handler. + ** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their + ** database connections for the meaning of "modify" in this paragraph. + ** + */ + SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int (*)(void*), void*); + + /* + ** CAPI3REF: Opening A New Database Connection + ** CONSTRUCTOR: sqlite3 + ** + ** ^These routines open an SQLite database file as specified by the + ** filename argument. ^The filename argument is interpreted as UTF-8 for + ** sqlite3_open() and sqlite3_open_v2() and as UTF-16 in the native byte + ** order for sqlite3_open16(). ^(A [database connection] handle is usually + ** returned in *ppDb, even if an error occurs. The only exception is that + ** if SQLite is unable to allocate memory to hold the [sqlite3] object, + ** a NULL will be written into *ppDb instead of a pointer to the [sqlite3] + ** object.)^ ^(If the database is opened (and/or created) successfully, then + ** [SQLITE_OK] is returned. Otherwise an [error code] is returned.)^ ^The + ** [sqlite3_errmsg()] or [sqlite3_errmsg16()] routines can be used to obtain + ** an English language description of the error following a failure of any + ** of the sqlite3_open() routines. + ** + ** ^The default encoding will be UTF-8 for databases created using + ** sqlite3_open() or sqlite3_open_v2(). ^The default encoding for databases + ** created using sqlite3_open16() will be UTF-16 in the native byte order. + ** + ** Whether or not an error occurs when it is opened, resources + ** associated with the [database connection] handle should be released by + ** passing it to [sqlite3_close()] when it is no longer required. + ** + ** The sqlite3_open_v2() interface works like sqlite3_open() + ** except that it accepts two additional parameters for additional control + ** over the new database connection. ^(The flags parameter to + ** sqlite3_open_v2() must include, at a minimum, one of the following + ** three flag combinations:)^ + ** + **
+ ** ^(
[SQLITE_OPEN_READONLY]
+ **
The database is opened in read-only mode. If the database does not + ** already exist, an error is returned.
)^ + ** + ** ^(
[SQLITE_OPEN_READWRITE]
+ **
The database is opened for reading and writing if possible, or reading + ** only if the file is write protected by the operating system. In either + ** case the database must already exist, otherwise an error is returned.
)^ + ** + ** ^(
[SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]
+ **
The database is opened for reading and writing, and is created if + ** it does not already exist. This is the behavior that is always used for + ** sqlite3_open() and sqlite3_open16().
)^ + **
+ ** + ** In addition to the required flags, the following optional flags are + ** also supported: + ** + **
+ ** ^(
[SQLITE_OPEN_URI]
+ **
The filename can be interpreted as a URI if this flag is set.
)^ + ** + ** ^(
[SQLITE_OPEN_MEMORY]
+ **
The database will be opened as an in-memory database. The database + ** is named by the "filename" argument for the purposes of cache-sharing, + ** if shared cache mode is enabled, but the "filename" is otherwise ignored. + **
)^ + ** + ** ^(
[SQLITE_OPEN_NOMUTEX]
+ **
The new database connection will use the "multi-thread" + ** [threading mode].)^ This means that separate threads are allowed + ** to use SQLite at the same time, as long as each thread is using + ** a different [database connection]. + ** + ** ^(
[SQLITE_OPEN_FULLMUTEX]
+ **
The new database connection will use the "serialized" + ** [threading mode].)^ This means the multiple threads can safely + ** attempt to use the same database connection at the same time. + ** (Mutexes will block any actual concurrency, but in this mode + ** there is no harm in trying.) + ** + ** ^(
[SQLITE_OPEN_SHAREDCACHE]
+ **
The database is opened [shared cache] enabled, overriding + ** the default shared cache setting provided by + ** [sqlite3_enable_shared_cache()].)^ + ** + ** ^(
[SQLITE_OPEN_PRIVATECACHE]
+ **
The database is opened [shared cache] disabled, overriding + ** the default shared cache setting provided by + ** [sqlite3_enable_shared_cache()].)^ + ** + ** [[OPEN_EXRESCODE]] ^(
[SQLITE_OPEN_EXRESCODE]
+ **
The database connection comes up in "extended result code mode". + ** In other words, the database behaves has if + ** [sqlite3_extended_result_codes(db,1)] where called on the database + ** connection as soon as the connection is created. In addition to setting + ** the extended result code mode, this flag also causes [sqlite3_open_v2()] + ** to return an extended result code.
+ ** + ** [[OPEN_NOFOLLOW]] ^(
[SQLITE_OPEN_NOFOLLOW]
+ **
The database filename is not allowed to be a symbolic link
+ **
)^ + ** + ** If the 3rd parameter to sqlite3_open_v2() is not one of the + ** required combinations shown above optionally combined with other + ** [SQLITE_OPEN_READONLY | SQLITE_OPEN_* bits] + ** then the behavior is undefined. Historic versions of SQLite + ** have silently ignored surplus bits in the flags parameter to + ** sqlite3_open_v2(), however that behavior might not be carried through + ** into future versions of SQLite and so applications should not rely + ** upon it. Note in particular that the SQLITE_OPEN_EXCLUSIVE flag is a no-op + ** for sqlite3_open_v2(). The SQLITE_OPEN_EXCLUSIVE does *not* cause + ** the open to fail if the database already exists. The SQLITE_OPEN_EXCLUSIVE + ** flag is intended for use by the [sqlite3_vfs|VFS interface] only, and not + ** by sqlite3_open_v2(). + ** + ** ^The fourth parameter to sqlite3_open_v2() is the name of the + ** [sqlite3_vfs] object that defines the operating system interface that + ** the new database connection should use. ^If the fourth parameter is + ** a NULL pointer then the default [sqlite3_vfs] object is used. + ** + ** ^If the filename is ":memory:", then a private, temporary in-memory database + ** is created for the connection. ^This in-memory database will vanish when + ** the database connection is closed. Future versions of SQLite might + ** make use of additional special filenames that begin with the ":" character. + ** It is recommended that when a database filename actually does begin with + ** a ":" character you should prefix the filename with a pathname such as + ** "./" to avoid ambiguity. + ** + ** ^If the filename is an empty string, then a private, temporary + ** on-disk database will be created. ^This private database will be + ** automatically deleted as soon as the database connection is closed. + ** + ** [[URI filenames in sqlite3_open()]]

URI Filenames

+ ** + ** ^If [URI filename] interpretation is enabled, and the filename argument + ** begins with "file:", then the filename is interpreted as a URI. ^URI + ** filename interpretation is enabled if the [SQLITE_OPEN_URI] flag is + ** set in the third argument to sqlite3_open_v2(), or if it has + ** been enabled globally using the [SQLITE_CONFIG_URI] option with the + ** [sqlite3_config()] method or by the [SQLITE_USE_URI] compile-time option. + ** URI filename interpretation is turned off + ** by default, but future releases of SQLite might enable URI filename + ** interpretation by default. See "[URI filenames]" for additional + ** information. + ** + ** URI filenames are parsed according to RFC 3986. ^If the URI contains an + ** authority, then it must be either an empty string or the string + ** "localhost". ^If the authority is not an empty string or "localhost", an + ** error is returned to the caller. ^The fragment component of a URI, if + ** present, is ignored. + ** + ** ^SQLite uses the path component of the URI as the name of the disk file + ** which contains the database. ^If the path begins with a '/' character, + ** then it is interpreted as an absolute path. ^If the path does not begin + ** with a '/' (meaning that the authority section is omitted from the URI) + ** then the path is interpreted as a relative path. + ** ^(On windows, the first component of an absolute path + ** is a drive specification (e.g. "C:").)^ + ** + ** [[core URI query parameters]] + ** The query component of a URI may contain parameters that are interpreted + ** either by SQLite itself, or by a [VFS | custom VFS implementation]. + ** SQLite and its built-in [VFSes] interpret the + ** following query parameters: + ** + **
    + **
  • vfs: ^The "vfs" parameter may be used to specify the name of + ** a VFS object that provides the operating system interface that should + ** be used to access the database file on disk. ^If this option is set to + ** an empty string the default VFS object is used. ^Specifying an unknown + ** VFS is an error. ^If sqlite3_open_v2() is used and the vfs option is + ** present, then the VFS specified by the option takes precedence over + ** the value passed as the fourth parameter to sqlite3_open_v2(). + ** + **
  • mode: ^(The mode parameter may be set to either "ro", "rw", + ** "rwc", or "memory". Attempting to set it to any other value is + ** an error)^. + ** ^If "ro" is specified, then the database is opened for read-only + ** access, just as if the [SQLITE_OPEN_READONLY] flag had been set in the + ** third argument to sqlite3_open_v2(). ^If the mode option is set to + ** "rw", then the database is opened for read-write (but not create) + ** access, as if SQLITE_OPEN_READWRITE (but not SQLITE_OPEN_CREATE) had + ** been set. ^Value "rwc" is equivalent to setting both + ** SQLITE_OPEN_READWRITE and SQLITE_OPEN_CREATE. ^If the mode option is + ** set to "memory" then a pure [in-memory database] that never reads + ** or writes from disk is used. ^It is an error to specify a value for + ** the mode parameter that is less restrictive than that specified by + ** the flags passed in the third parameter to sqlite3_open_v2(). + ** + **
  • cache: ^The cache parameter may be set to either "shared" or + ** "private". ^Setting it to "shared" is equivalent to setting the + ** SQLITE_OPEN_SHAREDCACHE bit in the flags argument passed to + ** sqlite3_open_v2(). ^Setting the cache parameter to "private" is + ** equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit. + ** ^If sqlite3_open_v2() is used and the "cache" parameter is present in + ** a URI filename, its value overrides any behavior requested by setting + ** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag. + ** + **
  • psow: ^The psow parameter indicates whether or not the + ** [powersafe overwrite] property does or does not apply to the + ** storage media on which the database file resides. + ** + **
  • nolock: ^The nolock parameter is a boolean query parameter + ** which if set disables file locking in rollback journal modes. This + ** is useful for accessing a database on a filesystem that does not + ** support locking. Caution: Database corruption might result if two + ** or more processes write to the same database and any one of those + ** processes uses nolock=1. + ** + **
  • immutable: ^The immutable parameter is a boolean query + ** parameter that indicates that the database file is stored on + ** read-only media. ^When immutable is set, SQLite assumes that the + ** database file cannot be changed, even by a process with higher + ** privilege, and so the database is opened read-only and all locking + ** and change detection is disabled. Caution: Setting the immutable + ** property on a database file that does in fact change can result + ** in incorrect query results and/or [SQLITE_CORRUPT] errors. + ** See also: [SQLITE_IOCAP_IMMUTABLE]. + ** + **
+ ** + ** ^Specifying an unknown parameter in the query component of a URI is not an + ** error. Future versions of SQLite might understand additional query + ** parameters. See "[query parameters with special meaning to SQLite]" for + ** additional information. + ** + ** [[URI filename examples]]

URI filename examples

+ ** + ** + **
URI filenames Results + **
file:data.db + ** Open the file "data.db" in the current directory. + **
file:/home/fred/data.db
+ ** file:///home/fred/data.db
+ ** file://localhost/home/fred/data.db
+ ** Open the database file "/home/fred/data.db". + **
file://darkstar/home/fred/data.db + ** An error. "darkstar" is not a recognized authority. + **
+ ** file:///C:/Documents%20and%20Settings/fred/Desktop/data.db + ** Windows only: Open the file "data.db" on fred's desktop on drive + ** C:. Note that the %20 escaping in this example is not strictly + ** necessary - space characters can be used literally + ** in URI filenames. + **
file:data.db?mode=ro&cache=private + ** Open file "data.db" in the current directory for read-only access. + ** Regardless of whether or not shared-cache mode is enabled by + ** default, use a private cache. + **
file:/home/fred/data.db?vfs=unix-dotfile + ** Open file "/home/fred/data.db". Use the special VFS "unix-dotfile" + ** that uses dot-files in place of posix advisory locking. + **
file:data.db?mode=readonly + ** An error. "readonly" is not a valid option for the "mode" parameter. + ** Use "ro" instead: "file:data.db?mode=ro". + **
+ ** + ** ^URI hexadecimal escape sequences (%HH) are supported within the path and + ** query components of a URI. A hexadecimal escape sequence consists of a + ** percent sign - "%" - followed by exactly two hexadecimal digits + ** specifying an octet value. ^Before the path or query components of a + ** URI filename are interpreted, they are encoded using UTF-8 and all + ** hexadecimal escape sequences replaced by a single byte containing the + ** corresponding octet. If this process generates an invalid UTF-8 encoding, + ** the results are undefined. + ** + ** Note to Windows users: The encoding used for the filename argument + ** of sqlite3_open() and sqlite3_open_v2() must be UTF-8, not whatever + ** codepage is currently defined. Filenames containing international + ** characters must be converted to UTF-8 prior to passing them into + ** sqlite3_open() or sqlite3_open_v2(). + ** + ** Note to Windows Runtime users: The temporary directory must be set + ** prior to calling sqlite3_open() or sqlite3_open_v2(). Otherwise, various + ** features that require the use of temporary files may fail. + ** + ** See also: [sqlite3_temp_directory] + */ + SQLITE_API int sqlite3_open(const char* filename, /* Database filename (UTF-8) */ + sqlite3** ppDb /* OUT: SQLite db handle */ + ); + SQLITE_API int sqlite3_open16(const void* filename, /* Database filename (UTF-16) */ + sqlite3** ppDb /* OUT: SQLite db handle */ + ); + SQLITE_API int sqlite3_open_v2(const char* filename, /* Database filename (UTF-8) */ + sqlite3** ppDb, /* OUT: SQLite db handle */ + int flags, /* Flags */ + const char* zVfs /* Name of VFS module to use */ + ); + + /* + ** CAPI3REF: Obtain Values For URI Parameters + ** + ** These are utility routines, useful to [VFS|custom VFS implementations], + ** that check if a database file was a URI that contained a specific query + ** parameter, and if so obtains the value of that query parameter. + ** + ** The first parameter to these interfaces (hereafter referred to + ** as F) must be one of: + **
    + **
  • A database filename pointer created by the SQLite core and + ** passed into the xOpen() method of a VFS implemention, or + **
  • A filename obtained from [sqlite3_db_filename()], or + **
  • A new filename constructed using [sqlite3_create_filename()]. + **
+ ** If the F parameter is not one of the above, then the behavior is + ** undefined and probably undesirable. Older versions of SQLite were + ** more tolerant of invalid F parameters than newer versions. + ** + ** If F is a suitable filename (as described in the previous paragraph) + ** and if P is the name of the query parameter, then + ** sqlite3_uri_parameter(F,P) returns the value of the P + ** parameter if it exists or a NULL pointer if P does not appear as a + ** query parameter on F. If P is a query parameter of F and it + ** has no explicit value, then sqlite3_uri_parameter(F,P) returns + ** a pointer to an empty string. + ** + ** The sqlite3_uri_boolean(F,P,B) routine assumes that P is a boolean + ** parameter and returns true (1) or false (0) according to the value + ** of P. The sqlite3_uri_boolean(F,P,B) routine returns true (1) if the + ** value of query parameter P is one of "yes", "true", or "on" in any + ** case or if the value begins with a non-zero number. The + ** sqlite3_uri_boolean(F,P,B) routines returns false (0) if the value of + ** query parameter P is one of "no", "false", or "off" in any case or + ** if the value begins with a numeric zero. If P is not a query + ** parameter on F or if the value of P does not match any of the + ** above, then sqlite3_uri_boolean(F,P,B) returns (B!=0). + ** + ** The sqlite3_uri_int64(F,P,D) routine converts the value of P into a + ** 64-bit signed integer and returns that integer, or D if P does not + ** exist. If the value of P is something other than an integer, then + ** zero is returned. + ** + ** The sqlite3_uri_key(F,N) returns a pointer to the name (not + ** the value) of the N-th query parameter for filename F, or a NULL + ** pointer if N is less than zero or greater than the number of query + ** parameters minus 1. The N value is zero-based so N should be 0 to obtain + ** the name of the first query parameter, 1 for the second parameter, and + ** so forth. + ** + ** If F is a NULL pointer, then sqlite3_uri_parameter(F,P) returns NULL and + ** sqlite3_uri_boolean(F,P,B) returns B. If F is not a NULL pointer and + ** is not a database file pathname pointer that the SQLite core passed + ** into the xOpen VFS method, then the behavior of this routine is undefined + ** and probably undesirable. + ** + ** Beginning with SQLite [version 3.31.0] ([dateof:3.31.0]) the input F + ** parameter can also be the name of a rollback journal file or WAL file + ** in addition to the main database file. Prior to version 3.31.0, these + ** routines would only work if F was the name of the main database file. + ** When the F parameter is the name of the rollback journal or WAL file, + ** it has access to all the same query parameters as were found on the + ** main database file. + ** + ** See the [URI filename] documentation for additional information. + */ + SQLITE_API const char* sqlite3_uri_parameter(const char* zFilename, const char* zParam); + SQLITE_API int sqlite3_uri_boolean(const char* zFile, const char* zParam, int bDefault); + SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64); + SQLITE_API const char* sqlite3_uri_key(const char* zFilename, int N); + + /* + ** CAPI3REF: Translate filenames + ** + ** These routines are available to [VFS|custom VFS implementations] for + ** translating filenames between the main database file, the journal file, + ** and the WAL file. + ** + ** If F is the name of an sqlite database file, journal file, or WAL file + ** passed by the SQLite core into the VFS, then sqlite3_filename_database(F) + ** returns the name of the corresponding database file. + ** + ** If F is the name of an sqlite database file, journal file, or WAL file + ** passed by the SQLite core into the VFS, or if F is a database filename + ** obtained from [sqlite3_db_filename()], then sqlite3_filename_journal(F) + ** returns the name of the corresponding rollback journal file. + ** + ** If F is the name of an sqlite database file, journal file, or WAL file + ** that was passed by the SQLite core into the VFS, or if F is a database + ** filename obtained from [sqlite3_db_filename()], then + ** sqlite3_filename_wal(F) returns the name of the corresponding + ** WAL file. + ** + ** In all of the above, if F is not the name of a database, journal or WAL + ** filename passed into the VFS from the SQLite core and F is not the + ** return value from [sqlite3_db_filename()], then the result is + ** undefined and is likely a memory access violation. + */ + SQLITE_API const char* sqlite3_filename_database(const char*); + SQLITE_API const char* sqlite3_filename_journal(const char*); + SQLITE_API const char* sqlite3_filename_wal(const char*); + + /* + ** CAPI3REF: Database File Corresponding To A Journal + ** + ** ^If X is the name of a rollback or WAL-mode journal file that is + ** passed into the xOpen method of [sqlite3_vfs], then + ** sqlite3_database_file_object(X) returns a pointer to the [sqlite3_file] + ** object that represents the main database file. + ** + ** This routine is intended for use in custom [VFS] implementations + ** only. It is not a general-purpose interface. + ** The argument sqlite3_file_object(X) must be a filename pointer that + ** has been passed into [sqlite3_vfs].xOpen method where the + ** flags parameter to xOpen contains one of the bits + ** [SQLITE_OPEN_MAIN_JOURNAL] or [SQLITE_OPEN_WAL]. Any other use + ** of this routine results in undefined and probably undesirable + ** behavior. + */ + SQLITE_API sqlite3_file* sqlite3_database_file_object(const char*); + + /* + ** CAPI3REF: Create and Destroy VFS Filenames + ** + ** These interfces are provided for use by [VFS shim] implementations and + ** are not useful outside of that context. + ** + ** The sqlite3_create_filename(D,J,W,N,P) allocates memory to hold a version of + ** database filename D with corresponding journal file J and WAL file W and + ** with N URI parameters key/values pairs in the array P. The result from + ** sqlite3_create_filename(D,J,W,N,P) is a pointer to a database filename that + ** is safe to pass to routines like: + **
    + **
  • [sqlite3_uri_parameter()], + **
  • [sqlite3_uri_boolean()], + **
  • [sqlite3_uri_int64()], + **
  • [sqlite3_uri_key()], + **
  • [sqlite3_filename_database()], + **
  • [sqlite3_filename_journal()], or + **
  • [sqlite3_filename_wal()]. + **
+ ** If a memory allocation error occurs, sqlite3_create_filename() might + ** return a NULL pointer. The memory obtained from sqlite3_create_filename(X) + ** must be released by a corresponding call to sqlite3_free_filename(Y). + ** + ** The P parameter in sqlite3_create_filename(D,J,W,N,P) should be an array + ** of 2*N pointers to strings. Each pair of pointers in this array corresponds + ** to a key and value for a query parameter. The P parameter may be a NULL + ** pointer if N is zero. None of the 2*N pointers in the P array may be + ** NULL pointers and key pointers should not be empty strings. + ** None of the D, J, or W parameters to sqlite3_create_filename(D,J,W,N,P) may + ** be NULL pointers, though they can be empty strings. + ** + ** The sqlite3_free_filename(Y) routine releases a memory allocation + ** previously obtained from sqlite3_create_filename(). Invoking + ** sqlite3_free_filename(Y) where Y is a NULL pointer is a harmless no-op. + ** + ** If the Y parameter to sqlite3_free_filename(Y) is anything other + ** than a NULL pointer or a pointer previously acquired from + ** sqlite3_create_filename(), then bad things such as heap + ** corruption or segfaults may occur. The value Y should not be + ** used again after sqlite3_free_filename(Y) has been called. This means + ** that if the [sqlite3_vfs.xOpen()] method of a VFS has been called using Y, + ** then the corresponding [sqlite3_module.xClose() method should also be + ** invoked prior to calling sqlite3_free_filename(Y). + */ + SQLITE_API char* sqlite3_create_filename(const char* zDatabase, + const char* zJournal, + const char* zWal, + int nParam, + const char** azParam); + SQLITE_API void sqlite3_free_filename(char*); + + /* + ** CAPI3REF: Error Codes And Messages + ** METHOD: sqlite3 + ** + ** ^If the most recent sqlite3_* API call associated with + ** [database connection] D failed, then the sqlite3_errcode(D) interface + ** returns the numeric [result code] or [extended result code] for that + ** API call. + ** ^The sqlite3_extended_errcode() + ** interface is the same except that it always returns the + ** [extended result code] even when extended result codes are + ** disabled. + ** + ** The values returned by sqlite3_errcode() and/or + ** sqlite3_extended_errcode() might change with each API call. + ** Except, there are some interfaces that are guaranteed to never + ** change the value of the error code. The error-code preserving + ** interfaces include the following: + ** + **
    + **
  • sqlite3_errcode() + **
  • sqlite3_extended_errcode() + **
  • sqlite3_errmsg() + **
  • sqlite3_errmsg16() + **
  • sqlite3_error_offset() + **
+ ** + ** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language + ** text that describes the error, as either UTF-8 or UTF-16 respectively. + ** ^(Memory to hold the error message string is managed internally. + ** The application does not need to worry about freeing the result. + ** However, the error string might be overwritten or deallocated by + ** subsequent calls to other SQLite interface functions.)^ + ** + ** ^The sqlite3_errstr() interface returns the English-language text + ** that describes the [result code], as UTF-8. + ** ^(Memory to hold the error message string is managed internally + ** and must not be freed by the application)^. + ** + ** ^If the most recent error references a specific token in the input + ** SQL, the sqlite3_error_offset() interface returns the byte offset + ** of the start of that token. ^The byte offset returned by + ** sqlite3_error_offset() assumes that the input SQL is UTF8. + ** ^If the most recent error does not reference a specific token in the input + ** SQL, then the sqlite3_error_offset() function returns -1. + ** + ** When the serialized [threading mode] is in use, it might be the + ** case that a second error occurs on a separate thread in between + ** the time of the first error and the call to these interfaces. + ** When that happens, the second error will be reported since these + ** interfaces always report the most recent result. To avoid + ** this, each thread can obtain exclusive use of the [database connection] D + ** by invoking [sqlite3_mutex_enter]([sqlite3_db_mutex](D)) before beginning + ** to use D and invoking [sqlite3_mutex_leave]([sqlite3_db_mutex](D)) after + ** all calls to the interfaces listed here are completed. + ** + ** If an interface fails with SQLITE_MISUSE, that means the interface + ** was invoked incorrectly by the application. In that case, the + ** error code and message may or may not be set. + */ + SQLITE_API int sqlite3_errcode(sqlite3* db); + SQLITE_API int sqlite3_extended_errcode(sqlite3* db); + SQLITE_API const char* sqlite3_errmsg(sqlite3*); + SQLITE_API const void* sqlite3_errmsg16(sqlite3*); + SQLITE_API const char* sqlite3_errstr(int); + SQLITE_API int sqlite3_error_offset(sqlite3* db); + + /* + ** CAPI3REF: Prepared Statement Object + ** KEYWORDS: {prepared statement} {prepared statements} + ** + ** An instance of this object represents a single SQL statement that + ** has been compiled into binary form and is ready to be evaluated. + ** + ** Think of each SQL statement as a separate computer program. The + ** original SQL text is source code. A prepared statement object + ** is the compiled object code. All SQL must be converted into a + ** prepared statement before it can be run. + ** + ** The life-cycle of a prepared statement object usually goes like this: + ** + **
    + **
  1. Create the prepared statement object using [sqlite3_prepare_v2()]. + **
  2. Bind values to [parameters] using the sqlite3_bind_*() + ** interfaces. + **
  3. Run the SQL by calling [sqlite3_step()] one or more times. + **
  4. Reset the prepared statement using [sqlite3_reset()] then go back + ** to step 2. Do this zero or more times. + **
  5. Destroy the object using [sqlite3_finalize()]. + **
+ */ + typedef struct sqlite3_stmt sqlite3_stmt; + + /* + ** CAPI3REF: Run-time Limits + ** METHOD: sqlite3 + ** + ** ^(This interface allows the size of various constructs to be limited + ** on a connection by connection basis. The first parameter is the + ** [database connection] whose limit is to be set or queried. The + ** second parameter is one of the [limit categories] that define a + ** class of constructs to be size limited. The third parameter is the + ** new limit for that construct.)^ + ** + ** ^If the new limit is a negative number, the limit is unchanged. + ** ^(For each limit category SQLITE_LIMIT_NAME there is a + ** [limits | hard upper bound] + ** set at compile-time by a C preprocessor macro called + ** [limits | SQLITE_MAX_NAME]. + ** (The "_LIMIT_" in the name is changed to "_MAX_".))^ + ** ^Attempts to increase a limit above its hard upper bound are + ** silently truncated to the hard upper bound. + ** + ** ^Regardless of whether or not the limit was changed, the + ** [sqlite3_limit()] interface returns the prior value of the limit. + ** ^Hence, to find the current value of a limit without changing it, + ** simply invoke this interface with the third parameter set to -1. + ** + ** Run-time limits are intended for use in applications that manage + ** both their own internal database and also databases that are controlled + ** by untrusted external sources. An example application might be a + ** web browser that has its own databases for storing history and + ** separate databases controlled by JavaScript applications downloaded + ** off the Internet. The internal databases can be given the + ** large, default limits. Databases managed by external sources can + ** be given much smaller limits designed to prevent a denial of service + ** attack. Developers might also want to use the [sqlite3_set_authorizer()] + ** interface to further control untrusted SQL. The size of the database + ** created by an untrusted script can be contained using the + ** [max_page_count] [PRAGMA]. + ** + ** New run-time limit categories may be added in future releases. + */ + SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); /* ** CAPI3REF: Run-Time Limit Categories @@ -3998,18 +3984,18 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** [prepared statement] may start.)^ ** */ -#define SQLITE_LIMIT_LENGTH 0 -#define SQLITE_LIMIT_SQL_LENGTH 1 -#define SQLITE_LIMIT_COLUMN 2 -#define SQLITE_LIMIT_EXPR_DEPTH 3 -#define SQLITE_LIMIT_COMPOUND_SELECT 4 -#define SQLITE_LIMIT_VDBE_OP 5 -#define SQLITE_LIMIT_FUNCTION_ARG 6 -#define SQLITE_LIMIT_ATTACHED 7 -#define SQLITE_LIMIT_LIKE_PATTERN_LENGTH 8 -#define SQLITE_LIMIT_VARIABLE_NUMBER 9 -#define SQLITE_LIMIT_TRIGGER_DEPTH 10 -#define SQLITE_LIMIT_WORKER_THREADS 11 +#define SQLITE_LIMIT_LENGTH 0 +#define SQLITE_LIMIT_SQL_LENGTH 1 +#define SQLITE_LIMIT_COLUMN 2 +#define SQLITE_LIMIT_EXPR_DEPTH 3 +#define SQLITE_LIMIT_COMPOUND_SELECT 4 +#define SQLITE_LIMIT_VDBE_OP 5 +#define SQLITE_LIMIT_FUNCTION_ARG 6 +#define SQLITE_LIMIT_ATTACHED 7 +#define SQLITE_LIMIT_LIKE_PATTERN_LENGTH 8 +#define SQLITE_LIMIT_VARIABLE_NUMBER 9 +#define SQLITE_LIMIT_TRIGGER_DEPTH 10 +#define SQLITE_LIMIT_WORKER_THREADS 11 /* ** CAPI3REF: Prepare Flags @@ -4046,807 +4032,800 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** any virtual tables. ** */ -#define SQLITE_PREPARE_PERSISTENT 0x01 -#define SQLITE_PREPARE_NORMALIZE 0x02 -#define SQLITE_PREPARE_NO_VTAB 0x04 - -/* -** CAPI3REF: Compiling An SQL Statement -** KEYWORDS: {SQL statement compiler} -** METHOD: sqlite3 -** CONSTRUCTOR: sqlite3_stmt -** -** To execute an SQL statement, it must first be compiled into a byte-code -** program using one of these routines. Or, in other words, these routines -** are constructors for the [prepared statement] object. -** -** The preferred routine to use is [sqlite3_prepare_v2()]. The -** [sqlite3_prepare()] interface is legacy and should be avoided. -** [sqlite3_prepare_v3()] has an extra "prepFlags" option that is used -** for special purposes. -** -** The use of the UTF-8 interfaces is preferred, as SQLite currently -** does all parsing using UTF-8. The UTF-16 interfaces are provided -** as a convenience. The UTF-16 interfaces work by converting the -** input text into UTF-8, then invoking the corresponding UTF-8 interface. -** -** The first argument, "db", is a [database connection] obtained from a -** prior successful call to [sqlite3_open()], [sqlite3_open_v2()] or -** [sqlite3_open16()]. The database connection must not have been closed. -** -** The second argument, "zSql", is the statement to be compiled, encoded -** as either UTF-8 or UTF-16. The sqlite3_prepare(), sqlite3_prepare_v2(), -** and sqlite3_prepare_v3() -** interfaces use UTF-8, and sqlite3_prepare16(), sqlite3_prepare16_v2(), -** and sqlite3_prepare16_v3() use UTF-16. -** -** ^If the nByte argument is negative, then zSql is read up to the -** first zero terminator. ^If nByte is positive, then it is the -** number of bytes read from zSql. ^If nByte is zero, then no prepared -** statement is generated. -** If the caller knows that the supplied string is nul-terminated, then -** there is a small performance advantage to passing an nByte parameter that -** is the number of bytes in the input string including -** the nul-terminator. -** -** ^If pzTail is not NULL then *pzTail is made to point to the first byte -** past the end of the first SQL statement in zSql. These routines only -** compile the first statement in zSql, so *pzTail is left pointing to -** what remains uncompiled. -** -** ^*ppStmt is left pointing to a compiled [prepared statement] that can be -** executed using [sqlite3_step()]. ^If there is an error, *ppStmt is set -** to NULL. ^If the input text contains no SQL (if the input is an empty -** string or a comment) then *ppStmt is set to NULL. -** The calling procedure is responsible for deleting the compiled -** SQL statement using [sqlite3_finalize()] after it has finished with it. -** ppStmt may not be NULL. -** -** ^On success, the sqlite3_prepare() family of routines return [SQLITE_OK]; -** otherwise an [error code] is returned. -** -** The sqlite3_prepare_v2(), sqlite3_prepare_v3(), sqlite3_prepare16_v2(), -** and sqlite3_prepare16_v3() interfaces are recommended for all new programs. -** The older interfaces (sqlite3_prepare() and sqlite3_prepare16()) -** are retained for backwards compatibility, but their use is discouraged. -** ^In the "vX" interfaces, the prepared statement -** that is returned (the [sqlite3_stmt] object) contains a copy of the -** original SQL text. This causes the [sqlite3_step()] interface to -** behave differently in three ways: -** -**
    -**
  1. -** ^If the database schema changes, instead of returning [SQLITE_SCHEMA] as it -** always used to do, [sqlite3_step()] will automatically recompile the SQL -** statement and try to run it again. As many as [SQLITE_MAX_SCHEMA_RETRY] -** retries will occur before sqlite3_step() gives up and returns an error. -**
  2. -** -**
  3. -** ^When an error occurs, [sqlite3_step()] will return one of the detailed -** [error codes] or [extended error codes]. ^The legacy behavior was that -** [sqlite3_step()] would only return a generic [SQLITE_ERROR] result code -** and the application would have to make a second call to [sqlite3_reset()] -** in order to find the underlying cause of the problem. With the "v2" prepare -** interfaces, the underlying reason for the error is returned immediately. -**
  4. -** -**
  5. -** ^If the specific value bound to a [parameter | host parameter] in the -** WHERE clause might influence the choice of query plan for a statement, -** then the statement will be automatically recompiled, as if there had been -** a schema change, on the first [sqlite3_step()] call following any change -** to the [sqlite3_bind_text | bindings] of that [parameter]. -** ^The specific value of a WHERE-clause [parameter] might influence the -** choice of query plan if the parameter is the left-hand side of a [LIKE] -** or [GLOB] operator or if the parameter is compared to an indexed column -** and the [SQLITE_ENABLE_STAT4] compile-time option is enabled. -**
  6. -**
-** -**

^sqlite3_prepare_v3() differs from sqlite3_prepare_v2() only in having -** the extra prepFlags parameter, which is a bit array consisting of zero or -** more of the [SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_*] flags. ^The -** sqlite3_prepare_v2() interface works exactly the same as -** sqlite3_prepare_v3() with a zero prepFlags parameter. -*/ -SQLITE_API int sqlite3_prepare( - sqlite3 *db, /* Database handle */ - const char *zSql, /* SQL statement, UTF-8 encoded */ - int nByte, /* Maximum length of zSql in bytes. */ - sqlite3_stmt **ppStmt, /* OUT: Statement handle */ - const char **pzTail /* OUT: Pointer to unused portion of zSql */ -); -SQLITE_API int sqlite3_prepare_v2( - sqlite3 *db, /* Database handle */ - const char *zSql, /* SQL statement, UTF-8 encoded */ - int nByte, /* Maximum length of zSql in bytes. */ - sqlite3_stmt **ppStmt, /* OUT: Statement handle */ - const char **pzTail /* OUT: Pointer to unused portion of zSql */ -); -SQLITE_API int sqlite3_prepare_v3( - sqlite3 *db, /* Database handle */ - const char *zSql, /* SQL statement, UTF-8 encoded */ - int nByte, /* Maximum length of zSql in bytes. */ - unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */ - sqlite3_stmt **ppStmt, /* OUT: Statement handle */ - const char **pzTail /* OUT: Pointer to unused portion of zSql */ -); -SQLITE_API int sqlite3_prepare16( - sqlite3 *db, /* Database handle */ - const void *zSql, /* SQL statement, UTF-16 encoded */ - int nByte, /* Maximum length of zSql in bytes. */ - sqlite3_stmt **ppStmt, /* OUT: Statement handle */ - const void **pzTail /* OUT: Pointer to unused portion of zSql */ -); -SQLITE_API int sqlite3_prepare16_v2( - sqlite3 *db, /* Database handle */ - const void *zSql, /* SQL statement, UTF-16 encoded */ - int nByte, /* Maximum length of zSql in bytes. */ - sqlite3_stmt **ppStmt, /* OUT: Statement handle */ - const void **pzTail /* OUT: Pointer to unused portion of zSql */ -); -SQLITE_API int sqlite3_prepare16_v3( - sqlite3 *db, /* Database handle */ - const void *zSql, /* SQL statement, UTF-16 encoded */ - int nByte, /* Maximum length of zSql in bytes. */ - unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */ - sqlite3_stmt **ppStmt, /* OUT: Statement handle */ - const void **pzTail /* OUT: Pointer to unused portion of zSql */ -); - -/* -** CAPI3REF: Retrieving Statement SQL -** METHOD: sqlite3_stmt -** -** ^The sqlite3_sql(P) interface returns a pointer to a copy of the UTF-8 -** SQL text used to create [prepared statement] P if P was -** created by [sqlite3_prepare_v2()], [sqlite3_prepare_v3()], -** [sqlite3_prepare16_v2()], or [sqlite3_prepare16_v3()]. -** ^The sqlite3_expanded_sql(P) interface returns a pointer to a UTF-8 -** string containing the SQL text of prepared statement P with -** [bound parameters] expanded. -** ^The sqlite3_normalized_sql(P) interface returns a pointer to a UTF-8 -** string containing the normalized SQL text of prepared statement P. The -** semantics used to normalize a SQL statement are unspecified and subject -** to change. At a minimum, literal values will be replaced with suitable -** placeholders. -** -** ^(For example, if a prepared statement is created using the SQL -** text "SELECT $abc,:xyz" and if parameter $abc is bound to integer 2345 -** and parameter :xyz is unbound, then sqlite3_sql() will return -** the original string, "SELECT $abc,:xyz" but sqlite3_expanded_sql() -** will return "SELECT 2345,NULL".)^ -** -** ^The sqlite3_expanded_sql() interface returns NULL if insufficient memory -** is available to hold the result, or if the result would exceed the -** the maximum string length determined by the [SQLITE_LIMIT_LENGTH]. -** -** ^The [SQLITE_TRACE_SIZE_LIMIT] compile-time option limits the size of -** bound parameter expansions. ^The [SQLITE_OMIT_TRACE] compile-time -** option causes sqlite3_expanded_sql() to always return NULL. -** -** ^The strings returned by sqlite3_sql(P) and sqlite3_normalized_sql(P) -** are managed by SQLite and are automatically freed when the prepared -** statement is finalized. -** ^The string returned by sqlite3_expanded_sql(P), on the other hand, -** is obtained from [sqlite3_malloc()] and must be freed by the application -** by passing it to [sqlite3_free()]. -** -** ^The sqlite3_normalized_sql() interface is only available if -** the [SQLITE_ENABLE_NORMALIZE] compile-time option is defined. -*/ -SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt); -SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt); +#define SQLITE_PREPARE_PERSISTENT 0x01 +#define SQLITE_PREPARE_NORMALIZE 0x02 +#define SQLITE_PREPARE_NO_VTAB 0x04 + + /* + ** CAPI3REF: Compiling An SQL Statement + ** KEYWORDS: {SQL statement compiler} + ** METHOD: sqlite3 + ** CONSTRUCTOR: sqlite3_stmt + ** + ** To execute an SQL statement, it must first be compiled into a byte-code + ** program using one of these routines. Or, in other words, these routines + ** are constructors for the [prepared statement] object. + ** + ** The preferred routine to use is [sqlite3_prepare_v2()]. The + ** [sqlite3_prepare()] interface is legacy and should be avoided. + ** [sqlite3_prepare_v3()] has an extra "prepFlags" option that is used + ** for special purposes. + ** + ** The use of the UTF-8 interfaces is preferred, as SQLite currently + ** does all parsing using UTF-8. The UTF-16 interfaces are provided + ** as a convenience. The UTF-16 interfaces work by converting the + ** input text into UTF-8, then invoking the corresponding UTF-8 interface. + ** + ** The first argument, "db", is a [database connection] obtained from a + ** prior successful call to [sqlite3_open()], [sqlite3_open_v2()] or + ** [sqlite3_open16()]. The database connection must not have been closed. + ** + ** The second argument, "zSql", is the statement to be compiled, encoded + ** as either UTF-8 or UTF-16. The sqlite3_prepare(), sqlite3_prepare_v2(), + ** and sqlite3_prepare_v3() + ** interfaces use UTF-8, and sqlite3_prepare16(), sqlite3_prepare16_v2(), + ** and sqlite3_prepare16_v3() use UTF-16. + ** + ** ^If the nByte argument is negative, then zSql is read up to the + ** first zero terminator. ^If nByte is positive, then it is the + ** number of bytes read from zSql. ^If nByte is zero, then no prepared + ** statement is generated. + ** If the caller knows that the supplied string is nul-terminated, then + ** there is a small performance advantage to passing an nByte parameter that + ** is the number of bytes in the input string including + ** the nul-terminator. + ** + ** ^If pzTail is not NULL then *pzTail is made to point to the first byte + ** past the end of the first SQL statement in zSql. These routines only + ** compile the first statement in zSql, so *pzTail is left pointing to + ** what remains uncompiled. + ** + ** ^*ppStmt is left pointing to a compiled [prepared statement] that can be + ** executed using [sqlite3_step()]. ^If there is an error, *ppStmt is set + ** to NULL. ^If the input text contains no SQL (if the input is an empty + ** string or a comment) then *ppStmt is set to NULL. + ** The calling procedure is responsible for deleting the compiled + ** SQL statement using [sqlite3_finalize()] after it has finished with it. + ** ppStmt may not be NULL. + ** + ** ^On success, the sqlite3_prepare() family of routines return [SQLITE_OK]; + ** otherwise an [error code] is returned. + ** + ** The sqlite3_prepare_v2(), sqlite3_prepare_v3(), sqlite3_prepare16_v2(), + ** and sqlite3_prepare16_v3() interfaces are recommended for all new programs. + ** The older interfaces (sqlite3_prepare() and sqlite3_prepare16()) + ** are retained for backwards compatibility, but their use is discouraged. + ** ^In the "vX" interfaces, the prepared statement + ** that is returned (the [sqlite3_stmt] object) contains a copy of the + ** original SQL text. This causes the [sqlite3_step()] interface to + ** behave differently in three ways: + ** + **

    + **
  1. + ** ^If the database schema changes, instead of returning [SQLITE_SCHEMA] as it + ** always used to do, [sqlite3_step()] will automatically recompile the SQL + ** statement and try to run it again. As many as [SQLITE_MAX_SCHEMA_RETRY] + ** retries will occur before sqlite3_step() gives up and returns an error. + **
  2. + ** + **
  3. + ** ^When an error occurs, [sqlite3_step()] will return one of the detailed + ** [error codes] or [extended error codes]. ^The legacy behavior was that + ** [sqlite3_step()] would only return a generic [SQLITE_ERROR] result code + ** and the application would have to make a second call to [sqlite3_reset()] + ** in order to find the underlying cause of the problem. With the "v2" prepare + ** interfaces, the underlying reason for the error is returned immediately. + **
  4. + ** + **
  5. + ** ^If the specific value bound to a [parameter | host parameter] in the + ** WHERE clause might influence the choice of query plan for a statement, + ** then the statement will be automatically recompiled, as if there had been + ** a schema change, on the first [sqlite3_step()] call following any change + ** to the [sqlite3_bind_text | bindings] of that [parameter]. + ** ^The specific value of a WHERE-clause [parameter] might influence the + ** choice of query plan if the parameter is the left-hand side of a [LIKE] + ** or [GLOB] operator or if the parameter is compared to an indexed column + ** and the [SQLITE_ENABLE_STAT4] compile-time option is enabled. + **
  6. + **
+ ** + **

^sqlite3_prepare_v3() differs from sqlite3_prepare_v2() only in having + ** the extra prepFlags parameter, which is a bit array consisting of zero or + ** more of the [SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_*] flags. ^The + ** sqlite3_prepare_v2() interface works exactly the same as + ** sqlite3_prepare_v3() with a zero prepFlags parameter. + */ + SQLITE_API int sqlite3_prepare(sqlite3* db, /* Database handle */ + const char* zSql, /* SQL statement, UTF-8 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + sqlite3_stmt** ppStmt, /* OUT: Statement handle */ + const char** pzTail /* OUT: Pointer to unused portion of zSql */ + ); + SQLITE_API int sqlite3_prepare_v2(sqlite3* db, /* Database handle */ + const char* zSql, /* SQL statement, UTF-8 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + sqlite3_stmt** ppStmt, /* OUT: Statement handle */ + const char** pzTail /* OUT: Pointer to unused portion of zSql */ + ); + SQLITE_API int sqlite3_prepare_v3(sqlite3* db, /* Database handle */ + const char* zSql, /* SQL statement, UTF-8 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */ + sqlite3_stmt** ppStmt, /* OUT: Statement handle */ + const char** pzTail /* OUT: Pointer to unused portion of zSql */ + ); + SQLITE_API int sqlite3_prepare16(sqlite3* db, /* Database handle */ + const void* zSql, /* SQL statement, UTF-16 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + sqlite3_stmt** ppStmt, /* OUT: Statement handle */ + const void** pzTail /* OUT: Pointer to unused portion of zSql */ + ); + SQLITE_API int sqlite3_prepare16_v2(sqlite3* db, /* Database handle */ + const void* zSql, /* SQL statement, UTF-16 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + sqlite3_stmt** ppStmt, /* OUT: Statement handle */ + const void** pzTail /* OUT: Pointer to unused portion of zSql */ + ); + SQLITE_API int sqlite3_prepare16_v3(sqlite3* db, /* Database handle */ + const void* zSql, /* SQL statement, UTF-16 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */ + sqlite3_stmt** ppStmt, /* OUT: Statement handle */ + const void** pzTail /* OUT: Pointer to unused portion of zSql */ + ); + + /* + ** CAPI3REF: Retrieving Statement SQL + ** METHOD: sqlite3_stmt + ** + ** ^The sqlite3_sql(P) interface returns a pointer to a copy of the UTF-8 + ** SQL text used to create [prepared statement] P if P was + ** created by [sqlite3_prepare_v2()], [sqlite3_prepare_v3()], + ** [sqlite3_prepare16_v2()], or [sqlite3_prepare16_v3()]. + ** ^The sqlite3_expanded_sql(P) interface returns a pointer to a UTF-8 + ** string containing the SQL text of prepared statement P with + ** [bound parameters] expanded. + ** ^The sqlite3_normalized_sql(P) interface returns a pointer to a UTF-8 + ** string containing the normalized SQL text of prepared statement P. The + ** semantics used to normalize a SQL statement are unspecified and subject + ** to change. At a minimum, literal values will be replaced with suitable + ** placeholders. + ** + ** ^(For example, if a prepared statement is created using the SQL + ** text "SELECT $abc,:xyz" and if parameter $abc is bound to integer 2345 + ** and parameter :xyz is unbound, then sqlite3_sql() will return + ** the original string, "SELECT $abc,:xyz" but sqlite3_expanded_sql() + ** will return "SELECT 2345,NULL".)^ + ** + ** ^The sqlite3_expanded_sql() interface returns NULL if insufficient memory + ** is available to hold the result, or if the result would exceed the + ** the maximum string length determined by the [SQLITE_LIMIT_LENGTH]. + ** + ** ^The [SQLITE_TRACE_SIZE_LIMIT] compile-time option limits the size of + ** bound parameter expansions. ^The [SQLITE_OMIT_TRACE] compile-time + ** option causes sqlite3_expanded_sql() to always return NULL. + ** + ** ^The strings returned by sqlite3_sql(P) and sqlite3_normalized_sql(P) + ** are managed by SQLite and are automatically freed when the prepared + ** statement is finalized. + ** ^The string returned by sqlite3_expanded_sql(P), on the other hand, + ** is obtained from [sqlite3_malloc()] and must be freed by the application + ** by passing it to [sqlite3_free()]. + ** + ** ^The sqlite3_normalized_sql() interface is only available if + ** the [SQLITE_ENABLE_NORMALIZE] compile-time option is defined. + */ + SQLITE_API const char* sqlite3_sql(sqlite3_stmt* pStmt); + SQLITE_API char* sqlite3_expanded_sql(sqlite3_stmt* pStmt); #ifdef SQLITE_ENABLE_NORMALIZE -SQLITE_API const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt); + SQLITE_API const char* sqlite3_normalized_sql(sqlite3_stmt* pStmt); #endif -/* -** CAPI3REF: Determine If An SQL Statement Writes The Database -** METHOD: sqlite3_stmt -** -** ^The sqlite3_stmt_readonly(X) interface returns true (non-zero) if -** and only if the [prepared statement] X makes no direct changes to -** the content of the database file. -** -** Note that [application-defined SQL functions] or -** [virtual tables] might change the database indirectly as a side effect. -** ^(For example, if an application defines a function "eval()" that -** calls [sqlite3_exec()], then the following SQL statement would -** change the database file through side-effects: -** -**

-**    SELECT eval('DELETE FROM t1') FROM t2;
-** 
-** -** But because the [SELECT] statement does not change the database file -** directly, sqlite3_stmt_readonly() would still return true.)^ -** -** ^Transaction control statements such as [BEGIN], [COMMIT], [ROLLBACK], -** [SAVEPOINT], and [RELEASE] cause sqlite3_stmt_readonly() to return true, -** since the statements themselves do not actually modify the database but -** rather they control the timing of when other statements modify the -** database. ^The [ATTACH] and [DETACH] statements also cause -** sqlite3_stmt_readonly() to return true since, while those statements -** change the configuration of a database connection, they do not make -** changes to the content of the database files on disk. -** ^The sqlite3_stmt_readonly() interface returns true for [BEGIN] since -** [BEGIN] merely sets internal flags, but the [BEGIN|BEGIN IMMEDIATE] and -** [BEGIN|BEGIN EXCLUSIVE] commands do touch the database and so -** sqlite3_stmt_readonly() returns false for those commands. -** -** ^This routine returns false if there is any possibility that the -** statement might change the database file. ^A false return does -** not guarantee that the statement will change the database file. -** ^For example, an UPDATE statement might have a WHERE clause that -** makes it a no-op, but the sqlite3_stmt_readonly() result would still -** be false. ^Similarly, a CREATE TABLE IF NOT EXISTS statement is a -** read-only no-op if the table already exists, but -** sqlite3_stmt_readonly() still returns false for such a statement. -** -** ^If prepared statement X is an [EXPLAIN] or [EXPLAIN QUERY PLAN] -** statement, then sqlite3_stmt_readonly(X) returns the same value as -** if the EXPLAIN or EXPLAIN QUERY PLAN prefix were omitted. -*/ -SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt); - -/* -** CAPI3REF: Query The EXPLAIN Setting For A Prepared Statement -** METHOD: sqlite3_stmt -** -** ^The sqlite3_stmt_isexplain(S) interface returns 1 if the -** prepared statement S is an EXPLAIN statement, or 2 if the -** statement S is an EXPLAIN QUERY PLAN. -** ^The sqlite3_stmt_isexplain(S) interface returns 0 if S is -** an ordinary statement or a NULL pointer. -*/ -SQLITE_API int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt); - -/* -** CAPI3REF: Determine If A Prepared Statement Has Been Reset -** METHOD: sqlite3_stmt -** -** ^The sqlite3_stmt_busy(S) interface returns true (non-zero) if the -** [prepared statement] S has been stepped at least once using -** [sqlite3_step(S)] but has neither run to completion (returned -** [SQLITE_DONE] from [sqlite3_step(S)]) nor -** been reset using [sqlite3_reset(S)]. ^The sqlite3_stmt_busy(S) -** interface returns false if S is a NULL pointer. If S is not a -** NULL pointer and is not a pointer to a valid [prepared statement] -** object, then the behavior is undefined and probably undesirable. -** -** This interface can be used in combination [sqlite3_next_stmt()] -** to locate all prepared statements associated with a database -** connection that are in need of being reset. This can be used, -** for example, in diagnostic routines to search for prepared -** statements that are holding a transaction open. -*/ -SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*); - -/* -** CAPI3REF: Dynamically Typed Value Object -** KEYWORDS: {protected sqlite3_value} {unprotected sqlite3_value} -** -** SQLite uses the sqlite3_value object to represent all values -** that can be stored in a database table. SQLite uses dynamic typing -** for the values it stores. ^Values stored in sqlite3_value objects -** can be integers, floating point values, strings, BLOBs, or NULL. -** -** An sqlite3_value object may be either "protected" or "unprotected". -** Some interfaces require a protected sqlite3_value. Other interfaces -** will accept either a protected or an unprotected sqlite3_value. -** Every interface that accepts sqlite3_value arguments specifies -** whether or not it requires a protected sqlite3_value. The -** [sqlite3_value_dup()] interface can be used to construct a new -** protected sqlite3_value from an unprotected sqlite3_value. -** -** The terms "protected" and "unprotected" refer to whether or not -** a mutex is held. An internal mutex is held for a protected -** sqlite3_value object but no mutex is held for an unprotected -** sqlite3_value object. If SQLite is compiled to be single-threaded -** (with [SQLITE_THREADSAFE=0] and with [sqlite3_threadsafe()] returning 0) -** or if SQLite is run in one of reduced mutex modes -** [SQLITE_CONFIG_SINGLETHREAD] or [SQLITE_CONFIG_MULTITHREAD] -** then there is no distinction between protected and unprotected -** sqlite3_value objects and they can be used interchangeably. However, -** for maximum code portability it is recommended that applications -** still make the distinction between protected and unprotected -** sqlite3_value objects even when not strictly required. -** -** ^The sqlite3_value objects that are passed as parameters into the -** implementation of [application-defined SQL functions] are protected. -** ^The sqlite3_value objects returned by [sqlite3_vtab_rhs_value()] -** are protected. -** ^The sqlite3_value object returned by -** [sqlite3_column_value()] is unprotected. -** Unprotected sqlite3_value objects may only be used as arguments -** to [sqlite3_result_value()], [sqlite3_bind_value()], and -** [sqlite3_value_dup()]. -** The [sqlite3_value_blob | sqlite3_value_type()] family of -** interfaces require protected sqlite3_value objects. -*/ -typedef struct sqlite3_value sqlite3_value; - -/* -** CAPI3REF: SQL Function Context Object -** -** The context in which an SQL function executes is stored in an -** sqlite3_context object. ^A pointer to an sqlite3_context object -** is always first parameter to [application-defined SQL functions]. -** The application-defined SQL function implementation will pass this -** pointer through into calls to [sqlite3_result_int | sqlite3_result()], -** [sqlite3_aggregate_context()], [sqlite3_user_data()], -** [sqlite3_context_db_handle()], [sqlite3_get_auxdata()], -** and/or [sqlite3_set_auxdata()]. -*/ -typedef struct sqlite3_context sqlite3_context; - -/* -** CAPI3REF: Binding Values To Prepared Statements -** KEYWORDS: {host parameter} {host parameters} {host parameter name} -** KEYWORDS: {SQL parameter} {SQL parameters} {parameter binding} -** METHOD: sqlite3_stmt -** -** ^(In the SQL statement text input to [sqlite3_prepare_v2()] and its variants, -** literals may be replaced by a [parameter] that matches one of following -** templates: -** -**
    -**
  • ? -**
  • ?NNN -**
  • :VVV -**
  • @VVV -**
  • $VVV -**
-** -** In the templates above, NNN represents an integer literal, -** and VVV represents an alphanumeric identifier.)^ ^The values of these -** parameters (also called "host parameter names" or "SQL parameters") -** can be set using the sqlite3_bind_*() routines defined here. -** -** ^The first argument to the sqlite3_bind_*() routines is always -** a pointer to the [sqlite3_stmt] object returned from -** [sqlite3_prepare_v2()] or its variants. -** -** ^The second argument is the index of the SQL parameter to be set. -** ^The leftmost SQL parameter has an index of 1. ^When the same named -** SQL parameter is used more than once, second and subsequent -** occurrences have the same index as the first occurrence. -** ^The index for named parameters can be looked up using the -** [sqlite3_bind_parameter_index()] API if desired. ^The index -** for "?NNN" parameters is the value of NNN. -** ^The NNN value must be between 1 and the [sqlite3_limit()] -** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 32766). -** -** ^The third argument is the value to bind to the parameter. -** ^If the third parameter to sqlite3_bind_text() or sqlite3_bind_text16() -** or sqlite3_bind_blob() is a NULL pointer then the fourth parameter -** is ignored and the end result is the same as sqlite3_bind_null(). -** ^If the third parameter to sqlite3_bind_text() is not NULL, then -** it should be a pointer to well-formed UTF8 text. -** ^If the third parameter to sqlite3_bind_text16() is not NULL, then -** it should be a pointer to well-formed UTF16 text. -** ^If the third parameter to sqlite3_bind_text64() is not NULL, then -** it should be a pointer to a well-formed unicode string that is -** either UTF8 if the sixth parameter is SQLITE_UTF8, or UTF16 -** otherwise. -** -** [[byte-order determination rules]] ^The byte-order of -** UTF16 input text is determined by the byte-order mark (BOM, U+FEFF) -** found in first character, which is removed, or in the absence of a BOM -** the byte order is the native byte order of the host -** machine for sqlite3_bind_text16() or the byte order specified in -** the 6th parameter for sqlite3_bind_text64().)^ -** ^If UTF16 input text contains invalid unicode -** characters, then SQLite might change those invalid characters -** into the unicode replacement character: U+FFFD. -** -** ^(In those routines that have a fourth argument, its value is the -** number of bytes in the parameter. To be clear: the value is the -** number of bytes in the value, not the number of characters.)^ -** ^If the fourth parameter to sqlite3_bind_text() or sqlite3_bind_text16() -** is negative, then the length of the string is -** the number of bytes up to the first zero terminator. -** If the fourth parameter to sqlite3_bind_blob() is negative, then -** the behavior is undefined. -** If a non-negative fourth parameter is provided to sqlite3_bind_text() -** or sqlite3_bind_text16() or sqlite3_bind_text64() then -** that parameter must be the byte offset -** where the NUL terminator would occur assuming the string were NUL -** terminated. If any NUL characters occurs at byte offsets less than -** the value of the fourth parameter then the resulting string value will -** contain embedded NULs. The result of expressions involving strings -** with embedded NULs is undefined. -** -** ^The fifth argument to the BLOB and string binding interfaces controls -** or indicates the lifetime of the object referenced by the third parameter. -** These three options exist: -** ^ (1) A destructor to dispose of the BLOB or string after SQLite has finished -** with it may be passed. ^It is called to dispose of the BLOB or string even -** if the call to the bind API fails, except the destructor is not called if -** the third parameter is a NULL pointer or the fourth parameter is negative. -** ^ (2) The special constant, [SQLITE_STATIC], may be passsed to indicate that -** the application remains responsible for disposing of the object. ^In this -** case, the object and the provided pointer to it must remain valid until -** either the prepared statement is finalized or the same SQL parameter is -** bound to something else, whichever occurs sooner. -** ^ (3) The constant, [SQLITE_TRANSIENT], may be passed to indicate that the -** object is to be copied prior to the return from sqlite3_bind_*(). ^The -** object and pointer to it must remain valid until then. ^SQLite will then -** manage the lifetime of its private copy. -** -** ^The sixth argument to sqlite3_bind_text64() must be one of -** [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE] -** to specify the encoding of the text in the third parameter. If -** the sixth argument to sqlite3_bind_text64() is not one of the -** allowed values shown above, or if the text encoding is different -** from the encoding specified by the sixth parameter, then the behavior -** is undefined. -** -** ^The sqlite3_bind_zeroblob() routine binds a BLOB of length N that -** is filled with zeroes. ^A zeroblob uses a fixed amount of memory -** (just an integer to hold its size) while it is being processed. -** Zeroblobs are intended to serve as placeholders for BLOBs whose -** content is later written using -** [sqlite3_blob_open | incremental BLOB I/O] routines. -** ^A negative value for the zeroblob results in a zero-length BLOB. -** -** ^The sqlite3_bind_pointer(S,I,P,T,D) routine causes the I-th parameter in -** [prepared statement] S to have an SQL value of NULL, but to also be -** associated with the pointer P of type T. ^D is either a NULL pointer or -** a pointer to a destructor function for P. ^SQLite will invoke the -** destructor D with a single argument of P when it is finished using -** P. The T parameter should be a static string, preferably a string -** literal. The sqlite3_bind_pointer() routine is part of the -** [pointer passing interface] added for SQLite 3.20.0. -** -** ^If any of the sqlite3_bind_*() routines are called with a NULL pointer -** for the [prepared statement] or with a prepared statement for which -** [sqlite3_step()] has been called more recently than [sqlite3_reset()], -** then the call will return [SQLITE_MISUSE]. If any sqlite3_bind_() -** routine is passed a [prepared statement] that has been finalized, the -** result is undefined and probably harmful. -** -** ^Bindings are not cleared by the [sqlite3_reset()] routine. -** ^Unbound parameters are interpreted as NULL. -** -** ^The sqlite3_bind_* routines return [SQLITE_OK] on success or an -** [error code] if anything goes wrong. -** ^[SQLITE_TOOBIG] might be returned if the size of a string or BLOB -** exceeds limits imposed by [sqlite3_limit]([SQLITE_LIMIT_LENGTH]) or -** [SQLITE_MAX_LENGTH]. -** ^[SQLITE_RANGE] is returned if the parameter -** index is out of range. ^[SQLITE_NOMEM] is returned if malloc() fails. -** -** See also: [sqlite3_bind_parameter_count()], -** [sqlite3_bind_parameter_name()], and [sqlite3_bind_parameter_index()]. -*/ -SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*)); -SQLITE_API int sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64, - void(*)(void*)); -SQLITE_API int sqlite3_bind_double(sqlite3_stmt*, int, double); -SQLITE_API int sqlite3_bind_int(sqlite3_stmt*, int, int); -SQLITE_API int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64); -SQLITE_API int sqlite3_bind_null(sqlite3_stmt*, int); -SQLITE_API int sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*)); -SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*)); -SQLITE_API int sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64, - void(*)(void*), unsigned char encoding); -SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*); -SQLITE_API int sqlite3_bind_pointer(sqlite3_stmt*, int, void*, const char*,void(*)(void*)); -SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n); -SQLITE_API int sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite3_uint64); - -/* -** CAPI3REF: Number Of SQL Parameters -** METHOD: sqlite3_stmt -** -** ^This routine can be used to find the number of [SQL parameters] -** in a [prepared statement]. SQL parameters are tokens of the -** form "?", "?NNN", ":AAA", "$AAA", or "@AAA" that serve as -** placeholders for values that are [sqlite3_bind_blob | bound] -** to the parameters at a later time. -** -** ^(This routine actually returns the index of the largest (rightmost) -** parameter. For all forms except ?NNN, this will correspond to the -** number of unique parameters. If parameters of the ?NNN form are used, -** there may be gaps in the list.)^ -** -** See also: [sqlite3_bind_blob|sqlite3_bind()], -** [sqlite3_bind_parameter_name()], and -** [sqlite3_bind_parameter_index()]. -*/ -SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt*); - -/* -** CAPI3REF: Name Of A Host Parameter -** METHOD: sqlite3_stmt -** -** ^The sqlite3_bind_parameter_name(P,N) interface returns -** the name of the N-th [SQL parameter] in the [prepared statement] P. -** ^(SQL parameters of the form "?NNN" or ":AAA" or "@AAA" or "$AAA" -** have a name which is the string "?NNN" or ":AAA" or "@AAA" or "$AAA" -** respectively. -** In other words, the initial ":" or "$" or "@" or "?" -** is included as part of the name.)^ -** ^Parameters of the form "?" without a following integer have no name -** and are referred to as "nameless" or "anonymous parameters". -** -** ^The first host parameter has an index of 1, not 0. -** -** ^If the value N is out of range or if the N-th parameter is -** nameless, then NULL is returned. ^The returned string is -** always in UTF-8 encoding even if the named parameter was -** originally specified as UTF-16 in [sqlite3_prepare16()], -** [sqlite3_prepare16_v2()], or [sqlite3_prepare16_v3()]. -** -** See also: [sqlite3_bind_blob|sqlite3_bind()], -** [sqlite3_bind_parameter_count()], and -** [sqlite3_bind_parameter_index()]. -*/ -SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int); - -/* -** CAPI3REF: Index Of A Parameter With A Given Name -** METHOD: sqlite3_stmt -** -** ^Return the index of an SQL parameter given its name. ^The -** index value returned is suitable for use as the second -** parameter to [sqlite3_bind_blob|sqlite3_bind()]. ^A zero -** is returned if no matching parameter is found. ^The parameter -** name must be given in UTF-8 even if the original statement -** was prepared from UTF-16 text using [sqlite3_prepare16_v2()] or -** [sqlite3_prepare16_v3()]. -** -** See also: [sqlite3_bind_blob|sqlite3_bind()], -** [sqlite3_bind_parameter_count()], and -** [sqlite3_bind_parameter_name()]. -*/ -SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName); - -/* -** CAPI3REF: Reset All Bindings On A Prepared Statement -** METHOD: sqlite3_stmt -** -** ^Contrary to the intuition of many, [sqlite3_reset()] does not reset -** the [sqlite3_bind_blob | bindings] on a [prepared statement]. -** ^Use this routine to reset all host parameters to NULL. -*/ -SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt*); - -/* -** CAPI3REF: Number Of Columns In A Result Set -** METHOD: sqlite3_stmt -** -** ^Return the number of columns in the result set returned by the -** [prepared statement]. ^If this routine returns 0, that means the -** [prepared statement] returns no data (for example an [UPDATE]). -** ^However, just because this routine returns a positive number does not -** mean that one or more rows of data will be returned. ^A SELECT statement -** will always have a positive sqlite3_column_count() but depending on the -** WHERE clause constraints and the table content, it might return no rows. -** -** See also: [sqlite3_data_count()] -*/ -SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt); - -/* -** CAPI3REF: Column Names In A Result Set -** METHOD: sqlite3_stmt -** -** ^These routines return the name assigned to a particular column -** in the result set of a [SELECT] statement. ^The sqlite3_column_name() -** interface returns a pointer to a zero-terminated UTF-8 string -** and sqlite3_column_name16() returns a pointer to a zero-terminated -** UTF-16 string. ^The first parameter is the [prepared statement] -** that implements the [SELECT] statement. ^The second parameter is the -** column number. ^The leftmost column is number 0. -** -** ^The returned string pointer is valid until either the [prepared statement] -** is destroyed by [sqlite3_finalize()] or until the statement is automatically -** reprepared by the first call to [sqlite3_step()] for a particular run -** or until the next call to -** sqlite3_column_name() or sqlite3_column_name16() on the same column. -** -** ^If sqlite3_malloc() fails during the processing of either routine -** (for example during a conversion from UTF-8 to UTF-16) then a -** NULL pointer is returned. -** -** ^The name of a result column is the value of the "AS" clause for -** that column, if there is an AS clause. If there is no AS clause -** then the name of the column is unspecified and may change from -** one release of SQLite to the next. -*/ -SQLITE_API const char *sqlite3_column_name(sqlite3_stmt*, int N); -SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N); - -/* -** CAPI3REF: Source Of Data In A Query Result -** METHOD: sqlite3_stmt -** -** ^These routines provide a means to determine the database, table, and -** table column that is the origin of a particular result column in -** [SELECT] statement. -** ^The name of the database or table or column can be returned as -** either a UTF-8 or UTF-16 string. ^The _database_ routines return -** the database name, the _table_ routines return the table name, and -** the origin_ routines return the column name. -** ^The returned string is valid until the [prepared statement] is destroyed -** using [sqlite3_finalize()] or until the statement is automatically -** reprepared by the first call to [sqlite3_step()] for a particular run -** or until the same information is requested -** again in a different encoding. -** -** ^The names returned are the original un-aliased names of the -** database, table, and column. -** -** ^The first argument to these interfaces is a [prepared statement]. -** ^These functions return information about the Nth result column returned by -** the statement, where N is the second function argument. -** ^The left-most column is column 0 for these routines. -** -** ^If the Nth column returned by the statement is an expression or -** subquery and is not a column value, then all of these functions return -** NULL. ^These routines might also return NULL if a memory allocation error -** occurs. ^Otherwise, they return the name of the attached database, table, -** or column that query result column was extracted from. -** -** ^As with all other SQLite APIs, those whose names end with "16" return -** UTF-16 encoded strings and the other functions return UTF-8. -** -** ^These APIs are only available if the library was compiled with the -** [SQLITE_ENABLE_COLUMN_METADATA] C-preprocessor symbol. -** -** If two or more threads call one or more -** [sqlite3_column_database_name | column metadata interfaces] -** for the same [prepared statement] and result column -** at the same time then the results are undefined. -*/ -SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt*,int); -SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt*,int); -SQLITE_API const char *sqlite3_column_table_name(sqlite3_stmt*,int); -SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt*,int); -SQLITE_API const char *sqlite3_column_origin_name(sqlite3_stmt*,int); -SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt*,int); - -/* -** CAPI3REF: Declared Datatype Of A Query Result -** METHOD: sqlite3_stmt -** -** ^(The first parameter is a [prepared statement]. -** If this statement is a [SELECT] statement and the Nth column of the -** returned result set of that [SELECT] is a table column (not an -** expression or subquery) then the declared type of the table -** column is returned.)^ ^If the Nth column of the result set is an -** expression or subquery, then a NULL pointer is returned. -** ^The returned string is always UTF-8 encoded. -** -** ^(For example, given the database schema: -** -** CREATE TABLE t1(c1 VARIANT); -** -** and the following statement to be compiled: -** -** SELECT c1 + 1, c1 FROM t1; -** -** this routine would return the string "VARIANT" for the second result -** column (i==1), and a NULL pointer for the first result column (i==0).)^ -** -** ^SQLite uses dynamic run-time typing. ^So just because a column -** is declared to contain a particular type does not mean that the -** data stored in that column is of the declared type. SQLite is -** strongly typed, but the typing is dynamic not static. ^Type -** is associated with individual values, not with the containers -** used to hold those values. -*/ -SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt*,int); -SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int); - -/* -** CAPI3REF: Evaluate An SQL Statement -** METHOD: sqlite3_stmt -** -** After a [prepared statement] has been prepared using any of -** [sqlite3_prepare_v2()], [sqlite3_prepare_v3()], [sqlite3_prepare16_v2()], -** or [sqlite3_prepare16_v3()] or one of the legacy -** interfaces [sqlite3_prepare()] or [sqlite3_prepare16()], this function -** must be called one or more times to evaluate the statement. -** -** The details of the behavior of the sqlite3_step() interface depend -** on whether the statement was prepared using the newer "vX" interfaces -** [sqlite3_prepare_v3()], [sqlite3_prepare_v2()], [sqlite3_prepare16_v3()], -** [sqlite3_prepare16_v2()] or the older legacy -** interfaces [sqlite3_prepare()] and [sqlite3_prepare16()]. The use of the -** new "vX" interface is recommended for new applications but the legacy -** interface will continue to be supported. -** -** ^In the legacy interface, the return value will be either [SQLITE_BUSY], -** [SQLITE_DONE], [SQLITE_ROW], [SQLITE_ERROR], or [SQLITE_MISUSE]. -** ^With the "v2" interface, any of the other [result codes] or -** [extended result codes] might be returned as well. -** -** ^[SQLITE_BUSY] means that the database engine was unable to acquire the -** database locks it needs to do its job. ^If the statement is a [COMMIT] -** or occurs outside of an explicit transaction, then you can retry the -** statement. If the statement is not a [COMMIT] and occurs within an -** explicit transaction then you should rollback the transaction before -** continuing. -** -** ^[SQLITE_DONE] means that the statement has finished executing -** successfully. sqlite3_step() should not be called again on this virtual -** machine without first calling [sqlite3_reset()] to reset the virtual -** machine back to its initial state. -** -** ^If the SQL statement being executed returns any data, then [SQLITE_ROW] -** is returned each time a new row of data is ready for processing by the -** caller. The values may be accessed using the [column access functions]. -** sqlite3_step() is called again to retrieve the next row of data. -** -** ^[SQLITE_ERROR] means that a run-time error (such as a constraint -** violation) has occurred. sqlite3_step() should not be called again on -** the VM. More information may be found by calling [sqlite3_errmsg()]. -** ^With the legacy interface, a more specific error code (for example, -** [SQLITE_INTERRUPT], [SQLITE_SCHEMA], [SQLITE_CORRUPT], and so forth) -** can be obtained by calling [sqlite3_reset()] on the -** [prepared statement]. ^In the "v2" interface, -** the more specific error code is returned directly by sqlite3_step(). -** -** [SQLITE_MISUSE] means that the this routine was called inappropriately. -** Perhaps it was called on a [prepared statement] that has -** already been [sqlite3_finalize | finalized] or on one that had -** previously returned [SQLITE_ERROR] or [SQLITE_DONE]. Or it could -** be the case that the same database connection is being used by two or -** more threads at the same moment in time. -** -** For all versions of SQLite up to and including 3.6.23.1, a call to -** [sqlite3_reset()] was required after sqlite3_step() returned anything -** other than [SQLITE_ROW] before any subsequent invocation of -** sqlite3_step(). Failure to reset the prepared statement using -** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from -** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1], -** sqlite3_step() began -** calling [sqlite3_reset()] automatically in this circumstance rather -** than returning [SQLITE_MISUSE]. This is not considered a compatibility -** break because any application that ever receives an SQLITE_MISUSE error -** is broken by definition. The [SQLITE_OMIT_AUTORESET] compile-time option -** can be used to restore the legacy behavior. -** -** Goofy Interface Alert: In the legacy interface, the sqlite3_step() -** API always returns a generic error code, [SQLITE_ERROR], following any -** error other than [SQLITE_BUSY] and [SQLITE_MISUSE]. You must call -** [sqlite3_reset()] or [sqlite3_finalize()] in order to find one of the -** specific [error codes] that better describes the error. -** We admit that this is a goofy design. The problem has been fixed -** with the "v2" interface. If you prepare all of your SQL statements -** using [sqlite3_prepare_v3()] or [sqlite3_prepare_v2()] -** or [sqlite3_prepare16_v2()] or [sqlite3_prepare16_v3()] instead -** of the legacy [sqlite3_prepare()] and [sqlite3_prepare16()] interfaces, -** then the more specific [error codes] are returned directly -** by sqlite3_step(). The use of the "vX" interfaces is recommended. -*/ -SQLITE_API int sqlite3_step(sqlite3_stmt*); - -/* -** CAPI3REF: Number of columns in a result set -** METHOD: sqlite3_stmt -** -** ^The sqlite3_data_count(P) interface returns the number of columns in the -** current row of the result set of [prepared statement] P. -** ^If prepared statement P does not have results ready to return -** (via calls to the [sqlite3_column_int | sqlite3_column()] family of -** interfaces) then sqlite3_data_count(P) returns 0. -** ^The sqlite3_data_count(P) routine also returns 0 if P is a NULL pointer. -** ^The sqlite3_data_count(P) routine returns 0 if the previous call to -** [sqlite3_step](P) returned [SQLITE_DONE]. ^The sqlite3_data_count(P) -** will return non-zero if previous call to [sqlite3_step](P) returned -** [SQLITE_ROW], except in the case of the [PRAGMA incremental_vacuum] -** where it always returns zero since each step of that multi-step -** pragma returns 0 columns of data. -** -** See also: [sqlite3_column_count()] -*/ -SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt); + /* + ** CAPI3REF: Determine If An SQL Statement Writes The Database + ** METHOD: sqlite3_stmt + ** + ** ^The sqlite3_stmt_readonly(X) interface returns true (non-zero) if + ** and only if the [prepared statement] X makes no direct changes to + ** the content of the database file. + ** + ** Note that [application-defined SQL functions] or + ** [virtual tables] might change the database indirectly as a side effect. + ** ^(For example, if an application defines a function "eval()" that + ** calls [sqlite3_exec()], then the following SQL statement would + ** change the database file through side-effects: + ** + **
+    **    SELECT eval('DELETE FROM t1') FROM t2;
+    ** 
+ ** + ** But because the [SELECT] statement does not change the database file + ** directly, sqlite3_stmt_readonly() would still return true.)^ + ** + ** ^Transaction control statements such as [BEGIN], [COMMIT], [ROLLBACK], + ** [SAVEPOINT], and [RELEASE] cause sqlite3_stmt_readonly() to return true, + ** since the statements themselves do not actually modify the database but + ** rather they control the timing of when other statements modify the + ** database. ^The [ATTACH] and [DETACH] statements also cause + ** sqlite3_stmt_readonly() to return true since, while those statements + ** change the configuration of a database connection, they do not make + ** changes to the content of the database files on disk. + ** ^The sqlite3_stmt_readonly() interface returns true for [BEGIN] since + ** [BEGIN] merely sets internal flags, but the [BEGIN|BEGIN IMMEDIATE] and + ** [BEGIN|BEGIN EXCLUSIVE] commands do touch the database and so + ** sqlite3_stmt_readonly() returns false for those commands. + ** + ** ^This routine returns false if there is any possibility that the + ** statement might change the database file. ^A false return does + ** not guarantee that the statement will change the database file. + ** ^For example, an UPDATE statement might have a WHERE clause that + ** makes it a no-op, but the sqlite3_stmt_readonly() result would still + ** be false. ^Similarly, a CREATE TABLE IF NOT EXISTS statement is a + ** read-only no-op if the table already exists, but + ** sqlite3_stmt_readonly() still returns false for such a statement. + ** + ** ^If prepared statement X is an [EXPLAIN] or [EXPLAIN QUERY PLAN] + ** statement, then sqlite3_stmt_readonly(X) returns the same value as + ** if the EXPLAIN or EXPLAIN QUERY PLAN prefix were omitted. + */ + SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt* pStmt); + + /* + ** CAPI3REF: Query The EXPLAIN Setting For A Prepared Statement + ** METHOD: sqlite3_stmt + ** + ** ^The sqlite3_stmt_isexplain(S) interface returns 1 if the + ** prepared statement S is an EXPLAIN statement, or 2 if the + ** statement S is an EXPLAIN QUERY PLAN. + ** ^The sqlite3_stmt_isexplain(S) interface returns 0 if S is + ** an ordinary statement or a NULL pointer. + */ + SQLITE_API int sqlite3_stmt_isexplain(sqlite3_stmt* pStmt); + + /* + ** CAPI3REF: Determine If A Prepared Statement Has Been Reset + ** METHOD: sqlite3_stmt + ** + ** ^The sqlite3_stmt_busy(S) interface returns true (non-zero) if the + ** [prepared statement] S has been stepped at least once using + ** [sqlite3_step(S)] but has neither run to completion (returned + ** [SQLITE_DONE] from [sqlite3_step(S)]) nor + ** been reset using [sqlite3_reset(S)]. ^The sqlite3_stmt_busy(S) + ** interface returns false if S is a NULL pointer. If S is not a + ** NULL pointer and is not a pointer to a valid [prepared statement] + ** object, then the behavior is undefined and probably undesirable. + ** + ** This interface can be used in combination [sqlite3_next_stmt()] + ** to locate all prepared statements associated with a database + ** connection that are in need of being reset. This can be used, + ** for example, in diagnostic routines to search for prepared + ** statements that are holding a transaction open. + */ + SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*); + + /* + ** CAPI3REF: Dynamically Typed Value Object + ** KEYWORDS: {protected sqlite3_value} {unprotected sqlite3_value} + ** + ** SQLite uses the sqlite3_value object to represent all values + ** that can be stored in a database table. SQLite uses dynamic typing + ** for the values it stores. ^Values stored in sqlite3_value objects + ** can be integers, floating point values, strings, BLOBs, or NULL. + ** + ** An sqlite3_value object may be either "protected" or "unprotected". + ** Some interfaces require a protected sqlite3_value. Other interfaces + ** will accept either a protected or an unprotected sqlite3_value. + ** Every interface that accepts sqlite3_value arguments specifies + ** whether or not it requires a protected sqlite3_value. The + ** [sqlite3_value_dup()] interface can be used to construct a new + ** protected sqlite3_value from an unprotected sqlite3_value. + ** + ** The terms "protected" and "unprotected" refer to whether or not + ** a mutex is held. An internal mutex is held for a protected + ** sqlite3_value object but no mutex is held for an unprotected + ** sqlite3_value object. If SQLite is compiled to be single-threaded + ** (with [SQLITE_THREADSAFE=0] and with [sqlite3_threadsafe()] returning 0) + ** or if SQLite is run in one of reduced mutex modes + ** [SQLITE_CONFIG_SINGLETHREAD] or [SQLITE_CONFIG_MULTITHREAD] + ** then there is no distinction between protected and unprotected + ** sqlite3_value objects and they can be used interchangeably. However, + ** for maximum code portability it is recommended that applications + ** still make the distinction between protected and unprotected + ** sqlite3_value objects even when not strictly required. + ** + ** ^The sqlite3_value objects that are passed as parameters into the + ** implementation of [application-defined SQL functions] are protected. + ** ^The sqlite3_value objects returned by [sqlite3_vtab_rhs_value()] + ** are protected. + ** ^The sqlite3_value object returned by + ** [sqlite3_column_value()] is unprotected. + ** Unprotected sqlite3_value objects may only be used as arguments + ** to [sqlite3_result_value()], [sqlite3_bind_value()], and + ** [sqlite3_value_dup()]. + ** The [sqlite3_value_blob | sqlite3_value_type()] family of + ** interfaces require protected sqlite3_value objects. + */ + typedef struct sqlite3_value sqlite3_value; + + /* + ** CAPI3REF: SQL Function Context Object + ** + ** The context in which an SQL function executes is stored in an + ** sqlite3_context object. ^A pointer to an sqlite3_context object + ** is always first parameter to [application-defined SQL functions]. + ** The application-defined SQL function implementation will pass this + ** pointer through into calls to [sqlite3_result_int | sqlite3_result()], + ** [sqlite3_aggregate_context()], [sqlite3_user_data()], + ** [sqlite3_context_db_handle()], [sqlite3_get_auxdata()], + ** and/or [sqlite3_set_auxdata()]. + */ + typedef struct sqlite3_context sqlite3_context; + + /* + ** CAPI3REF: Binding Values To Prepared Statements + ** KEYWORDS: {host parameter} {host parameters} {host parameter name} + ** KEYWORDS: {SQL parameter} {SQL parameters} {parameter binding} + ** METHOD: sqlite3_stmt + ** + ** ^(In the SQL statement text input to [sqlite3_prepare_v2()] and its variants, + ** literals may be replaced by a [parameter] that matches one of following + ** templates: + ** + **
    + **
  • ? + **
  • ?NNN + **
  • :VVV + **
  • @VVV + **
  • $VVV + **
+ ** + ** In the templates above, NNN represents an integer literal, + ** and VVV represents an alphanumeric identifier.)^ ^The values of these + ** parameters (also called "host parameter names" or "SQL parameters") + ** can be set using the sqlite3_bind_*() routines defined here. + ** + ** ^The first argument to the sqlite3_bind_*() routines is always + ** a pointer to the [sqlite3_stmt] object returned from + ** [sqlite3_prepare_v2()] or its variants. + ** + ** ^The second argument is the index of the SQL parameter to be set. + ** ^The leftmost SQL parameter has an index of 1. ^When the same named + ** SQL parameter is used more than once, second and subsequent + ** occurrences have the same index as the first occurrence. + ** ^The index for named parameters can be looked up using the + ** [sqlite3_bind_parameter_index()] API if desired. ^The index + ** for "?NNN" parameters is the value of NNN. + ** ^The NNN value must be between 1 and the [sqlite3_limit()] + ** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 32766). + ** + ** ^The third argument is the value to bind to the parameter. + ** ^If the third parameter to sqlite3_bind_text() or sqlite3_bind_text16() + ** or sqlite3_bind_blob() is a NULL pointer then the fourth parameter + ** is ignored and the end result is the same as sqlite3_bind_null(). + ** ^If the third parameter to sqlite3_bind_text() is not NULL, then + ** it should be a pointer to well-formed UTF8 text. + ** ^If the third parameter to sqlite3_bind_text16() is not NULL, then + ** it should be a pointer to well-formed UTF16 text. + ** ^If the third parameter to sqlite3_bind_text64() is not NULL, then + ** it should be a pointer to a well-formed unicode string that is + ** either UTF8 if the sixth parameter is SQLITE_UTF8, or UTF16 + ** otherwise. + ** + ** [[byte-order determination rules]] ^The byte-order of + ** UTF16 input text is determined by the byte-order mark (BOM, U+FEFF) + ** found in first character, which is removed, or in the absence of a BOM + ** the byte order is the native byte order of the host + ** machine for sqlite3_bind_text16() or the byte order specified in + ** the 6th parameter for sqlite3_bind_text64().)^ + ** ^If UTF16 input text contains invalid unicode + ** characters, then SQLite might change those invalid characters + ** into the unicode replacement character: U+FFFD. + ** + ** ^(In those routines that have a fourth argument, its value is the + ** number of bytes in the parameter. To be clear: the value is the + ** number of bytes in the value, not the number of characters.)^ + ** ^If the fourth parameter to sqlite3_bind_text() or sqlite3_bind_text16() + ** is negative, then the length of the string is + ** the number of bytes up to the first zero terminator. + ** If the fourth parameter to sqlite3_bind_blob() is negative, then + ** the behavior is undefined. + ** If a non-negative fourth parameter is provided to sqlite3_bind_text() + ** or sqlite3_bind_text16() or sqlite3_bind_text64() then + ** that parameter must be the byte offset + ** where the NUL terminator would occur assuming the string were NUL + ** terminated. If any NUL characters occurs at byte offsets less than + ** the value of the fourth parameter then the resulting string value will + ** contain embedded NULs. The result of expressions involving strings + ** with embedded NULs is undefined. + ** + ** ^The fifth argument to the BLOB and string binding interfaces controls + ** or indicates the lifetime of the object referenced by the third parameter. + ** These three options exist: + ** ^ (1) A destructor to dispose of the BLOB or string after SQLite has finished + ** with it may be passed. ^It is called to dispose of the BLOB or string even + ** if the call to the bind API fails, except the destructor is not called if + ** the third parameter is a NULL pointer or the fourth parameter is negative. + ** ^ (2) The special constant, [SQLITE_STATIC], may be passsed to indicate that + ** the application remains responsible for disposing of the object. ^In this + ** case, the object and the provided pointer to it must remain valid until + ** either the prepared statement is finalized or the same SQL parameter is + ** bound to something else, whichever occurs sooner. + ** ^ (3) The constant, [SQLITE_TRANSIENT], may be passed to indicate that the + ** object is to be copied prior to the return from sqlite3_bind_*(). ^The + ** object and pointer to it must remain valid until then. ^SQLite will then + ** manage the lifetime of its private copy. + ** + ** ^The sixth argument to sqlite3_bind_text64() must be one of + ** [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE] + ** to specify the encoding of the text in the third parameter. If + ** the sixth argument to sqlite3_bind_text64() is not one of the + ** allowed values shown above, or if the text encoding is different + ** from the encoding specified by the sixth parameter, then the behavior + ** is undefined. + ** + ** ^The sqlite3_bind_zeroblob() routine binds a BLOB of length N that + ** is filled with zeroes. ^A zeroblob uses a fixed amount of memory + ** (just an integer to hold its size) while it is being processed. + ** Zeroblobs are intended to serve as placeholders for BLOBs whose + ** content is later written using + ** [sqlite3_blob_open | incremental BLOB I/O] routines. + ** ^A negative value for the zeroblob results in a zero-length BLOB. + ** + ** ^The sqlite3_bind_pointer(S,I,P,T,D) routine causes the I-th parameter in + ** [prepared statement] S to have an SQL value of NULL, but to also be + ** associated with the pointer P of type T. ^D is either a NULL pointer or + ** a pointer to a destructor function for P. ^SQLite will invoke the + ** destructor D with a single argument of P when it is finished using + ** P. The T parameter should be a static string, preferably a string + ** literal. The sqlite3_bind_pointer() routine is part of the + ** [pointer passing interface] added for SQLite 3.20.0. + ** + ** ^If any of the sqlite3_bind_*() routines are called with a NULL pointer + ** for the [prepared statement] or with a prepared statement for which + ** [sqlite3_step()] has been called more recently than [sqlite3_reset()], + ** then the call will return [SQLITE_MISUSE]. If any sqlite3_bind_() + ** routine is passed a [prepared statement] that has been finalized, the + ** result is undefined and probably harmful. + ** + ** ^Bindings are not cleared by the [sqlite3_reset()] routine. + ** ^Unbound parameters are interpreted as NULL. + ** + ** ^The sqlite3_bind_* routines return [SQLITE_OK] on success or an + ** [error code] if anything goes wrong. + ** ^[SQLITE_TOOBIG] might be returned if the size of a string or BLOB + ** exceeds limits imposed by [sqlite3_limit]([SQLITE_LIMIT_LENGTH]) or + ** [SQLITE_MAX_LENGTH]. + ** ^[SQLITE_RANGE] is returned if the parameter + ** index is out of range. ^[SQLITE_NOMEM] is returned if malloc() fails. + ** + ** See also: [sqlite3_bind_parameter_count()], + ** [sqlite3_bind_parameter_name()], and [sqlite3_bind_parameter_index()]. + */ + SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void (*)(void*)); + SQLITE_API int sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64, void (*)(void*)); + SQLITE_API int sqlite3_bind_double(sqlite3_stmt*, int, double); + SQLITE_API int sqlite3_bind_int(sqlite3_stmt*, int, int); + SQLITE_API int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64); + SQLITE_API int sqlite3_bind_null(sqlite3_stmt*, int); + SQLITE_API int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int, void (*)(void*)); + SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void (*)(void*)); + SQLITE_API int + sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64, void (*)(void*), unsigned char encoding); + SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*); + SQLITE_API int sqlite3_bind_pointer(sqlite3_stmt*, int, void*, const char*, void (*)(void*)); + SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n); + SQLITE_API int sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite3_uint64); + + /* + ** CAPI3REF: Number Of SQL Parameters + ** METHOD: sqlite3_stmt + ** + ** ^This routine can be used to find the number of [SQL parameters] + ** in a [prepared statement]. SQL parameters are tokens of the + ** form "?", "?NNN", ":AAA", "$AAA", or "@AAA" that serve as + ** placeholders for values that are [sqlite3_bind_blob | bound] + ** to the parameters at a later time. + ** + ** ^(This routine actually returns the index of the largest (rightmost) + ** parameter. For all forms except ?NNN, this will correspond to the + ** number of unique parameters. If parameters of the ?NNN form are used, + ** there may be gaps in the list.)^ + ** + ** See also: [sqlite3_bind_blob|sqlite3_bind()], + ** [sqlite3_bind_parameter_name()], and + ** [sqlite3_bind_parameter_index()]. + */ + SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt*); + + /* + ** CAPI3REF: Name Of A Host Parameter + ** METHOD: sqlite3_stmt + ** + ** ^The sqlite3_bind_parameter_name(P,N) interface returns + ** the name of the N-th [SQL parameter] in the [prepared statement] P. + ** ^(SQL parameters of the form "?NNN" or ":AAA" or "@AAA" or "$AAA" + ** have a name which is the string "?NNN" or ":AAA" or "@AAA" or "$AAA" + ** respectively. + ** In other words, the initial ":" or "$" or "@" or "?" + ** is included as part of the name.)^ + ** ^Parameters of the form "?" without a following integer have no name + ** and are referred to as "nameless" or "anonymous parameters". + ** + ** ^The first host parameter has an index of 1, not 0. + ** + ** ^If the value N is out of range or if the N-th parameter is + ** nameless, then NULL is returned. ^The returned string is + ** always in UTF-8 encoding even if the named parameter was + ** originally specified as UTF-16 in [sqlite3_prepare16()], + ** [sqlite3_prepare16_v2()], or [sqlite3_prepare16_v3()]. + ** + ** See also: [sqlite3_bind_blob|sqlite3_bind()], + ** [sqlite3_bind_parameter_count()], and + ** [sqlite3_bind_parameter_index()]. + */ + SQLITE_API const char* sqlite3_bind_parameter_name(sqlite3_stmt*, int); + + /* + ** CAPI3REF: Index Of A Parameter With A Given Name + ** METHOD: sqlite3_stmt + ** + ** ^Return the index of an SQL parameter given its name. ^The + ** index value returned is suitable for use as the second + ** parameter to [sqlite3_bind_blob|sqlite3_bind()]. ^A zero + ** is returned if no matching parameter is found. ^The parameter + ** name must be given in UTF-8 even if the original statement + ** was prepared from UTF-16 text using [sqlite3_prepare16_v2()] or + ** [sqlite3_prepare16_v3()]. + ** + ** See also: [sqlite3_bind_blob|sqlite3_bind()], + ** [sqlite3_bind_parameter_count()], and + ** [sqlite3_bind_parameter_name()]. + */ + SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt*, const char* zName); + + /* + ** CAPI3REF: Reset All Bindings On A Prepared Statement + ** METHOD: sqlite3_stmt + ** + ** ^Contrary to the intuition of many, [sqlite3_reset()] does not reset + ** the [sqlite3_bind_blob | bindings] on a [prepared statement]. + ** ^Use this routine to reset all host parameters to NULL. + */ + SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt*); + + /* + ** CAPI3REF: Number Of Columns In A Result Set + ** METHOD: sqlite3_stmt + ** + ** ^Return the number of columns in the result set returned by the + ** [prepared statement]. ^If this routine returns 0, that means the + ** [prepared statement] returns no data (for example an [UPDATE]). + ** ^However, just because this routine returns a positive number does not + ** mean that one or more rows of data will be returned. ^A SELECT statement + ** will always have a positive sqlite3_column_count() but depending on the + ** WHERE clause constraints and the table content, it might return no rows. + ** + ** See also: [sqlite3_data_count()] + */ + SQLITE_API int sqlite3_column_count(sqlite3_stmt* pStmt); + + /* + ** CAPI3REF: Column Names In A Result Set + ** METHOD: sqlite3_stmt + ** + ** ^These routines return the name assigned to a particular column + ** in the result set of a [SELECT] statement. ^The sqlite3_column_name() + ** interface returns a pointer to a zero-terminated UTF-8 string + ** and sqlite3_column_name16() returns a pointer to a zero-terminated + ** UTF-16 string. ^The first parameter is the [prepared statement] + ** that implements the [SELECT] statement. ^The second parameter is the + ** column number. ^The leftmost column is number 0. + ** + ** ^The returned string pointer is valid until either the [prepared statement] + ** is destroyed by [sqlite3_finalize()] or until the statement is automatically + ** reprepared by the first call to [sqlite3_step()] for a particular run + ** or until the next call to + ** sqlite3_column_name() or sqlite3_column_name16() on the same column. + ** + ** ^If sqlite3_malloc() fails during the processing of either routine + ** (for example during a conversion from UTF-8 to UTF-16) then a + ** NULL pointer is returned. + ** + ** ^The name of a result column is the value of the "AS" clause for + ** that column, if there is an AS clause. If there is no AS clause + ** then the name of the column is unspecified and may change from + ** one release of SQLite to the next. + */ + SQLITE_API const char* sqlite3_column_name(sqlite3_stmt*, int N); + SQLITE_API const void* sqlite3_column_name16(sqlite3_stmt*, int N); + + /* + ** CAPI3REF: Source Of Data In A Query Result + ** METHOD: sqlite3_stmt + ** + ** ^These routines provide a means to determine the database, table, and + ** table column that is the origin of a particular result column in + ** [SELECT] statement. + ** ^The name of the database or table or column can be returned as + ** either a UTF-8 or UTF-16 string. ^The _database_ routines return + ** the database name, the _table_ routines return the table name, and + ** the origin_ routines return the column name. + ** ^The returned string is valid until the [prepared statement] is destroyed + ** using [sqlite3_finalize()] or until the statement is automatically + ** reprepared by the first call to [sqlite3_step()] for a particular run + ** or until the same information is requested + ** again in a different encoding. + ** + ** ^The names returned are the original un-aliased names of the + ** database, table, and column. + ** + ** ^The first argument to these interfaces is a [prepared statement]. + ** ^These functions return information about the Nth result column returned by + ** the statement, where N is the second function argument. + ** ^The left-most column is column 0 for these routines. + ** + ** ^If the Nth column returned by the statement is an expression or + ** subquery and is not a column value, then all of these functions return + ** NULL. ^These routines might also return NULL if a memory allocation error + ** occurs. ^Otherwise, they return the name of the attached database, table, + ** or column that query result column was extracted from. + ** + ** ^As with all other SQLite APIs, those whose names end with "16" return + ** UTF-16 encoded strings and the other functions return UTF-8. + ** + ** ^These APIs are only available if the library was compiled with the + ** [SQLITE_ENABLE_COLUMN_METADATA] C-preprocessor symbol. + ** + ** If two or more threads call one or more + ** [sqlite3_column_database_name | column metadata interfaces] + ** for the same [prepared statement] and result column + ** at the same time then the results are undefined. + */ + SQLITE_API const char* sqlite3_column_database_name(sqlite3_stmt*, int); + SQLITE_API const void* sqlite3_column_database_name16(sqlite3_stmt*, int); + SQLITE_API const char* sqlite3_column_table_name(sqlite3_stmt*, int); + SQLITE_API const void* sqlite3_column_table_name16(sqlite3_stmt*, int); + SQLITE_API const char* sqlite3_column_origin_name(sqlite3_stmt*, int); + SQLITE_API const void* sqlite3_column_origin_name16(sqlite3_stmt*, int); + + /* + ** CAPI3REF: Declared Datatype Of A Query Result + ** METHOD: sqlite3_stmt + ** + ** ^(The first parameter is a [prepared statement]. + ** If this statement is a [SELECT] statement and the Nth column of the + ** returned result set of that [SELECT] is a table column (not an + ** expression or subquery) then the declared type of the table + ** column is returned.)^ ^If the Nth column of the result set is an + ** expression or subquery, then a NULL pointer is returned. + ** ^The returned string is always UTF-8 encoded. + ** + ** ^(For example, given the database schema: + ** + ** CREATE TABLE t1(c1 VARIANT); + ** + ** and the following statement to be compiled: + ** + ** SELECT c1 + 1, c1 FROM t1; + ** + ** this routine would return the string "VARIANT" for the second result + ** column (i==1), and a NULL pointer for the first result column (i==0).)^ + ** + ** ^SQLite uses dynamic run-time typing. ^So just because a column + ** is declared to contain a particular type does not mean that the + ** data stored in that column is of the declared type. SQLite is + ** strongly typed, but the typing is dynamic not static. ^Type + ** is associated with individual values, not with the containers + ** used to hold those values. + */ + SQLITE_API const char* sqlite3_column_decltype(sqlite3_stmt*, int); + SQLITE_API const void* sqlite3_column_decltype16(sqlite3_stmt*, int); + + /* + ** CAPI3REF: Evaluate An SQL Statement + ** METHOD: sqlite3_stmt + ** + ** After a [prepared statement] has been prepared using any of + ** [sqlite3_prepare_v2()], [sqlite3_prepare_v3()], [sqlite3_prepare16_v2()], + ** or [sqlite3_prepare16_v3()] or one of the legacy + ** interfaces [sqlite3_prepare()] or [sqlite3_prepare16()], this function + ** must be called one or more times to evaluate the statement. + ** + ** The details of the behavior of the sqlite3_step() interface depend + ** on whether the statement was prepared using the newer "vX" interfaces + ** [sqlite3_prepare_v3()], [sqlite3_prepare_v2()], [sqlite3_prepare16_v3()], + ** [sqlite3_prepare16_v2()] or the older legacy + ** interfaces [sqlite3_prepare()] and [sqlite3_prepare16()]. The use of the + ** new "vX" interface is recommended for new applications but the legacy + ** interface will continue to be supported. + ** + ** ^In the legacy interface, the return value will be either [SQLITE_BUSY], + ** [SQLITE_DONE], [SQLITE_ROW], [SQLITE_ERROR], or [SQLITE_MISUSE]. + ** ^With the "v2" interface, any of the other [result codes] or + ** [extended result codes] might be returned as well. + ** + ** ^[SQLITE_BUSY] means that the database engine was unable to acquire the + ** database locks it needs to do its job. ^If the statement is a [COMMIT] + ** or occurs outside of an explicit transaction, then you can retry the + ** statement. If the statement is not a [COMMIT] and occurs within an + ** explicit transaction then you should rollback the transaction before + ** continuing. + ** + ** ^[SQLITE_DONE] means that the statement has finished executing + ** successfully. sqlite3_step() should not be called again on this virtual + ** machine without first calling [sqlite3_reset()] to reset the virtual + ** machine back to its initial state. + ** + ** ^If the SQL statement being executed returns any data, then [SQLITE_ROW] + ** is returned each time a new row of data is ready for processing by the + ** caller. The values may be accessed using the [column access functions]. + ** sqlite3_step() is called again to retrieve the next row of data. + ** + ** ^[SQLITE_ERROR] means that a run-time error (such as a constraint + ** violation) has occurred. sqlite3_step() should not be called again on + ** the VM. More information may be found by calling [sqlite3_errmsg()]. + ** ^With the legacy interface, a more specific error code (for example, + ** [SQLITE_INTERRUPT], [SQLITE_SCHEMA], [SQLITE_CORRUPT], and so forth) + ** can be obtained by calling [sqlite3_reset()] on the + ** [prepared statement]. ^In the "v2" interface, + ** the more specific error code is returned directly by sqlite3_step(). + ** + ** [SQLITE_MISUSE] means that the this routine was called inappropriately. + ** Perhaps it was called on a [prepared statement] that has + ** already been [sqlite3_finalize | finalized] or on one that had + ** previously returned [SQLITE_ERROR] or [SQLITE_DONE]. Or it could + ** be the case that the same database connection is being used by two or + ** more threads at the same moment in time. + ** + ** For all versions of SQLite up to and including 3.6.23.1, a call to + ** [sqlite3_reset()] was required after sqlite3_step() returned anything + ** other than [SQLITE_ROW] before any subsequent invocation of + ** sqlite3_step(). Failure to reset the prepared statement using + ** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from + ** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1], + ** sqlite3_step() began + ** calling [sqlite3_reset()] automatically in this circumstance rather + ** than returning [SQLITE_MISUSE]. This is not considered a compatibility + ** break because any application that ever receives an SQLITE_MISUSE error + ** is broken by definition. The [SQLITE_OMIT_AUTORESET] compile-time option + ** can be used to restore the legacy behavior. + ** + ** Goofy Interface Alert: In the legacy interface, the sqlite3_step() + ** API always returns a generic error code, [SQLITE_ERROR], following any + ** error other than [SQLITE_BUSY] and [SQLITE_MISUSE]. You must call + ** [sqlite3_reset()] or [sqlite3_finalize()] in order to find one of the + ** specific [error codes] that better describes the error. + ** We admit that this is a goofy design. The problem has been fixed + ** with the "v2" interface. If you prepare all of your SQL statements + ** using [sqlite3_prepare_v3()] or [sqlite3_prepare_v2()] + ** or [sqlite3_prepare16_v2()] or [sqlite3_prepare16_v3()] instead + ** of the legacy [sqlite3_prepare()] and [sqlite3_prepare16()] interfaces, + ** then the more specific [error codes] are returned directly + ** by sqlite3_step(). The use of the "vX" interfaces is recommended. + */ + SQLITE_API int sqlite3_step(sqlite3_stmt*); + + /* + ** CAPI3REF: Number of columns in a result set + ** METHOD: sqlite3_stmt + ** + ** ^The sqlite3_data_count(P) interface returns the number of columns in the + ** current row of the result set of [prepared statement] P. + ** ^If prepared statement P does not have results ready to return + ** (via calls to the [sqlite3_column_int | sqlite3_column()] family of + ** interfaces) then sqlite3_data_count(P) returns 0. + ** ^The sqlite3_data_count(P) routine also returns 0 if P is a NULL pointer. + ** ^The sqlite3_data_count(P) routine returns 0 if the previous call to + ** [sqlite3_step](P) returned [SQLITE_DONE]. ^The sqlite3_data_count(P) + ** will return non-zero if previous call to [sqlite3_step](P) returned + ** [SQLITE_ROW], except in the case of the [PRAGMA incremental_vacuum] + ** where it always returns zero since each step of that multi-step + ** pragma returns 0 columns of data. + ** + ** See also: [sqlite3_column_count()] + */ + SQLITE_API int sqlite3_data_count(sqlite3_stmt* pStmt); /* ** CAPI3REF: Fundamental Datatypes @@ -4869,458 +4848,450 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt); ** SQLite version 2 and SQLite version 3 should use SQLITE3_TEXT, not ** SQLITE_TEXT. */ -#define SQLITE_INTEGER 1 -#define SQLITE_FLOAT 2 -#define SQLITE_BLOB 4 -#define SQLITE_NULL 5 +#define SQLITE_INTEGER 1 +#define SQLITE_FLOAT 2 +#define SQLITE_BLOB 4 +#define SQLITE_NULL 5 #ifdef SQLITE_TEXT -# undef SQLITE_TEXT +#undef SQLITE_TEXT #else -# define SQLITE_TEXT 3 +#define SQLITE_TEXT 3 #endif -#define SQLITE3_TEXT 3 - -/* -** CAPI3REF: Result Values From A Query -** KEYWORDS: {column access functions} -** METHOD: sqlite3_stmt -** -** Summary: -**
-**
sqlite3_column_blobBLOB result -**
sqlite3_column_doubleREAL result -**
sqlite3_column_int32-bit INTEGER result -**
sqlite3_column_int6464-bit INTEGER result -**
sqlite3_column_textUTF-8 TEXT result -**
sqlite3_column_text16UTF-16 TEXT result -**
sqlite3_column_valueThe result as an -** [sqlite3_value|unprotected sqlite3_value] object. -**
    -**
sqlite3_column_bytesSize of a BLOB -** or a UTF-8 TEXT result in bytes -**
sqlite3_column_bytes16   -** →  Size of UTF-16 -** TEXT in bytes -**
sqlite3_column_typeDefault -** datatype of the result -**
-** -** Details: -** -** ^These routines return information about a single column of the current -** result row of a query. ^In every case the first argument is a pointer -** to the [prepared statement] that is being evaluated (the [sqlite3_stmt*] -** that was returned from [sqlite3_prepare_v2()] or one of its variants) -** and the second argument is the index of the column for which information -** should be returned. ^The leftmost column of the result set has the index 0. -** ^The number of columns in the result can be determined using -** [sqlite3_column_count()]. -** -** If the SQL statement does not currently point to a valid row, or if the -** column index is out of range, the result is undefined. -** These routines may only be called when the most recent call to -** [sqlite3_step()] has returned [SQLITE_ROW] and neither -** [sqlite3_reset()] nor [sqlite3_finalize()] have been called subsequently. -** If any of these routines are called after [sqlite3_reset()] or -** [sqlite3_finalize()] or after [sqlite3_step()] has returned -** something other than [SQLITE_ROW], the results are undefined. -** If [sqlite3_step()] or [sqlite3_reset()] or [sqlite3_finalize()] -** are called from a different thread while any of these routines -** are pending, then the results are undefined. -** -** The first six interfaces (_blob, _double, _int, _int64, _text, and _text16) -** each return the value of a result column in a specific data format. If -** the result column is not initially in the requested format (for example, -** if the query returns an integer but the sqlite3_column_text() interface -** is used to extract the value) then an automatic type conversion is performed. -** -** ^The sqlite3_column_type() routine returns the -** [SQLITE_INTEGER | datatype code] for the initial data type -** of the result column. ^The returned value is one of [SQLITE_INTEGER], -** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL]. -** The return value of sqlite3_column_type() can be used to decide which -** of the first six interface should be used to extract the column value. -** The value returned by sqlite3_column_type() is only meaningful if no -** automatic type conversions have occurred for the value in question. -** After a type conversion, the result of calling sqlite3_column_type() -** is undefined, though harmless. Future -** versions of SQLite may change the behavior of sqlite3_column_type() -** following a type conversion. -** -** If the result is a BLOB or a TEXT string, then the sqlite3_column_bytes() -** or sqlite3_column_bytes16() interfaces can be used to determine the size -** of that BLOB or string. -** -** ^If the result is a BLOB or UTF-8 string then the sqlite3_column_bytes() -** routine returns the number of bytes in that BLOB or string. -** ^If the result is a UTF-16 string, then sqlite3_column_bytes() converts -** the string to UTF-8 and then returns the number of bytes. -** ^If the result is a numeric value then sqlite3_column_bytes() uses -** [sqlite3_snprintf()] to convert that value to a UTF-8 string and returns -** the number of bytes in that string. -** ^If the result is NULL, then sqlite3_column_bytes() returns zero. -** -** ^If the result is a BLOB or UTF-16 string then the sqlite3_column_bytes16() -** routine returns the number of bytes in that BLOB or string. -** ^If the result is a UTF-8 string, then sqlite3_column_bytes16() converts -** the string to UTF-16 and then returns the number of bytes. -** ^If the result is a numeric value then sqlite3_column_bytes16() uses -** [sqlite3_snprintf()] to convert that value to a UTF-16 string and returns -** the number of bytes in that string. -** ^If the result is NULL, then sqlite3_column_bytes16() returns zero. -** -** ^The values returned by [sqlite3_column_bytes()] and -** [sqlite3_column_bytes16()] do not include the zero terminators at the end -** of the string. ^For clarity: the values returned by -** [sqlite3_column_bytes()] and [sqlite3_column_bytes16()] are the number of -** bytes in the string, not the number of characters. -** -** ^Strings returned by sqlite3_column_text() and sqlite3_column_text16(), -** even empty strings, are always zero-terminated. ^The return -** value from sqlite3_column_blob() for a zero-length BLOB is a NULL pointer. -** -** Warning: ^The object returned by [sqlite3_column_value()] is an -** [unprotected sqlite3_value] object. In a multithreaded environment, -** an unprotected sqlite3_value object may only be used safely with -** [sqlite3_bind_value()] and [sqlite3_result_value()]. -** If the [unprotected sqlite3_value] object returned by -** [sqlite3_column_value()] is used in any other way, including calls -** to routines like [sqlite3_value_int()], [sqlite3_value_text()], -** or [sqlite3_value_bytes()], the behavior is not threadsafe. -** Hence, the sqlite3_column_value() interface -** is normally only useful within the implementation of -** [application-defined SQL functions] or [virtual tables], not within -** top-level application code. -** -** The these routines may attempt to convert the datatype of the result. -** ^For example, if the internal representation is FLOAT and a text result -** is requested, [sqlite3_snprintf()] is used internally to perform the -** conversion automatically. ^(The following table details the conversions -** that are applied: -** -**
-** -**
Internal
Type
Requested
Type
Conversion -** -**
NULL INTEGER Result is 0 -**
NULL FLOAT Result is 0.0 -**
NULL TEXT Result is a NULL pointer -**
NULL BLOB Result is a NULL pointer -**
INTEGER FLOAT Convert from integer to float -**
INTEGER TEXT ASCII rendering of the integer -**
INTEGER BLOB Same as INTEGER->TEXT -**
FLOAT INTEGER [CAST] to INTEGER -**
FLOAT TEXT ASCII rendering of the float -**
FLOAT BLOB [CAST] to BLOB -**
TEXT INTEGER [CAST] to INTEGER -**
TEXT FLOAT [CAST] to REAL -**
TEXT BLOB No change -**
BLOB INTEGER [CAST] to INTEGER -**
BLOB FLOAT [CAST] to REAL -**
BLOB TEXT Add a zero terminator if needed -**
-**
)^ -** -** Note that when type conversions occur, pointers returned by prior -** calls to sqlite3_column_blob(), sqlite3_column_text(), and/or -** sqlite3_column_text16() may be invalidated. -** Type conversions and pointer invalidations might occur -** in the following cases: -** -**
    -**
  • The initial content is a BLOB and sqlite3_column_text() or -** sqlite3_column_text16() is called. A zero-terminator might -** need to be added to the string.
  • -**
  • The initial content is UTF-8 text and sqlite3_column_bytes16() or -** sqlite3_column_text16() is called. The content must be converted -** to UTF-16.
  • -**
  • The initial content is UTF-16 text and sqlite3_column_bytes() or -** sqlite3_column_text() is called. The content must be converted -** to UTF-8.
  • -**
-** -** ^Conversions between UTF-16be and UTF-16le are always done in place and do -** not invalidate a prior pointer, though of course the content of the buffer -** that the prior pointer references will have been modified. Other kinds -** of conversion are done in place when it is possible, but sometimes they -** are not possible and in those cases prior pointers are invalidated. -** -** The safest policy is to invoke these routines -** in one of the following ways: -** -**
    -**
  • sqlite3_column_text() followed by sqlite3_column_bytes()
  • -**
  • sqlite3_column_blob() followed by sqlite3_column_bytes()
  • -**
  • sqlite3_column_text16() followed by sqlite3_column_bytes16()
  • -**
-** -** In other words, you should call sqlite3_column_text(), -** sqlite3_column_blob(), or sqlite3_column_text16() first to force the result -** into the desired format, then invoke sqlite3_column_bytes() or -** sqlite3_column_bytes16() to find the size of the result. Do not mix calls -** to sqlite3_column_text() or sqlite3_column_blob() with calls to -** sqlite3_column_bytes16(), and do not mix calls to sqlite3_column_text16() -** with calls to sqlite3_column_bytes(). -** -** ^The pointers returned are valid until a type conversion occurs as -** described above, or until [sqlite3_step()] or [sqlite3_reset()] or -** [sqlite3_finalize()] is called. ^The memory space used to hold strings -** and BLOBs is freed automatically. Do not pass the pointers returned -** from [sqlite3_column_blob()], [sqlite3_column_text()], etc. into -** [sqlite3_free()]. -** -** As long as the input parameters are correct, these routines will only -** fail if an out-of-memory error occurs during a format conversion. -** Only the following subset of interfaces are subject to out-of-memory -** errors: -** -**
    -**
  • sqlite3_column_blob() -**
  • sqlite3_column_text() -**
  • sqlite3_column_text16() -**
  • sqlite3_column_bytes() -**
  • sqlite3_column_bytes16() -**
-** -** If an out-of-memory error occurs, then the return value from these -** routines is the same as if the column had contained an SQL NULL value. -** Valid SQL NULL returns can be distinguished from out-of-memory errors -** by invoking the [sqlite3_errcode()] immediately after the suspect -** return value is obtained and before any -** other SQLite interface is called on the same [database connection]. -*/ -SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol); -SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol); -SQLITE_API int sqlite3_column_int(sqlite3_stmt*, int iCol); -SQLITE_API sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol); -SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol); -SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt*, int iCol); -SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol); -SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol); -SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol); -SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol); - -/* -** CAPI3REF: Destroy A Prepared Statement Object -** DESTRUCTOR: sqlite3_stmt -** -** ^The sqlite3_finalize() function is called to delete a [prepared statement]. -** ^If the most recent evaluation of the statement encountered no errors -** or if the statement is never been evaluated, then sqlite3_finalize() returns -** SQLITE_OK. ^If the most recent evaluation of statement S failed, then -** sqlite3_finalize(S) returns the appropriate [error code] or -** [extended error code]. -** -** ^The sqlite3_finalize(S) routine can be called at any point during -** the life cycle of [prepared statement] S: -** before statement S is ever evaluated, after -** one or more calls to [sqlite3_reset()], or after any call -** to [sqlite3_step()] regardless of whether or not the statement has -** completed execution. -** -** ^Invoking sqlite3_finalize() on a NULL pointer is a harmless no-op. -** -** The application must finalize every [prepared statement] in order to avoid -** resource leaks. It is a grievous error for the application to try to use -** a prepared statement after it has been finalized. Any use of a prepared -** statement after it has been finalized can result in undefined and -** undesirable behavior such as segfaults and heap corruption. -*/ -SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt); - -/* -** CAPI3REF: Reset A Prepared Statement Object -** METHOD: sqlite3_stmt -** -** The sqlite3_reset() function is called to reset a [prepared statement] -** object back to its initial state, ready to be re-executed. -** ^Any SQL statement variables that had values bound to them using -** the [sqlite3_bind_blob | sqlite3_bind_*() API] retain their values. -** Use [sqlite3_clear_bindings()] to reset the bindings. -** -** ^The [sqlite3_reset(S)] interface resets the [prepared statement] S -** back to the beginning of its program. -** -** ^If the most recent call to [sqlite3_step(S)] for the -** [prepared statement] S returned [SQLITE_ROW] or [SQLITE_DONE], -** or if [sqlite3_step(S)] has never before been called on S, -** then [sqlite3_reset(S)] returns [SQLITE_OK]. -** -** ^If the most recent call to [sqlite3_step(S)] for the -** [prepared statement] S indicated an error, then -** [sqlite3_reset(S)] returns an appropriate [error code]. -** -** ^The [sqlite3_reset(S)] interface does not change the values -** of any [sqlite3_bind_blob|bindings] on the [prepared statement] S. -*/ -SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); - -/* -** CAPI3REF: Create Or Redefine SQL Functions -** KEYWORDS: {function creation routines} -** METHOD: sqlite3 -** -** ^These functions (collectively known as "function creation routines") -** are used to add SQL functions or aggregates or to redefine the behavior -** of existing SQL functions or aggregates. The only differences between -** the three "sqlite3_create_function*" routines are the text encoding -** expected for the second parameter (the name of the function being -** created) and the presence or absence of a destructor callback for -** the application data pointer. Function sqlite3_create_window_function() -** is similar, but allows the user to supply the extra callback functions -** needed by [aggregate window functions]. -** -** ^The first parameter is the [database connection] to which the SQL -** function is to be added. ^If an application uses more than one database -** connection then application-defined SQL functions must be added -** to each database connection separately. -** -** ^The second parameter is the name of the SQL function to be created or -** redefined. ^The length of the name is limited to 255 bytes in a UTF-8 -** representation, exclusive of the zero-terminator. ^Note that the name -** length limit is in UTF-8 bytes, not characters nor UTF-16 bytes. -** ^Any attempt to create a function with a longer name -** will result in [SQLITE_MISUSE] being returned. -** -** ^The third parameter (nArg) -** is the number of arguments that the SQL function or -** aggregate takes. ^If this parameter is -1, then the SQL function or -** aggregate may take any number of arguments between 0 and the limit -** set by [sqlite3_limit]([SQLITE_LIMIT_FUNCTION_ARG]). If the third -** parameter is less than -1 or greater than 127 then the behavior is -** undefined. -** -** ^The fourth parameter, eTextRep, specifies what -** [SQLITE_UTF8 | text encoding] this SQL function prefers for -** its parameters. The application should set this parameter to -** [SQLITE_UTF16LE] if the function implementation invokes -** [sqlite3_value_text16le()] on an input, or [SQLITE_UTF16BE] if the -** implementation invokes [sqlite3_value_text16be()] on an input, or -** [SQLITE_UTF16] if [sqlite3_value_text16()] is used, or [SQLITE_UTF8] -** otherwise. ^The same SQL function may be registered multiple times using -** different preferred text encodings, with different implementations for -** each encoding. -** ^When multiple implementations of the same function are available, SQLite -** will pick the one that involves the least amount of data conversion. -** -** ^The fourth parameter may optionally be ORed with [SQLITE_DETERMINISTIC] -** to signal that the function will always return the same result given -** the same inputs within a single SQL statement. Most SQL functions are -** deterministic. The built-in [random()] SQL function is an example of a -** function that is not deterministic. The SQLite query planner is able to -** perform additional optimizations on deterministic functions, so use -** of the [SQLITE_DETERMINISTIC] flag is recommended where possible. -** -** ^The fourth parameter may also optionally include the [SQLITE_DIRECTONLY] -** flag, which if present prevents the function from being invoked from -** within VIEWs, TRIGGERs, CHECK constraints, generated column expressions, -** index expressions, or the WHERE clause of partial indexes. -** -** For best security, the [SQLITE_DIRECTONLY] flag is recommended for -** all application-defined SQL functions that do not need to be -** used inside of triggers, view, CHECK constraints, or other elements of -** the database schema. This flags is especially recommended for SQL -** functions that have side effects or reveal internal application state. -** Without this flag, an attacker might be able to modify the schema of -** a database file to include invocations of the function with parameters -** chosen by the attacker, which the application will then execute when -** the database file is opened and read. -** -** ^(The fifth parameter is an arbitrary pointer. The implementation of the -** function can gain access to this pointer using [sqlite3_user_data()].)^ -** -** ^The sixth, seventh and eighth parameters passed to the three -** "sqlite3_create_function*" functions, xFunc, xStep and xFinal, are -** pointers to C-language functions that implement the SQL function or -** aggregate. ^A scalar SQL function requires an implementation of the xFunc -** callback only; NULL pointers must be passed as the xStep and xFinal -** parameters. ^An aggregate SQL function requires an implementation of xStep -** and xFinal and NULL pointer must be passed for xFunc. ^To delete an existing -** SQL function or aggregate, pass NULL pointers for all three function -** callbacks. -** -** ^The sixth, seventh, eighth and ninth parameters (xStep, xFinal, xValue -** and xInverse) passed to sqlite3_create_window_function are pointers to -** C-language callbacks that implement the new function. xStep and xFinal -** must both be non-NULL. xValue and xInverse may either both be NULL, in -** which case a regular aggregate function is created, or must both be -** non-NULL, in which case the new function may be used as either an aggregate -** or aggregate window function. More details regarding the implementation -** of aggregate window functions are -** [user-defined window functions|available here]. -** -** ^(If the final parameter to sqlite3_create_function_v2() or -** sqlite3_create_window_function() is not NULL, then it is destructor for -** the application data pointer. The destructor is invoked when the function -** is deleted, either by being overloaded or when the database connection -** closes.)^ ^The destructor is also invoked if the call to -** sqlite3_create_function_v2() fails. ^When the destructor callback is -** invoked, it is passed a single argument which is a copy of the application -** data pointer which was the fifth parameter to sqlite3_create_function_v2(). -** -** ^It is permitted to register multiple implementations of the same -** functions with the same name but with either differing numbers of -** arguments or differing preferred text encodings. ^SQLite will use -** the implementation that most closely matches the way in which the -** SQL function is used. ^A function implementation with a non-negative -** nArg parameter is a better match than a function implementation with -** a negative nArg. ^A function where the preferred text encoding -** matches the database encoding is a better -** match than a function where the encoding is different. -** ^A function where the encoding difference is between UTF16le and UTF16be -** is a closer match than a function where the encoding difference is -** between UTF8 and UTF16. -** -** ^Built-in functions may be overloaded by new application-defined functions. -** -** ^An application-defined function is permitted to call other -** SQLite interfaces. However, such calls must not -** close the database connection nor finalize or reset the prepared -** statement in which the function is running. -*/ -SQLITE_API int sqlite3_create_function( - sqlite3 *db, - const char *zFunctionName, - int nArg, - int eTextRep, - void *pApp, - void (*xFunc)(sqlite3_context*,int,sqlite3_value**), - void (*xStep)(sqlite3_context*,int,sqlite3_value**), - void (*xFinal)(sqlite3_context*) -); -SQLITE_API int sqlite3_create_function16( - sqlite3 *db, - const void *zFunctionName, - int nArg, - int eTextRep, - void *pApp, - void (*xFunc)(sqlite3_context*,int,sqlite3_value**), - void (*xStep)(sqlite3_context*,int,sqlite3_value**), - void (*xFinal)(sqlite3_context*) -); -SQLITE_API int sqlite3_create_function_v2( - sqlite3 *db, - const char *zFunctionName, - int nArg, - int eTextRep, - void *pApp, - void (*xFunc)(sqlite3_context*,int,sqlite3_value**), - void (*xStep)(sqlite3_context*,int,sqlite3_value**), - void (*xFinal)(sqlite3_context*), - void(*xDestroy)(void*) -); -SQLITE_API int sqlite3_create_window_function( - sqlite3 *db, - const char *zFunctionName, - int nArg, - int eTextRep, - void *pApp, - void (*xStep)(sqlite3_context*,int,sqlite3_value**), - void (*xFinal)(sqlite3_context*), - void (*xValue)(sqlite3_context*), - void (*xInverse)(sqlite3_context*,int,sqlite3_value**), - void(*xDestroy)(void*) -); +#define SQLITE3_TEXT 3 + + /* + ** CAPI3REF: Result Values From A Query + ** KEYWORDS: {column access functions} + ** METHOD: sqlite3_stmt + ** + ** Summary: + **
+ **
sqlite3_column_blobBLOB result + **
sqlite3_column_doubleREAL result + **
sqlite3_column_int32-bit INTEGER result + **
sqlite3_column_int6464-bit INTEGER result + **
sqlite3_column_textUTF-8 TEXT result + **
sqlite3_column_text16UTF-16 TEXT result + **
sqlite3_column_valueThe result as an + ** [sqlite3_value|unprotected sqlite3_value] object. + **
    + **
sqlite3_column_bytesSize of a BLOB + ** or a UTF-8 TEXT result in bytes + **
sqlite3_column_bytes16   + ** →  Size of UTF-16 + ** TEXT in bytes + **
sqlite3_column_typeDefault + ** datatype of the result + **
+ ** + ** Details: + ** + ** ^These routines return information about a single column of the current + ** result row of a query. ^In every case the first argument is a pointer + ** to the [prepared statement] that is being evaluated (the [sqlite3_stmt*] + ** that was returned from [sqlite3_prepare_v2()] or one of its variants) + ** and the second argument is the index of the column for which information + ** should be returned. ^The leftmost column of the result set has the index 0. + ** ^The number of columns in the result can be determined using + ** [sqlite3_column_count()]. + ** + ** If the SQL statement does not currently point to a valid row, or if the + ** column index is out of range, the result is undefined. + ** These routines may only be called when the most recent call to + ** [sqlite3_step()] has returned [SQLITE_ROW] and neither + ** [sqlite3_reset()] nor [sqlite3_finalize()] have been called subsequently. + ** If any of these routines are called after [sqlite3_reset()] or + ** [sqlite3_finalize()] or after [sqlite3_step()] has returned + ** something other than [SQLITE_ROW], the results are undefined. + ** If [sqlite3_step()] or [sqlite3_reset()] or [sqlite3_finalize()] + ** are called from a different thread while any of these routines + ** are pending, then the results are undefined. + ** + ** The first six interfaces (_blob, _double, _int, _int64, _text, and _text16) + ** each return the value of a result column in a specific data format. If + ** the result column is not initially in the requested format (for example, + ** if the query returns an integer but the sqlite3_column_text() interface + ** is used to extract the value) then an automatic type conversion is performed. + ** + ** ^The sqlite3_column_type() routine returns the + ** [SQLITE_INTEGER | datatype code] for the initial data type + ** of the result column. ^The returned value is one of [SQLITE_INTEGER], + ** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL]. + ** The return value of sqlite3_column_type() can be used to decide which + ** of the first six interface should be used to extract the column value. + ** The value returned by sqlite3_column_type() is only meaningful if no + ** automatic type conversions have occurred for the value in question. + ** After a type conversion, the result of calling sqlite3_column_type() + ** is undefined, though harmless. Future + ** versions of SQLite may change the behavior of sqlite3_column_type() + ** following a type conversion. + ** + ** If the result is a BLOB or a TEXT string, then the sqlite3_column_bytes() + ** or sqlite3_column_bytes16() interfaces can be used to determine the size + ** of that BLOB or string. + ** + ** ^If the result is a BLOB or UTF-8 string then the sqlite3_column_bytes() + ** routine returns the number of bytes in that BLOB or string. + ** ^If the result is a UTF-16 string, then sqlite3_column_bytes() converts + ** the string to UTF-8 and then returns the number of bytes. + ** ^If the result is a numeric value then sqlite3_column_bytes() uses + ** [sqlite3_snprintf()] to convert that value to a UTF-8 string and returns + ** the number of bytes in that string. + ** ^If the result is NULL, then sqlite3_column_bytes() returns zero. + ** + ** ^If the result is a BLOB or UTF-16 string then the sqlite3_column_bytes16() + ** routine returns the number of bytes in that BLOB or string. + ** ^If the result is a UTF-8 string, then sqlite3_column_bytes16() converts + ** the string to UTF-16 and then returns the number of bytes. + ** ^If the result is a numeric value then sqlite3_column_bytes16() uses + ** [sqlite3_snprintf()] to convert that value to a UTF-16 string and returns + ** the number of bytes in that string. + ** ^If the result is NULL, then sqlite3_column_bytes16() returns zero. + ** + ** ^The values returned by [sqlite3_column_bytes()] and + ** [sqlite3_column_bytes16()] do not include the zero terminators at the end + ** of the string. ^For clarity: the values returned by + ** [sqlite3_column_bytes()] and [sqlite3_column_bytes16()] are the number of + ** bytes in the string, not the number of characters. + ** + ** ^Strings returned by sqlite3_column_text() and sqlite3_column_text16(), + ** even empty strings, are always zero-terminated. ^The return + ** value from sqlite3_column_blob() for a zero-length BLOB is a NULL pointer. + ** + ** Warning: ^The object returned by [sqlite3_column_value()] is an + ** [unprotected sqlite3_value] object. In a multithreaded environment, + ** an unprotected sqlite3_value object may only be used safely with + ** [sqlite3_bind_value()] and [sqlite3_result_value()]. + ** If the [unprotected sqlite3_value] object returned by + ** [sqlite3_column_value()] is used in any other way, including calls + ** to routines like [sqlite3_value_int()], [sqlite3_value_text()], + ** or [sqlite3_value_bytes()], the behavior is not threadsafe. + ** Hence, the sqlite3_column_value() interface + ** is normally only useful within the implementation of + ** [application-defined SQL functions] or [virtual tables], not within + ** top-level application code. + ** + ** The these routines may attempt to convert the datatype of the result. + ** ^For example, if the internal representation is FLOAT and a text result + ** is requested, [sqlite3_snprintf()] is used internally to perform the + ** conversion automatically. ^(The following table details the conversions + ** that are applied: + ** + **
+ ** + **
Internal
Type
Requested
Type
Conversion + ** + **
NULL INTEGER Result is 0 + **
NULL FLOAT Result is 0.0 + **
NULL TEXT Result is a NULL pointer + **
NULL BLOB Result is a NULL pointer + **
INTEGER FLOAT Convert from integer to float + **
INTEGER TEXT ASCII rendering of the integer + **
INTEGER BLOB Same as INTEGER->TEXT + **
FLOAT INTEGER [CAST] to INTEGER + **
FLOAT TEXT ASCII rendering of the float + **
FLOAT BLOB [CAST] to BLOB + **
TEXT INTEGER [CAST] to INTEGER + **
TEXT FLOAT [CAST] to REAL + **
TEXT BLOB No change + **
BLOB INTEGER [CAST] to INTEGER + **
BLOB FLOAT [CAST] to REAL + **
BLOB TEXT Add a zero terminator if needed + **
+ **
)^ + ** + ** Note that when type conversions occur, pointers returned by prior + ** calls to sqlite3_column_blob(), sqlite3_column_text(), and/or + ** sqlite3_column_text16() may be invalidated. + ** Type conversions and pointer invalidations might occur + ** in the following cases: + ** + **
    + **
  • The initial content is a BLOB and sqlite3_column_text() or + ** sqlite3_column_text16() is called. A zero-terminator might + ** need to be added to the string.
  • + **
  • The initial content is UTF-8 text and sqlite3_column_bytes16() or + ** sqlite3_column_text16() is called. The content must be converted + ** to UTF-16.
  • + **
  • The initial content is UTF-16 text and sqlite3_column_bytes() or + ** sqlite3_column_text() is called. The content must be converted + ** to UTF-8.
  • + **
+ ** + ** ^Conversions between UTF-16be and UTF-16le are always done in place and do + ** not invalidate a prior pointer, though of course the content of the buffer + ** that the prior pointer references will have been modified. Other kinds + ** of conversion are done in place when it is possible, but sometimes they + ** are not possible and in those cases prior pointers are invalidated. + ** + ** The safest policy is to invoke these routines + ** in one of the following ways: + ** + **
    + **
  • sqlite3_column_text() followed by sqlite3_column_bytes()
  • + **
  • sqlite3_column_blob() followed by sqlite3_column_bytes()
  • + **
  • sqlite3_column_text16() followed by sqlite3_column_bytes16()
  • + **
+ ** + ** In other words, you should call sqlite3_column_text(), + ** sqlite3_column_blob(), or sqlite3_column_text16() first to force the result + ** into the desired format, then invoke sqlite3_column_bytes() or + ** sqlite3_column_bytes16() to find the size of the result. Do not mix calls + ** to sqlite3_column_text() or sqlite3_column_blob() with calls to + ** sqlite3_column_bytes16(), and do not mix calls to sqlite3_column_text16() + ** with calls to sqlite3_column_bytes(). + ** + ** ^The pointers returned are valid until a type conversion occurs as + ** described above, or until [sqlite3_step()] or [sqlite3_reset()] or + ** [sqlite3_finalize()] is called. ^The memory space used to hold strings + ** and BLOBs is freed automatically. Do not pass the pointers returned + ** from [sqlite3_column_blob()], [sqlite3_column_text()], etc. into + ** [sqlite3_free()]. + ** + ** As long as the input parameters are correct, these routines will only + ** fail if an out-of-memory error occurs during a format conversion. + ** Only the following subset of interfaces are subject to out-of-memory + ** errors: + ** + **
    + **
  • sqlite3_column_blob() + **
  • sqlite3_column_text() + **
  • sqlite3_column_text16() + **
  • sqlite3_column_bytes() + **
  • sqlite3_column_bytes16() + **
+ ** + ** If an out-of-memory error occurs, then the return value from these + ** routines is the same as if the column had contained an SQL NULL value. + ** Valid SQL NULL returns can be distinguished from out-of-memory errors + ** by invoking the [sqlite3_errcode()] immediately after the suspect + ** return value is obtained and before any + ** other SQLite interface is called on the same [database connection]. + */ + SQLITE_API const void* sqlite3_column_blob(sqlite3_stmt*, int iCol); + SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol); + SQLITE_API int sqlite3_column_int(sqlite3_stmt*, int iCol); + SQLITE_API sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol); + SQLITE_API const unsigned char* sqlite3_column_text(sqlite3_stmt*, int iCol); + SQLITE_API const void* sqlite3_column_text16(sqlite3_stmt*, int iCol); + SQLITE_API sqlite3_value* sqlite3_column_value(sqlite3_stmt*, int iCol); + SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol); + SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol); + SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol); + + /* + ** CAPI3REF: Destroy A Prepared Statement Object + ** DESTRUCTOR: sqlite3_stmt + ** + ** ^The sqlite3_finalize() function is called to delete a [prepared statement]. + ** ^If the most recent evaluation of the statement encountered no errors + ** or if the statement is never been evaluated, then sqlite3_finalize() returns + ** SQLITE_OK. ^If the most recent evaluation of statement S failed, then + ** sqlite3_finalize(S) returns the appropriate [error code] or + ** [extended error code]. + ** + ** ^The sqlite3_finalize(S) routine can be called at any point during + ** the life cycle of [prepared statement] S: + ** before statement S is ever evaluated, after + ** one or more calls to [sqlite3_reset()], or after any call + ** to [sqlite3_step()] regardless of whether or not the statement has + ** completed execution. + ** + ** ^Invoking sqlite3_finalize() on a NULL pointer is a harmless no-op. + ** + ** The application must finalize every [prepared statement] in order to avoid + ** resource leaks. It is a grievous error for the application to try to use + ** a prepared statement after it has been finalized. Any use of a prepared + ** statement after it has been finalized can result in undefined and + ** undesirable behavior such as segfaults and heap corruption. + */ + SQLITE_API int sqlite3_finalize(sqlite3_stmt* pStmt); + + /* + ** CAPI3REF: Reset A Prepared Statement Object + ** METHOD: sqlite3_stmt + ** + ** The sqlite3_reset() function is called to reset a [prepared statement] + ** object back to its initial state, ready to be re-executed. + ** ^Any SQL statement variables that had values bound to them using + ** the [sqlite3_bind_blob | sqlite3_bind_*() API] retain their values. + ** Use [sqlite3_clear_bindings()] to reset the bindings. + ** + ** ^The [sqlite3_reset(S)] interface resets the [prepared statement] S + ** back to the beginning of its program. + ** + ** ^If the most recent call to [sqlite3_step(S)] for the + ** [prepared statement] S returned [SQLITE_ROW] or [SQLITE_DONE], + ** or if [sqlite3_step(S)] has never before been called on S, + ** then [sqlite3_reset(S)] returns [SQLITE_OK]. + ** + ** ^If the most recent call to [sqlite3_step(S)] for the + ** [prepared statement] S indicated an error, then + ** [sqlite3_reset(S)] returns an appropriate [error code]. + ** + ** ^The [sqlite3_reset(S)] interface does not change the values + ** of any [sqlite3_bind_blob|bindings] on the [prepared statement] S. + */ + SQLITE_API int sqlite3_reset(sqlite3_stmt* pStmt); + + /* + ** CAPI3REF: Create Or Redefine SQL Functions + ** KEYWORDS: {function creation routines} + ** METHOD: sqlite3 + ** + ** ^These functions (collectively known as "function creation routines") + ** are used to add SQL functions or aggregates or to redefine the behavior + ** of existing SQL functions or aggregates. The only differences between + ** the three "sqlite3_create_function*" routines are the text encoding + ** expected for the second parameter (the name of the function being + ** created) and the presence or absence of a destructor callback for + ** the application data pointer. Function sqlite3_create_window_function() + ** is similar, but allows the user to supply the extra callback functions + ** needed by [aggregate window functions]. + ** + ** ^The first parameter is the [database connection] to which the SQL + ** function is to be added. ^If an application uses more than one database + ** connection then application-defined SQL functions must be added + ** to each database connection separately. + ** + ** ^The second parameter is the name of the SQL function to be created or + ** redefined. ^The length of the name is limited to 255 bytes in a UTF-8 + ** representation, exclusive of the zero-terminator. ^Note that the name + ** length limit is in UTF-8 bytes, not characters nor UTF-16 bytes. + ** ^Any attempt to create a function with a longer name + ** will result in [SQLITE_MISUSE] being returned. + ** + ** ^The third parameter (nArg) + ** is the number of arguments that the SQL function or + ** aggregate takes. ^If this parameter is -1, then the SQL function or + ** aggregate may take any number of arguments between 0 and the limit + ** set by [sqlite3_limit]([SQLITE_LIMIT_FUNCTION_ARG]). If the third + ** parameter is less than -1 or greater than 127 then the behavior is + ** undefined. + ** + ** ^The fourth parameter, eTextRep, specifies what + ** [SQLITE_UTF8 | text encoding] this SQL function prefers for + ** its parameters. The application should set this parameter to + ** [SQLITE_UTF16LE] if the function implementation invokes + ** [sqlite3_value_text16le()] on an input, or [SQLITE_UTF16BE] if the + ** implementation invokes [sqlite3_value_text16be()] on an input, or + ** [SQLITE_UTF16] if [sqlite3_value_text16()] is used, or [SQLITE_UTF8] + ** otherwise. ^The same SQL function may be registered multiple times using + ** different preferred text encodings, with different implementations for + ** each encoding. + ** ^When multiple implementations of the same function are available, SQLite + ** will pick the one that involves the least amount of data conversion. + ** + ** ^The fourth parameter may optionally be ORed with [SQLITE_DETERMINISTIC] + ** to signal that the function will always return the same result given + ** the same inputs within a single SQL statement. Most SQL functions are + ** deterministic. The built-in [random()] SQL function is an example of a + ** function that is not deterministic. The SQLite query planner is able to + ** perform additional optimizations on deterministic functions, so use + ** of the [SQLITE_DETERMINISTIC] flag is recommended where possible. + ** + ** ^The fourth parameter may also optionally include the [SQLITE_DIRECTONLY] + ** flag, which if present prevents the function from being invoked from + ** within VIEWs, TRIGGERs, CHECK constraints, generated column expressions, + ** index expressions, or the WHERE clause of partial indexes. + ** + ** For best security, the [SQLITE_DIRECTONLY] flag is recommended for + ** all application-defined SQL functions that do not need to be + ** used inside of triggers, view, CHECK constraints, or other elements of + ** the database schema. This flags is especially recommended for SQL + ** functions that have side effects or reveal internal application state. + ** Without this flag, an attacker might be able to modify the schema of + ** a database file to include invocations of the function with parameters + ** chosen by the attacker, which the application will then execute when + ** the database file is opened and read. + ** + ** ^(The fifth parameter is an arbitrary pointer. The implementation of the + ** function can gain access to this pointer using [sqlite3_user_data()].)^ + ** + ** ^The sixth, seventh and eighth parameters passed to the three + ** "sqlite3_create_function*" functions, xFunc, xStep and xFinal, are + ** pointers to C-language functions that implement the SQL function or + ** aggregate. ^A scalar SQL function requires an implementation of the xFunc + ** callback only; NULL pointers must be passed as the xStep and xFinal + ** parameters. ^An aggregate SQL function requires an implementation of xStep + ** and xFinal and NULL pointer must be passed for xFunc. ^To delete an existing + ** SQL function or aggregate, pass NULL pointers for all three function + ** callbacks. + ** + ** ^The sixth, seventh, eighth and ninth parameters (xStep, xFinal, xValue + ** and xInverse) passed to sqlite3_create_window_function are pointers to + ** C-language callbacks that implement the new function. xStep and xFinal + ** must both be non-NULL. xValue and xInverse may either both be NULL, in + ** which case a regular aggregate function is created, or must both be + ** non-NULL, in which case the new function may be used as either an aggregate + ** or aggregate window function. More details regarding the implementation + ** of aggregate window functions are + ** [user-defined window functions|available here]. + ** + ** ^(If the final parameter to sqlite3_create_function_v2() or + ** sqlite3_create_window_function() is not NULL, then it is destructor for + ** the application data pointer. The destructor is invoked when the function + ** is deleted, either by being overloaded or when the database connection + ** closes.)^ ^The destructor is also invoked if the call to + ** sqlite3_create_function_v2() fails. ^When the destructor callback is + ** invoked, it is passed a single argument which is a copy of the application + ** data pointer which was the fifth parameter to sqlite3_create_function_v2(). + ** + ** ^It is permitted to register multiple implementations of the same + ** functions with the same name but with either differing numbers of + ** arguments or differing preferred text encodings. ^SQLite will use + ** the implementation that most closely matches the way in which the + ** SQL function is used. ^A function implementation with a non-negative + ** nArg parameter is a better match than a function implementation with + ** a negative nArg. ^A function where the preferred text encoding + ** matches the database encoding is a better + ** match than a function where the encoding is different. + ** ^A function where the encoding difference is between UTF16le and UTF16be + ** is a closer match than a function where the encoding difference is + ** between UTF8 and UTF16. + ** + ** ^Built-in functions may be overloaded by new application-defined functions. + ** + ** ^An application-defined function is permitted to call other + ** SQLite interfaces. However, such calls must not + ** close the database connection nor finalize or reset the prepared + ** statement in which the function is running. + */ + SQLITE_API int sqlite3_create_function(sqlite3* db, + const char* zFunctionName, + int nArg, + int eTextRep, + void* pApp, + void (*xFunc)(sqlite3_context*, int, sqlite3_value**), + void (*xStep)(sqlite3_context*, int, sqlite3_value**), + void (*xFinal)(sqlite3_context*)); + SQLITE_API int sqlite3_create_function16(sqlite3* db, + const void* zFunctionName, + int nArg, + int eTextRep, + void* pApp, + void (*xFunc)(sqlite3_context*, int, sqlite3_value**), + void (*xStep)(sqlite3_context*, int, sqlite3_value**), + void (*xFinal)(sqlite3_context*)); + SQLITE_API int sqlite3_create_function_v2(sqlite3* db, + const char* zFunctionName, + int nArg, + int eTextRep, + void* pApp, + void (*xFunc)(sqlite3_context*, int, sqlite3_value**), + void (*xStep)(sqlite3_context*, int, sqlite3_value**), + void (*xFinal)(sqlite3_context*), + void (*xDestroy)(void*)); + SQLITE_API int sqlite3_create_window_function(sqlite3* db, + const char* zFunctionName, + int nArg, + int eTextRep, + void* pApp, + void (*xStep)(sqlite3_context*, int, sqlite3_value**), + void (*xFinal)(sqlite3_context*), + void (*xValue)(sqlite3_context*), + void (*xInverse)(sqlite3_context*, int, sqlite3_value**), + void (*xDestroy)(void*)); /* ** CAPI3REF: Text Encodings @@ -5328,12 +5299,12 @@ SQLITE_API int sqlite3_create_window_function( ** These constant define integer codes that represent the various ** text encodings supported by SQLite. */ -#define SQLITE_UTF8 1 /* IMP: R-37514-35566 */ -#define SQLITE_UTF16LE 2 /* IMP: R-03371-37637 */ -#define SQLITE_UTF16BE 3 /* IMP: R-51971-34154 */ -#define SQLITE_UTF16 4 /* Use native byte order */ -#define SQLITE_ANY 5 /* Deprecated */ -#define SQLITE_UTF16_ALIGNED 8 /* sqlite3_create_collation only */ +#define SQLITE_UTF8 1 /* IMP: R-37514-35566 */ +#define SQLITE_UTF16LE 2 /* IMP: R-03371-37637 */ +#define SQLITE_UTF16BE 3 /* IMP: R-51971-34154 */ +#define SQLITE_UTF16 4 /* Use native byte order */ +#define SQLITE_ANY 5 /* Deprecated */ +#define SQLITE_UTF16_ALIGNED 8 /* sqlite3_create_collation only */ /* ** CAPI3REF: Function Flags @@ -5400,10 +5371,10 @@ SQLITE_API int sqlite3_create_window_function( ** ** */ -#define SQLITE_DETERMINISTIC 0x000000800 -#define SQLITE_DIRECTONLY 0x000080000 -#define SQLITE_SUBTYPE 0x000100000 -#define SQLITE_INNOCUOUS 0x000200000 +#define SQLITE_DETERMINISTIC 0x000000800 +#define SQLITE_DIRECTONLY 0x000080000 +#define SQLITE_SUBTYPE 0x000100000 +#define SQLITE_INNOCUOUS 0x000200000 /* ** CAPI3REF: Deprecated Functions @@ -5416,814 +5387,794 @@ SQLITE_API int sqlite3_create_window_function( ** these functions, we will not explain what they do. */ #ifndef SQLITE_OMIT_DEPRECATED -SQLITE_API SQLITE_DEPRECATED int sqlite3_aggregate_count(sqlite3_context*); -SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*); -SQLITE_API SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*); -SQLITE_API SQLITE_DEPRECATED int sqlite3_global_recover(void); -SQLITE_API SQLITE_DEPRECATED void sqlite3_thread_cleanup(void); -SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int), - void*,sqlite3_int64); + SQLITE_API SQLITE_DEPRECATED int sqlite3_aggregate_count(sqlite3_context*); + SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*); + SQLITE_API SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*); + SQLITE_API SQLITE_DEPRECATED int sqlite3_global_recover(void); + SQLITE_API SQLITE_DEPRECATED void sqlite3_thread_cleanup(void); + SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void (*)(void*, sqlite3_int64, int), void*, sqlite3_int64); #endif -/* -** CAPI3REF: Obtaining SQL Values -** METHOD: sqlite3_value -** -** Summary: -**
-**
sqlite3_value_blobBLOB value -**
sqlite3_value_doubleREAL value -**
sqlite3_value_int32-bit INTEGER value -**
sqlite3_value_int6464-bit INTEGER value -**
sqlite3_value_pointerPointer value -**
sqlite3_value_textUTF-8 TEXT value -**
sqlite3_value_text16UTF-16 TEXT value in -** the native byteorder -**
sqlite3_value_text16beUTF-16be TEXT value -**
sqlite3_value_text16leUTF-16le TEXT value -**
    -**
sqlite3_value_bytesSize of a BLOB -** or a UTF-8 TEXT in bytes -**
sqlite3_value_bytes16   -** →  Size of UTF-16 -** TEXT in bytes -**
sqlite3_value_typeDefault -** datatype of the value -**
sqlite3_value_numeric_type   -** →  Best numeric datatype of the value -**
sqlite3_value_nochange   -** →  True if the column is unchanged in an UPDATE -** against a virtual table. -**
sqlite3_value_frombind   -** →  True if value originated from a [bound parameter] -**
-** -** Details: -** -** These routines extract type, size, and content information from -** [protected sqlite3_value] objects. Protected sqlite3_value objects -** are used to pass parameter information into the functions that -** implement [application-defined SQL functions] and [virtual tables]. -** -** These routines work only with [protected sqlite3_value] objects. -** Any attempt to use these routines on an [unprotected sqlite3_value] -** is not threadsafe. -** -** ^These routines work just like the corresponding [column access functions] -** except that these routines take a single [protected sqlite3_value] object -** pointer instead of a [sqlite3_stmt*] pointer and an integer column number. -** -** ^The sqlite3_value_text16() interface extracts a UTF-16 string -** in the native byte-order of the host machine. ^The -** sqlite3_value_text16be() and sqlite3_value_text16le() interfaces -** extract UTF-16 strings as big-endian and little-endian respectively. -** -** ^If [sqlite3_value] object V was initialized -** using [sqlite3_bind_pointer(S,I,P,X,D)] or [sqlite3_result_pointer(C,P,X,D)] -** and if X and Y are strings that compare equal according to strcmp(X,Y), -** then sqlite3_value_pointer(V,Y) will return the pointer P. ^Otherwise, -** sqlite3_value_pointer(V,Y) returns a NULL. The sqlite3_bind_pointer() -** routine is part of the [pointer passing interface] added for SQLite 3.20.0. -** -** ^(The sqlite3_value_type(V) interface returns the -** [SQLITE_INTEGER | datatype code] for the initial datatype of the -** [sqlite3_value] object V. The returned value is one of [SQLITE_INTEGER], -** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL].)^ -** Other interfaces might change the datatype for an sqlite3_value object. -** For example, if the datatype is initially SQLITE_INTEGER and -** sqlite3_value_text(V) is called to extract a text value for that -** integer, then subsequent calls to sqlite3_value_type(V) might return -** SQLITE_TEXT. Whether or not a persistent internal datatype conversion -** occurs is undefined and may change from one release of SQLite to the next. -** -** ^(The sqlite3_value_numeric_type() interface attempts to apply -** numeric affinity to the value. This means that an attempt is -** made to convert the value to an integer or floating point. If -** such a conversion is possible without loss of information (in other -** words, if the value is a string that looks like a number) -** then the conversion is performed. Otherwise no conversion occurs. -** The [SQLITE_INTEGER | datatype] after conversion is returned.)^ -** -** ^Within the [xUpdate] method of a [virtual table], the -** sqlite3_value_nochange(X) interface returns true if and only if -** the column corresponding to X is unchanged by the UPDATE operation -** that the xUpdate method call was invoked to implement and if -** and the prior [xColumn] method call that was invoked to extracted -** the value for that column returned without setting a result (probably -** because it queried [sqlite3_vtab_nochange()] and found that the column -** was unchanging). ^Within an [xUpdate] method, any value for which -** sqlite3_value_nochange(X) is true will in all other respects appear -** to be a NULL value. If sqlite3_value_nochange(X) is invoked anywhere other -** than within an [xUpdate] method call for an UPDATE statement, then -** the return value is arbitrary and meaningless. -** -** ^The sqlite3_value_frombind(X) interface returns non-zero if the -** value X originated from one of the [sqlite3_bind_int|sqlite3_bind()] -** interfaces. ^If X comes from an SQL literal value, or a table column, -** or an expression, then sqlite3_value_frombind(X) returns zero. -** -** Please pay particular attention to the fact that the pointer returned -** from [sqlite3_value_blob()], [sqlite3_value_text()], or -** [sqlite3_value_text16()] can be invalidated by a subsequent call to -** [sqlite3_value_bytes()], [sqlite3_value_bytes16()], [sqlite3_value_text()], -** or [sqlite3_value_text16()]. -** -** These routines must be called from the same thread as -** the SQL function that supplied the [sqlite3_value*] parameters. -** -** As long as the input parameter is correct, these routines can only -** fail if an out-of-memory error occurs during a format conversion. -** Only the following subset of interfaces are subject to out-of-memory -** errors: -** -**
    -**
  • sqlite3_value_blob() -**
  • sqlite3_value_text() -**
  • sqlite3_value_text16() -**
  • sqlite3_value_text16le() -**
  • sqlite3_value_text16be() -**
  • sqlite3_value_bytes() -**
  • sqlite3_value_bytes16() -**
-** -** If an out-of-memory error occurs, then the return value from these -** routines is the same as if the column had contained an SQL NULL value. -** Valid SQL NULL returns can be distinguished from out-of-memory errors -** by invoking the [sqlite3_errcode()] immediately after the suspect -** return value is obtained and before any -** other SQLite interface is called on the same [database connection]. -*/ -SQLITE_API const void *sqlite3_value_blob(sqlite3_value*); -SQLITE_API double sqlite3_value_double(sqlite3_value*); -SQLITE_API int sqlite3_value_int(sqlite3_value*); -SQLITE_API sqlite3_int64 sqlite3_value_int64(sqlite3_value*); -SQLITE_API void *sqlite3_value_pointer(sqlite3_value*, const char*); -SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value*); -SQLITE_API const void *sqlite3_value_text16(sqlite3_value*); -SQLITE_API const void *sqlite3_value_text16le(sqlite3_value*); -SQLITE_API const void *sqlite3_value_text16be(sqlite3_value*); -SQLITE_API int sqlite3_value_bytes(sqlite3_value*); -SQLITE_API int sqlite3_value_bytes16(sqlite3_value*); -SQLITE_API int sqlite3_value_type(sqlite3_value*); -SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*); -SQLITE_API int sqlite3_value_nochange(sqlite3_value*); -SQLITE_API int sqlite3_value_frombind(sqlite3_value*); - -/* -** CAPI3REF: Finding The Subtype Of SQL Values -** METHOD: sqlite3_value -** -** The sqlite3_value_subtype(V) function returns the subtype for -** an [application-defined SQL function] argument V. The subtype -** information can be used to pass a limited amount of context from -** one SQL function to another. Use the [sqlite3_result_subtype()] -** routine to set the subtype for the return value of an SQL function. -*/ -SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*); - -/* -** CAPI3REF: Copy And Free SQL Values -** METHOD: sqlite3_value -** -** ^The sqlite3_value_dup(V) interface makes a copy of the [sqlite3_value] -** object D and returns a pointer to that copy. ^The [sqlite3_value] returned -** is a [protected sqlite3_value] object even if the input is not. -** ^The sqlite3_value_dup(V) interface returns NULL if V is NULL or if a -** memory allocation fails. -** -** ^The sqlite3_value_free(V) interface frees an [sqlite3_value] object -** previously obtained from [sqlite3_value_dup()]. ^If V is a NULL pointer -** then sqlite3_value_free(V) is a harmless no-op. -*/ -SQLITE_API sqlite3_value *sqlite3_value_dup(const sqlite3_value*); -SQLITE_API void sqlite3_value_free(sqlite3_value*); - -/* -** CAPI3REF: Obtain Aggregate Function Context -** METHOD: sqlite3_context -** -** Implementations of aggregate SQL functions use this -** routine to allocate memory for storing their state. -** -** ^The first time the sqlite3_aggregate_context(C,N) routine is called -** for a particular aggregate function, SQLite allocates -** N bytes of memory, zeroes out that memory, and returns a pointer -** to the new memory. ^On second and subsequent calls to -** sqlite3_aggregate_context() for the same aggregate function instance, -** the same buffer is returned. Sqlite3_aggregate_context() is normally -** called once for each invocation of the xStep callback and then one -** last time when the xFinal callback is invoked. ^(When no rows match -** an aggregate query, the xStep() callback of the aggregate function -** implementation is never called and xFinal() is called exactly once. -** In those cases, sqlite3_aggregate_context() might be called for the -** first time from within xFinal().)^ -** -** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer -** when first called if N is less than or equal to zero or if a memory -** allocate error occurs. -** -** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is -** determined by the N parameter on first successful call. Changing the -** value of N in any subsequent call to sqlite3_aggregate_context() within -** the same aggregate function instance will not resize the memory -** allocation.)^ Within the xFinal callback, it is customary to set -** N=0 in calls to sqlite3_aggregate_context(C,N) so that no -** pointless memory allocations occur. -** -** ^SQLite automatically frees the memory allocated by -** sqlite3_aggregate_context() when the aggregate query concludes. -** -** The first parameter must be a copy of the -** [sqlite3_context | SQL function context] that is the first parameter -** to the xStep or xFinal callback routine that implements the aggregate -** function. -** -** This routine must be called from the same thread in which -** the aggregate SQL function is running. -*/ -SQLITE_API void *sqlite3_aggregate_context(sqlite3_context*, int nBytes); - -/* -** CAPI3REF: User Data For Functions -** METHOD: sqlite3_context -** -** ^The sqlite3_user_data() interface returns a copy of -** the pointer that was the pUserData parameter (the 5th parameter) -** of the [sqlite3_create_function()] -** and [sqlite3_create_function16()] routines that originally -** registered the application defined function. -** -** This routine must be called from the same thread in which -** the application-defined function is running. -*/ -SQLITE_API void *sqlite3_user_data(sqlite3_context*); - -/* -** CAPI3REF: Database Connection For Functions -** METHOD: sqlite3_context -** -** ^The sqlite3_context_db_handle() interface returns a copy of -** the pointer to the [database connection] (the 1st parameter) -** of the [sqlite3_create_function()] -** and [sqlite3_create_function16()] routines that originally -** registered the application defined function. -*/ -SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*); - -/* -** CAPI3REF: Function Auxiliary Data -** METHOD: sqlite3_context -** -** These functions may be used by (non-aggregate) SQL functions to -** associate metadata with argument values. If the same value is passed to -** multiple invocations of the same SQL function during query execution, under -** some circumstances the associated metadata may be preserved. An example -** of where this might be useful is in a regular-expression matching -** function. The compiled version of the regular expression can be stored as -** metadata associated with the pattern string. -** Then as long as the pattern string remains the same, -** the compiled regular expression can be reused on multiple -** invocations of the same function. -** -** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the metadata -** associated by the sqlite3_set_auxdata(C,N,P,X) function with the Nth argument -** value to the application-defined function. ^N is zero for the left-most -** function argument. ^If there is no metadata -** associated with the function argument, the sqlite3_get_auxdata(C,N) interface -** returns a NULL pointer. -** -** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th -** argument of the application-defined function. ^Subsequent -** calls to sqlite3_get_auxdata(C,N) return P from the most recent -** sqlite3_set_auxdata(C,N,P,X) call if the metadata is still valid or -** NULL if the metadata has been discarded. -** ^After each call to sqlite3_set_auxdata(C,N,P,X) where X is not NULL, -** SQLite will invoke the destructor function X with parameter P exactly -** once, when the metadata is discarded. -** SQLite is free to discard the metadata at any time, including:
    -**
  • ^(when the corresponding function parameter changes)^, or -**
  • ^(when [sqlite3_reset()] or [sqlite3_finalize()] is called for the -** SQL statement)^, or -**
  • ^(when sqlite3_set_auxdata() is invoked again on the same -** parameter)^, or -**
  • ^(during the original sqlite3_set_auxdata() call when a memory -** allocation error occurs.)^
-** -** Note the last bullet in particular. The destructor X in -** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the -** sqlite3_set_auxdata() interface even returns. Hence sqlite3_set_auxdata() -** should be called near the end of the function implementation and the -** function implementation should not make any use of P after -** sqlite3_set_auxdata() has been called. -** -** ^(In practice, metadata is preserved between function calls for -** function parameters that are compile-time constants, including literal -** values and [parameters] and expressions composed from the same.)^ -** -** The value of the N parameter to these interfaces should be non-negative. -** Future enhancements may make use of negative N values to define new -** kinds of function caching behavior. -** -** These routines must be called from the same thread in which -** the SQL function is running. -*/ -SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int N); -SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*)); - - -/* -** CAPI3REF: Constants Defining Special Destructor Behavior -** -** These are special values for the destructor that is passed in as the -** final argument to routines like [sqlite3_result_blob()]. ^If the destructor -** argument is SQLITE_STATIC, it means that the content pointer is constant -** and will never change. It does not need to be destroyed. ^The -** SQLITE_TRANSIENT value means that the content will likely change in -** the near future and that SQLite should make its own private copy of -** the content before returning. -** -** The typedef is necessary to work around problems in certain -** C++ compilers. -*/ -typedef void (*sqlite3_destructor_type)(void*); -#define SQLITE_STATIC ((sqlite3_destructor_type)0) -#define SQLITE_TRANSIENT ((sqlite3_destructor_type)-1) - -/* -** CAPI3REF: Setting The Result Of An SQL Function -** METHOD: sqlite3_context -** -** These routines are used by the xFunc or xFinal callbacks that -** implement SQL functions and aggregates. See -** [sqlite3_create_function()] and [sqlite3_create_function16()] -** for additional information. -** -** These functions work very much like the [parameter binding] family of -** functions used to bind values to host parameters in prepared statements. -** Refer to the [SQL parameter] documentation for additional information. -** -** ^The sqlite3_result_blob() interface sets the result from -** an application-defined function to be the BLOB whose content is pointed -** to by the second parameter and which is N bytes long where N is the -** third parameter. -** -** ^The sqlite3_result_zeroblob(C,N) and sqlite3_result_zeroblob64(C,N) -** interfaces set the result of the application-defined function to be -** a BLOB containing all zero bytes and N bytes in size. -** -** ^The sqlite3_result_double() interface sets the result from -** an application-defined function to be a floating point value specified -** by its 2nd argument. -** -** ^The sqlite3_result_error() and sqlite3_result_error16() functions -** cause the implemented SQL function to throw an exception. -** ^SQLite uses the string pointed to by the -** 2nd parameter of sqlite3_result_error() or sqlite3_result_error16() -** as the text of an error message. ^SQLite interprets the error -** message string from sqlite3_result_error() as UTF-8. ^SQLite -** interprets the string from sqlite3_result_error16() as UTF-16 using -** the same [byte-order determination rules] as [sqlite3_bind_text16()]. -** ^If the third parameter to sqlite3_result_error() -** or sqlite3_result_error16() is negative then SQLite takes as the error -** message all text up through the first zero character. -** ^If the third parameter to sqlite3_result_error() or -** sqlite3_result_error16() is non-negative then SQLite takes that many -** bytes (not characters) from the 2nd parameter as the error message. -** ^The sqlite3_result_error() and sqlite3_result_error16() -** routines make a private copy of the error message text before -** they return. Hence, the calling function can deallocate or -** modify the text after they return without harm. -** ^The sqlite3_result_error_code() function changes the error code -** returned by SQLite as a result of an error in a function. ^By default, -** the error code is SQLITE_ERROR. ^A subsequent call to sqlite3_result_error() -** or sqlite3_result_error16() resets the error code to SQLITE_ERROR. -** -** ^The sqlite3_result_error_toobig() interface causes SQLite to throw an -** error indicating that a string or BLOB is too long to represent. -** -** ^The sqlite3_result_error_nomem() interface causes SQLite to throw an -** error indicating that a memory allocation failed. -** -** ^The sqlite3_result_int() interface sets the return value -** of the application-defined function to be the 32-bit signed integer -** value given in the 2nd argument. -** ^The sqlite3_result_int64() interface sets the return value -** of the application-defined function to be the 64-bit signed integer -** value given in the 2nd argument. -** -** ^The sqlite3_result_null() interface sets the return value -** of the application-defined function to be NULL. -** -** ^The sqlite3_result_text(), sqlite3_result_text16(), -** sqlite3_result_text16le(), and sqlite3_result_text16be() interfaces -** set the return value of the application-defined function to be -** a text string which is represented as UTF-8, UTF-16 native byte order, -** UTF-16 little endian, or UTF-16 big endian, respectively. -** ^The sqlite3_result_text64() interface sets the return value of an -** application-defined function to be a text string in an encoding -** specified by the fifth (and last) parameter, which must be one -** of [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE]. -** ^SQLite takes the text result from the application from -** the 2nd parameter of the sqlite3_result_text* interfaces. -** ^If the 3rd parameter to the sqlite3_result_text* interfaces -** is negative, then SQLite takes result text from the 2nd parameter -** through the first zero character. -** ^If the 3rd parameter to the sqlite3_result_text* interfaces -** is non-negative, then as many bytes (not characters) of the text -** pointed to by the 2nd parameter are taken as the application-defined -** function result. If the 3rd parameter is non-negative, then it -** must be the byte offset into the string where the NUL terminator would -** appear if the string where NUL terminated. If any NUL characters occur -** in the string at a byte offset that is less than the value of the 3rd -** parameter, then the resulting string will contain embedded NULs and the -** result of expressions operating on strings with embedded NULs is undefined. -** ^If the 4th parameter to the sqlite3_result_text* interfaces -** or sqlite3_result_blob is a non-NULL pointer, then SQLite calls that -** function as the destructor on the text or BLOB result when it has -** finished using that result. -** ^If the 4th parameter to the sqlite3_result_text* interfaces or to -** sqlite3_result_blob is the special constant SQLITE_STATIC, then SQLite -** assumes that the text or BLOB result is in constant space and does not -** copy the content of the parameter nor call a destructor on the content -** when it has finished using that result. -** ^If the 4th parameter to the sqlite3_result_text* interfaces -** or sqlite3_result_blob is the special constant SQLITE_TRANSIENT -** then SQLite makes a copy of the result into space obtained -** from [sqlite3_malloc()] before it returns. -** -** ^For the sqlite3_result_text16(), sqlite3_result_text16le(), and -** sqlite3_result_text16be() routines, and for sqlite3_result_text64() -** when the encoding is not UTF8, if the input UTF16 begins with a -** byte-order mark (BOM, U+FEFF) then the BOM is removed from the -** string and the rest of the string is interpreted according to the -** byte-order specified by the BOM. ^The byte-order specified by -** the BOM at the beginning of the text overrides the byte-order -** specified by the interface procedure. ^So, for example, if -** sqlite3_result_text16le() is invoked with text that begins -** with bytes 0xfe, 0xff (a big-endian byte-order mark) then the -** first two bytes of input are skipped and the remaining input -** is interpreted as UTF16BE text. -** -** ^For UTF16 input text to the sqlite3_result_text16(), -** sqlite3_result_text16be(), sqlite3_result_text16le(), and -** sqlite3_result_text64() routines, if the text contains invalid -** UTF16 characters, the invalid characters might be converted -** into the unicode replacement character, U+FFFD. -** -** ^The sqlite3_result_value() interface sets the result of -** the application-defined function to be a copy of the -** [unprotected sqlite3_value] object specified by the 2nd parameter. ^The -** sqlite3_result_value() interface makes a copy of the [sqlite3_value] -** so that the [sqlite3_value] specified in the parameter may change or -** be deallocated after sqlite3_result_value() returns without harm. -** ^A [protected sqlite3_value] object may always be used where an -** [unprotected sqlite3_value] object is required, so either -** kind of [sqlite3_value] object can be used with this interface. -** -** ^The sqlite3_result_pointer(C,P,T,D) interface sets the result to an -** SQL NULL value, just like [sqlite3_result_null(C)], except that it -** also associates the host-language pointer P or type T with that -** NULL value such that the pointer can be retrieved within an -** [application-defined SQL function] using [sqlite3_value_pointer()]. -** ^If the D parameter is not NULL, then it is a pointer to a destructor -** for the P parameter. ^SQLite invokes D with P as its only argument -** when SQLite is finished with P. The T parameter should be a static -** string and preferably a string literal. The sqlite3_result_pointer() -** routine is part of the [pointer passing interface] added for SQLite 3.20.0. -** -** If these routines are called from within the different thread -** than the one containing the application-defined function that received -** the [sqlite3_context] pointer, the results are undefined. -*/ -SQLITE_API void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*)); -SQLITE_API void sqlite3_result_blob64(sqlite3_context*,const void*, - sqlite3_uint64,void(*)(void*)); -SQLITE_API void sqlite3_result_double(sqlite3_context*, double); -SQLITE_API void sqlite3_result_error(sqlite3_context*, const char*, int); -SQLITE_API void sqlite3_result_error16(sqlite3_context*, const void*, int); -SQLITE_API void sqlite3_result_error_toobig(sqlite3_context*); -SQLITE_API void sqlite3_result_error_nomem(sqlite3_context*); -SQLITE_API void sqlite3_result_error_code(sqlite3_context*, int); -SQLITE_API void sqlite3_result_int(sqlite3_context*, int); -SQLITE_API void sqlite3_result_int64(sqlite3_context*, sqlite3_int64); -SQLITE_API void sqlite3_result_null(sqlite3_context*); -SQLITE_API void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*)); -SQLITE_API void sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64, - void(*)(void*), unsigned char encoding); -SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*)); -SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*)); -SQLITE_API void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*)); -SQLITE_API void sqlite3_result_value(sqlite3_context*, sqlite3_value*); -SQLITE_API void sqlite3_result_pointer(sqlite3_context*, void*,const char*,void(*)(void*)); -SQLITE_API void sqlite3_result_zeroblob(sqlite3_context*, int n); -SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n); - - -/* -** CAPI3REF: Setting The Subtype Of An SQL Function -** METHOD: sqlite3_context -** -** The sqlite3_result_subtype(C,T) function causes the subtype of -** the result from the [application-defined SQL function] with -** [sqlite3_context] C to be the value T. Only the lower 8 bits -** of the subtype T are preserved in current versions of SQLite; -** higher order bits are discarded. -** The number of subtype bytes preserved by SQLite might increase -** in future releases of SQLite. -*/ -SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int); - -/* -** CAPI3REF: Define New Collating Sequences -** METHOD: sqlite3 -** -** ^These functions add, remove, or modify a [collation] associated -** with the [database connection] specified as the first argument. -** -** ^The name of the collation is a UTF-8 string -** for sqlite3_create_collation() and sqlite3_create_collation_v2() -** and a UTF-16 string in native byte order for sqlite3_create_collation16(). -** ^Collation names that compare equal according to [sqlite3_strnicmp()] are -** considered to be the same name. -** -** ^(The third argument (eTextRep) must be one of the constants: -**
    -**
  • [SQLITE_UTF8], -**
  • [SQLITE_UTF16LE], -**
  • [SQLITE_UTF16BE], -**
  • [SQLITE_UTF16], or -**
  • [SQLITE_UTF16_ALIGNED]. -**
)^ -** ^The eTextRep argument determines the encoding of strings passed -** to the collating function callback, xCompare. -** ^The [SQLITE_UTF16] and [SQLITE_UTF16_ALIGNED] values for eTextRep -** force strings to be UTF16 with native byte order. -** ^The [SQLITE_UTF16_ALIGNED] value for eTextRep forces strings to begin -** on an even byte address. -** -** ^The fourth argument, pArg, is an application data pointer that is passed -** through as the first argument to the collating function callback. -** -** ^The fifth argument, xCompare, is a pointer to the collating function. -** ^Multiple collating functions can be registered using the same name but -** with different eTextRep parameters and SQLite will use whichever -** function requires the least amount of data transformation. -** ^If the xCompare argument is NULL then the collating function is -** deleted. ^When all collating functions having the same name are deleted, -** that collation is no longer usable. -** -** ^The collating function callback is invoked with a copy of the pArg -** application data pointer and with two strings in the encoding specified -** by the eTextRep argument. The two integer parameters to the collating -** function callback are the length of the two strings, in bytes. The collating -** function must return an integer that is negative, zero, or positive -** if the first string is less than, equal to, or greater than the second, -** respectively. A collating function must always return the same answer -** given the same inputs. If two or more collating functions are registered -** to the same collation name (using different eTextRep values) then all -** must give an equivalent answer when invoked with equivalent strings. -** The collating function must obey the following properties for all -** strings A, B, and C: -** -**
    -**
  1. If A==B then B==A. -**
  2. If A==B and B==C then A==C. -**
  3. If A<B THEN B>A. -**
  4. If A<B and B<C then A<C. -**
-** -** If a collating function fails any of the above constraints and that -** collating function is registered and used, then the behavior of SQLite -** is undefined. -** -** ^The sqlite3_create_collation_v2() works like sqlite3_create_collation() -** with the addition that the xDestroy callback is invoked on pArg when -** the collating function is deleted. -** ^Collating functions are deleted when they are overridden by later -** calls to the collation creation functions or when the -** [database connection] is closed using [sqlite3_close()]. -** -** ^The xDestroy callback is not called if the -** sqlite3_create_collation_v2() function fails. Applications that invoke -** sqlite3_create_collation_v2() with a non-NULL xDestroy argument should -** check the return code and dispose of the application data pointer -** themselves rather than expecting SQLite to deal with it for them. -** This is different from every other SQLite interface. The inconsistency -** is unfortunate but cannot be changed without breaking backwards -** compatibility. -** -** See also: [sqlite3_collation_needed()] and [sqlite3_collation_needed16()]. -*/ -SQLITE_API int sqlite3_create_collation( - sqlite3*, - const char *zName, - int eTextRep, - void *pArg, - int(*xCompare)(void*,int,const void*,int,const void*) -); -SQLITE_API int sqlite3_create_collation_v2( - sqlite3*, - const char *zName, - int eTextRep, - void *pArg, - int(*xCompare)(void*,int,const void*,int,const void*), - void(*xDestroy)(void*) -); -SQLITE_API int sqlite3_create_collation16( - sqlite3*, - const void *zName, - int eTextRep, - void *pArg, - int(*xCompare)(void*,int,const void*,int,const void*) -); - -/* -** CAPI3REF: Collation Needed Callbacks -** METHOD: sqlite3 -** -** ^To avoid having to register all collation sequences before a database -** can be used, a single callback function may be registered with the -** [database connection] to be invoked whenever an undefined collation -** sequence is required. -** -** ^If the function is registered using the sqlite3_collation_needed() API, -** then it is passed the names of undefined collation sequences as strings -** encoded in UTF-8. ^If sqlite3_collation_needed16() is used, -** the names are passed as UTF-16 in machine native byte order. -** ^A call to either function replaces the existing collation-needed callback. -** -** ^(When the callback is invoked, the first argument passed is a copy -** of the second argument to sqlite3_collation_needed() or -** sqlite3_collation_needed16(). The second argument is the database -** connection. The third argument is one of [SQLITE_UTF8], [SQLITE_UTF16BE], -** or [SQLITE_UTF16LE], indicating the most desirable form of the collation -** sequence function required. The fourth parameter is the name of the -** required collation sequence.)^ -** -** The callback function should register the desired collation using -** [sqlite3_create_collation()], [sqlite3_create_collation16()], or -** [sqlite3_create_collation_v2()]. -*/ -SQLITE_API int sqlite3_collation_needed( - sqlite3*, - void*, - void(*)(void*,sqlite3*,int eTextRep,const char*) -); -SQLITE_API int sqlite3_collation_needed16( - sqlite3*, - void*, - void(*)(void*,sqlite3*,int eTextRep,const void*) -); + /* + ** CAPI3REF: Obtaining SQL Values + ** METHOD: sqlite3_value + ** + ** Summary: + **
+ **
sqlite3_value_blobBLOB value + **
sqlite3_value_doubleREAL value + **
sqlite3_value_int32-bit INTEGER value + **
sqlite3_value_int6464-bit INTEGER value + **
sqlite3_value_pointerPointer value + **
sqlite3_value_textUTF-8 TEXT value + **
sqlite3_value_text16UTF-16 TEXT value in + ** the native byteorder + **
sqlite3_value_text16beUTF-16be TEXT value + **
sqlite3_value_text16leUTF-16le TEXT value + **
    + **
sqlite3_value_bytesSize of a BLOB + ** or a UTF-8 TEXT in bytes + **
sqlite3_value_bytes16   + ** →  Size of UTF-16 + ** TEXT in bytes + **
sqlite3_value_typeDefault + ** datatype of the value + **
sqlite3_value_numeric_type   + ** →  Best numeric datatype of the value + **
sqlite3_value_nochange   + ** →  True if the column is unchanged in an UPDATE + ** against a virtual table. + **
sqlite3_value_frombind   + ** →  True if value originated from a [bound parameter] + **
+ ** + ** Details: + ** + ** These routines extract type, size, and content information from + ** [protected sqlite3_value] objects. Protected sqlite3_value objects + ** are used to pass parameter information into the functions that + ** implement [application-defined SQL functions] and [virtual tables]. + ** + ** These routines work only with [protected sqlite3_value] objects. + ** Any attempt to use these routines on an [unprotected sqlite3_value] + ** is not threadsafe. + ** + ** ^These routines work just like the corresponding [column access functions] + ** except that these routines take a single [protected sqlite3_value] object + ** pointer instead of a [sqlite3_stmt*] pointer and an integer column number. + ** + ** ^The sqlite3_value_text16() interface extracts a UTF-16 string + ** in the native byte-order of the host machine. ^The + ** sqlite3_value_text16be() and sqlite3_value_text16le() interfaces + ** extract UTF-16 strings as big-endian and little-endian respectively. + ** + ** ^If [sqlite3_value] object V was initialized + ** using [sqlite3_bind_pointer(S,I,P,X,D)] or [sqlite3_result_pointer(C,P,X,D)] + ** and if X and Y are strings that compare equal according to strcmp(X,Y), + ** then sqlite3_value_pointer(V,Y) will return the pointer P. ^Otherwise, + ** sqlite3_value_pointer(V,Y) returns a NULL. The sqlite3_bind_pointer() + ** routine is part of the [pointer passing interface] added for SQLite 3.20.0. + ** + ** ^(The sqlite3_value_type(V) interface returns the + ** [SQLITE_INTEGER | datatype code] for the initial datatype of the + ** [sqlite3_value] object V. The returned value is one of [SQLITE_INTEGER], + ** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL].)^ + ** Other interfaces might change the datatype for an sqlite3_value object. + ** For example, if the datatype is initially SQLITE_INTEGER and + ** sqlite3_value_text(V) is called to extract a text value for that + ** integer, then subsequent calls to sqlite3_value_type(V) might return + ** SQLITE_TEXT. Whether or not a persistent internal datatype conversion + ** occurs is undefined and may change from one release of SQLite to the next. + ** + ** ^(The sqlite3_value_numeric_type() interface attempts to apply + ** numeric affinity to the value. This means that an attempt is + ** made to convert the value to an integer or floating point. If + ** such a conversion is possible without loss of information (in other + ** words, if the value is a string that looks like a number) + ** then the conversion is performed. Otherwise no conversion occurs. + ** The [SQLITE_INTEGER | datatype] after conversion is returned.)^ + ** + ** ^Within the [xUpdate] method of a [virtual table], the + ** sqlite3_value_nochange(X) interface returns true if and only if + ** the column corresponding to X is unchanged by the UPDATE operation + ** that the xUpdate method call was invoked to implement and if + ** and the prior [xColumn] method call that was invoked to extracted + ** the value for that column returned without setting a result (probably + ** because it queried [sqlite3_vtab_nochange()] and found that the column + ** was unchanging). ^Within an [xUpdate] method, any value for which + ** sqlite3_value_nochange(X) is true will in all other respects appear + ** to be a NULL value. If sqlite3_value_nochange(X) is invoked anywhere other + ** than within an [xUpdate] method call for an UPDATE statement, then + ** the return value is arbitrary and meaningless. + ** + ** ^The sqlite3_value_frombind(X) interface returns non-zero if the + ** value X originated from one of the [sqlite3_bind_int|sqlite3_bind()] + ** interfaces. ^If X comes from an SQL literal value, or a table column, + ** or an expression, then sqlite3_value_frombind(X) returns zero. + ** + ** Please pay particular attention to the fact that the pointer returned + ** from [sqlite3_value_blob()], [sqlite3_value_text()], or + ** [sqlite3_value_text16()] can be invalidated by a subsequent call to + ** [sqlite3_value_bytes()], [sqlite3_value_bytes16()], [sqlite3_value_text()], + ** or [sqlite3_value_text16()]. + ** + ** These routines must be called from the same thread as + ** the SQL function that supplied the [sqlite3_value*] parameters. + ** + ** As long as the input parameter is correct, these routines can only + ** fail if an out-of-memory error occurs during a format conversion. + ** Only the following subset of interfaces are subject to out-of-memory + ** errors: + ** + **
    + **
  • sqlite3_value_blob() + **
  • sqlite3_value_text() + **
  • sqlite3_value_text16() + **
  • sqlite3_value_text16le() + **
  • sqlite3_value_text16be() + **
  • sqlite3_value_bytes() + **
  • sqlite3_value_bytes16() + **
+ ** + ** If an out-of-memory error occurs, then the return value from these + ** routines is the same as if the column had contained an SQL NULL value. + ** Valid SQL NULL returns can be distinguished from out-of-memory errors + ** by invoking the [sqlite3_errcode()] immediately after the suspect + ** return value is obtained and before any + ** other SQLite interface is called on the same [database connection]. + */ + SQLITE_API const void* sqlite3_value_blob(sqlite3_value*); + SQLITE_API double sqlite3_value_double(sqlite3_value*); + SQLITE_API int sqlite3_value_int(sqlite3_value*); + SQLITE_API sqlite3_int64 sqlite3_value_int64(sqlite3_value*); + SQLITE_API void* sqlite3_value_pointer(sqlite3_value*, const char*); + SQLITE_API const unsigned char* sqlite3_value_text(sqlite3_value*); + SQLITE_API const void* sqlite3_value_text16(sqlite3_value*); + SQLITE_API const void* sqlite3_value_text16le(sqlite3_value*); + SQLITE_API const void* sqlite3_value_text16be(sqlite3_value*); + SQLITE_API int sqlite3_value_bytes(sqlite3_value*); + SQLITE_API int sqlite3_value_bytes16(sqlite3_value*); + SQLITE_API int sqlite3_value_type(sqlite3_value*); + SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*); + SQLITE_API int sqlite3_value_nochange(sqlite3_value*); + SQLITE_API int sqlite3_value_frombind(sqlite3_value*); + + /* + ** CAPI3REF: Finding The Subtype Of SQL Values + ** METHOD: sqlite3_value + ** + ** The sqlite3_value_subtype(V) function returns the subtype for + ** an [application-defined SQL function] argument V. The subtype + ** information can be used to pass a limited amount of context from + ** one SQL function to another. Use the [sqlite3_result_subtype()] + ** routine to set the subtype for the return value of an SQL function. + */ + SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*); + + /* + ** CAPI3REF: Copy And Free SQL Values + ** METHOD: sqlite3_value + ** + ** ^The sqlite3_value_dup(V) interface makes a copy of the [sqlite3_value] + ** object D and returns a pointer to that copy. ^The [sqlite3_value] returned + ** is a [protected sqlite3_value] object even if the input is not. + ** ^The sqlite3_value_dup(V) interface returns NULL if V is NULL or if a + ** memory allocation fails. + ** + ** ^The sqlite3_value_free(V) interface frees an [sqlite3_value] object + ** previously obtained from [sqlite3_value_dup()]. ^If V is a NULL pointer + ** then sqlite3_value_free(V) is a harmless no-op. + */ + SQLITE_API sqlite3_value* sqlite3_value_dup(const sqlite3_value*); + SQLITE_API void sqlite3_value_free(sqlite3_value*); + + /* + ** CAPI3REF: Obtain Aggregate Function Context + ** METHOD: sqlite3_context + ** + ** Implementations of aggregate SQL functions use this + ** routine to allocate memory for storing their state. + ** + ** ^The first time the sqlite3_aggregate_context(C,N) routine is called + ** for a particular aggregate function, SQLite allocates + ** N bytes of memory, zeroes out that memory, and returns a pointer + ** to the new memory. ^On second and subsequent calls to + ** sqlite3_aggregate_context() for the same aggregate function instance, + ** the same buffer is returned. Sqlite3_aggregate_context() is normally + ** called once for each invocation of the xStep callback and then one + ** last time when the xFinal callback is invoked. ^(When no rows match + ** an aggregate query, the xStep() callback of the aggregate function + ** implementation is never called and xFinal() is called exactly once. + ** In those cases, sqlite3_aggregate_context() might be called for the + ** first time from within xFinal().)^ + ** + ** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer + ** when first called if N is less than or equal to zero or if a memory + ** allocate error occurs. + ** + ** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is + ** determined by the N parameter on first successful call. Changing the + ** value of N in any subsequent call to sqlite3_aggregate_context() within + ** the same aggregate function instance will not resize the memory + ** allocation.)^ Within the xFinal callback, it is customary to set + ** N=0 in calls to sqlite3_aggregate_context(C,N) so that no + ** pointless memory allocations occur. + ** + ** ^SQLite automatically frees the memory allocated by + ** sqlite3_aggregate_context() when the aggregate query concludes. + ** + ** The first parameter must be a copy of the + ** [sqlite3_context | SQL function context] that is the first parameter + ** to the xStep or xFinal callback routine that implements the aggregate + ** function. + ** + ** This routine must be called from the same thread in which + ** the aggregate SQL function is running. + */ + SQLITE_API void* sqlite3_aggregate_context(sqlite3_context*, int nBytes); + + /* + ** CAPI3REF: User Data For Functions + ** METHOD: sqlite3_context + ** + ** ^The sqlite3_user_data() interface returns a copy of + ** the pointer that was the pUserData parameter (the 5th parameter) + ** of the [sqlite3_create_function()] + ** and [sqlite3_create_function16()] routines that originally + ** registered the application defined function. + ** + ** This routine must be called from the same thread in which + ** the application-defined function is running. + */ + SQLITE_API void* sqlite3_user_data(sqlite3_context*); + + /* + ** CAPI3REF: Database Connection For Functions + ** METHOD: sqlite3_context + ** + ** ^The sqlite3_context_db_handle() interface returns a copy of + ** the pointer to the [database connection] (the 1st parameter) + ** of the [sqlite3_create_function()] + ** and [sqlite3_create_function16()] routines that originally + ** registered the application defined function. + */ + SQLITE_API sqlite3* sqlite3_context_db_handle(sqlite3_context*); + + /* + ** CAPI3REF: Function Auxiliary Data + ** METHOD: sqlite3_context + ** + ** These functions may be used by (non-aggregate) SQL functions to + ** associate metadata with argument values. If the same value is passed to + ** multiple invocations of the same SQL function during query execution, under + ** some circumstances the associated metadata may be preserved. An example + ** of where this might be useful is in a regular-expression matching + ** function. The compiled version of the regular expression can be stored as + ** metadata associated with the pattern string. + ** Then as long as the pattern string remains the same, + ** the compiled regular expression can be reused on multiple + ** invocations of the same function. + ** + ** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the metadata + ** associated by the sqlite3_set_auxdata(C,N,P,X) function with the Nth argument + ** value to the application-defined function. ^N is zero for the left-most + ** function argument. ^If there is no metadata + ** associated with the function argument, the sqlite3_get_auxdata(C,N) interface + ** returns a NULL pointer. + ** + ** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th + ** argument of the application-defined function. ^Subsequent + ** calls to sqlite3_get_auxdata(C,N) return P from the most recent + ** sqlite3_set_auxdata(C,N,P,X) call if the metadata is still valid or + ** NULL if the metadata has been discarded. + ** ^After each call to sqlite3_set_auxdata(C,N,P,X) where X is not NULL, + ** SQLite will invoke the destructor function X with parameter P exactly + ** once, when the metadata is discarded. + ** SQLite is free to discard the metadata at any time, including:
    + **
  • ^(when the corresponding function parameter changes)^, or + **
  • ^(when [sqlite3_reset()] or [sqlite3_finalize()] is called for the + ** SQL statement)^, or + **
  • ^(when sqlite3_set_auxdata() is invoked again on the same + ** parameter)^, or + **
  • ^(during the original sqlite3_set_auxdata() call when a memory + ** allocation error occurs.)^
+ ** + ** Note the last bullet in particular. The destructor X in + ** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the + ** sqlite3_set_auxdata() interface even returns. Hence sqlite3_set_auxdata() + ** should be called near the end of the function implementation and the + ** function implementation should not make any use of P after + ** sqlite3_set_auxdata() has been called. + ** + ** ^(In practice, metadata is preserved between function calls for + ** function parameters that are compile-time constants, including literal + ** values and [parameters] and expressions composed from the same.)^ + ** + ** The value of the N parameter to these interfaces should be non-negative. + ** Future enhancements may make use of negative N values to define new + ** kinds of function caching behavior. + ** + ** These routines must be called from the same thread in which + ** the SQL function is running. + */ + SQLITE_API void* sqlite3_get_auxdata(sqlite3_context*, int N); + SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*)); + + /* + ** CAPI3REF: Constants Defining Special Destructor Behavior + ** + ** These are special values for the destructor that is passed in as the + ** final argument to routines like [sqlite3_result_blob()]. ^If the destructor + ** argument is SQLITE_STATIC, it means that the content pointer is constant + ** and will never change. It does not need to be destroyed. ^The + ** SQLITE_TRANSIENT value means that the content will likely change in + ** the near future and that SQLite should make its own private copy of + ** the content before returning. + ** + ** The typedef is necessary to work around problems in certain + ** C++ compilers. + */ + typedef void (*sqlite3_destructor_type)(void*); +#define SQLITE_STATIC ((sqlite3_destructor_type)0) +#define SQLITE_TRANSIENT ((sqlite3_destructor_type)-1) + + /* + ** CAPI3REF: Setting The Result Of An SQL Function + ** METHOD: sqlite3_context + ** + ** These routines are used by the xFunc or xFinal callbacks that + ** implement SQL functions and aggregates. See + ** [sqlite3_create_function()] and [sqlite3_create_function16()] + ** for additional information. + ** + ** These functions work very much like the [parameter binding] family of + ** functions used to bind values to host parameters in prepared statements. + ** Refer to the [SQL parameter] documentation for additional information. + ** + ** ^The sqlite3_result_blob() interface sets the result from + ** an application-defined function to be the BLOB whose content is pointed + ** to by the second parameter and which is N bytes long where N is the + ** third parameter. + ** + ** ^The sqlite3_result_zeroblob(C,N) and sqlite3_result_zeroblob64(C,N) + ** interfaces set the result of the application-defined function to be + ** a BLOB containing all zero bytes and N bytes in size. + ** + ** ^The sqlite3_result_double() interface sets the result from + ** an application-defined function to be a floating point value specified + ** by its 2nd argument. + ** + ** ^The sqlite3_result_error() and sqlite3_result_error16() functions + ** cause the implemented SQL function to throw an exception. + ** ^SQLite uses the string pointed to by the + ** 2nd parameter of sqlite3_result_error() or sqlite3_result_error16() + ** as the text of an error message. ^SQLite interprets the error + ** message string from sqlite3_result_error() as UTF-8. ^SQLite + ** interprets the string from sqlite3_result_error16() as UTF-16 using + ** the same [byte-order determination rules] as [sqlite3_bind_text16()]. + ** ^If the third parameter to sqlite3_result_error() + ** or sqlite3_result_error16() is negative then SQLite takes as the error + ** message all text up through the first zero character. + ** ^If the third parameter to sqlite3_result_error() or + ** sqlite3_result_error16() is non-negative then SQLite takes that many + ** bytes (not characters) from the 2nd parameter as the error message. + ** ^The sqlite3_result_error() and sqlite3_result_error16() + ** routines make a private copy of the error message text before + ** they return. Hence, the calling function can deallocate or + ** modify the text after they return without harm. + ** ^The sqlite3_result_error_code() function changes the error code + ** returned by SQLite as a result of an error in a function. ^By default, + ** the error code is SQLITE_ERROR. ^A subsequent call to sqlite3_result_error() + ** or sqlite3_result_error16() resets the error code to SQLITE_ERROR. + ** + ** ^The sqlite3_result_error_toobig() interface causes SQLite to throw an + ** error indicating that a string or BLOB is too long to represent. + ** + ** ^The sqlite3_result_error_nomem() interface causes SQLite to throw an + ** error indicating that a memory allocation failed. + ** + ** ^The sqlite3_result_int() interface sets the return value + ** of the application-defined function to be the 32-bit signed integer + ** value given in the 2nd argument. + ** ^The sqlite3_result_int64() interface sets the return value + ** of the application-defined function to be the 64-bit signed integer + ** value given in the 2nd argument. + ** + ** ^The sqlite3_result_null() interface sets the return value + ** of the application-defined function to be NULL. + ** + ** ^The sqlite3_result_text(), sqlite3_result_text16(), + ** sqlite3_result_text16le(), and sqlite3_result_text16be() interfaces + ** set the return value of the application-defined function to be + ** a text string which is represented as UTF-8, UTF-16 native byte order, + ** UTF-16 little endian, or UTF-16 big endian, respectively. + ** ^The sqlite3_result_text64() interface sets the return value of an + ** application-defined function to be a text string in an encoding + ** specified by the fifth (and last) parameter, which must be one + ** of [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE]. + ** ^SQLite takes the text result from the application from + ** the 2nd parameter of the sqlite3_result_text* interfaces. + ** ^If the 3rd parameter to the sqlite3_result_text* interfaces + ** is negative, then SQLite takes result text from the 2nd parameter + ** through the first zero character. + ** ^If the 3rd parameter to the sqlite3_result_text* interfaces + ** is non-negative, then as many bytes (not characters) of the text + ** pointed to by the 2nd parameter are taken as the application-defined + ** function result. If the 3rd parameter is non-negative, then it + ** must be the byte offset into the string where the NUL terminator would + ** appear if the string where NUL terminated. If any NUL characters occur + ** in the string at a byte offset that is less than the value of the 3rd + ** parameter, then the resulting string will contain embedded NULs and the + ** result of expressions operating on strings with embedded NULs is undefined. + ** ^If the 4th parameter to the sqlite3_result_text* interfaces + ** or sqlite3_result_blob is a non-NULL pointer, then SQLite calls that + ** function as the destructor on the text or BLOB result when it has + ** finished using that result. + ** ^If the 4th parameter to the sqlite3_result_text* interfaces or to + ** sqlite3_result_blob is the special constant SQLITE_STATIC, then SQLite + ** assumes that the text or BLOB result is in constant space and does not + ** copy the content of the parameter nor call a destructor on the content + ** when it has finished using that result. + ** ^If the 4th parameter to the sqlite3_result_text* interfaces + ** or sqlite3_result_blob is the special constant SQLITE_TRANSIENT + ** then SQLite makes a copy of the result into space obtained + ** from [sqlite3_malloc()] before it returns. + ** + ** ^For the sqlite3_result_text16(), sqlite3_result_text16le(), and + ** sqlite3_result_text16be() routines, and for sqlite3_result_text64() + ** when the encoding is not UTF8, if the input UTF16 begins with a + ** byte-order mark (BOM, U+FEFF) then the BOM is removed from the + ** string and the rest of the string is interpreted according to the + ** byte-order specified by the BOM. ^The byte-order specified by + ** the BOM at the beginning of the text overrides the byte-order + ** specified by the interface procedure. ^So, for example, if + ** sqlite3_result_text16le() is invoked with text that begins + ** with bytes 0xfe, 0xff (a big-endian byte-order mark) then the + ** first two bytes of input are skipped and the remaining input + ** is interpreted as UTF16BE text. + ** + ** ^For UTF16 input text to the sqlite3_result_text16(), + ** sqlite3_result_text16be(), sqlite3_result_text16le(), and + ** sqlite3_result_text64() routines, if the text contains invalid + ** UTF16 characters, the invalid characters might be converted + ** into the unicode replacement character, U+FFFD. + ** + ** ^The sqlite3_result_value() interface sets the result of + ** the application-defined function to be a copy of the + ** [unprotected sqlite3_value] object specified by the 2nd parameter. ^The + ** sqlite3_result_value() interface makes a copy of the [sqlite3_value] + ** so that the [sqlite3_value] specified in the parameter may change or + ** be deallocated after sqlite3_result_value() returns without harm. + ** ^A [protected sqlite3_value] object may always be used where an + ** [unprotected sqlite3_value] object is required, so either + ** kind of [sqlite3_value] object can be used with this interface. + ** + ** ^The sqlite3_result_pointer(C,P,T,D) interface sets the result to an + ** SQL NULL value, just like [sqlite3_result_null(C)], except that it + ** also associates the host-language pointer P or type T with that + ** NULL value such that the pointer can be retrieved within an + ** [application-defined SQL function] using [sqlite3_value_pointer()]. + ** ^If the D parameter is not NULL, then it is a pointer to a destructor + ** for the P parameter. ^SQLite invokes D with P as its only argument + ** when SQLite is finished with P. The T parameter should be a static + ** string and preferably a string literal. The sqlite3_result_pointer() + ** routine is part of the [pointer passing interface] added for SQLite 3.20.0. + ** + ** If these routines are called from within the different thread + ** than the one containing the application-defined function that received + ** the [sqlite3_context] pointer, the results are undefined. + */ + SQLITE_API void sqlite3_result_blob(sqlite3_context*, const void*, int, void (*)(void*)); + SQLITE_API void sqlite3_result_blob64(sqlite3_context*, const void*, sqlite3_uint64, void (*)(void*)); + SQLITE_API void sqlite3_result_double(sqlite3_context*, double); + SQLITE_API void sqlite3_result_error(sqlite3_context*, const char*, int); + SQLITE_API void sqlite3_result_error16(sqlite3_context*, const void*, int); + SQLITE_API void sqlite3_result_error_toobig(sqlite3_context*); + SQLITE_API void sqlite3_result_error_nomem(sqlite3_context*); + SQLITE_API void sqlite3_result_error_code(sqlite3_context*, int); + SQLITE_API void sqlite3_result_int(sqlite3_context*, int); + SQLITE_API void sqlite3_result_int64(sqlite3_context*, sqlite3_int64); + SQLITE_API void sqlite3_result_null(sqlite3_context*); + SQLITE_API void sqlite3_result_text(sqlite3_context*, const char*, int, void (*)(void*)); + SQLITE_API void + sqlite3_result_text64(sqlite3_context*, const char*, sqlite3_uint64, void (*)(void*), unsigned char encoding); + SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void (*)(void*)); + SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int, void (*)(void*)); + SQLITE_API void sqlite3_result_text16be(sqlite3_context*, const void*, int, void (*)(void*)); + SQLITE_API void sqlite3_result_value(sqlite3_context*, sqlite3_value*); + SQLITE_API void sqlite3_result_pointer(sqlite3_context*, void*, const char*, void (*)(void*)); + SQLITE_API void sqlite3_result_zeroblob(sqlite3_context*, int n); + SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n); + + /* + ** CAPI3REF: Setting The Subtype Of An SQL Function + ** METHOD: sqlite3_context + ** + ** The sqlite3_result_subtype(C,T) function causes the subtype of + ** the result from the [application-defined SQL function] with + ** [sqlite3_context] C to be the value T. Only the lower 8 bits + ** of the subtype T are preserved in current versions of SQLite; + ** higher order bits are discarded. + ** The number of subtype bytes preserved by SQLite might increase + ** in future releases of SQLite. + */ + SQLITE_API void sqlite3_result_subtype(sqlite3_context*, unsigned int); + + /* + ** CAPI3REF: Define New Collating Sequences + ** METHOD: sqlite3 + ** + ** ^These functions add, remove, or modify a [collation] associated + ** with the [database connection] specified as the first argument. + ** + ** ^The name of the collation is a UTF-8 string + ** for sqlite3_create_collation() and sqlite3_create_collation_v2() + ** and a UTF-16 string in native byte order for sqlite3_create_collation16(). + ** ^Collation names that compare equal according to [sqlite3_strnicmp()] are + ** considered to be the same name. + ** + ** ^(The third argument (eTextRep) must be one of the constants: + **
    + **
  • [SQLITE_UTF8], + **
  • [SQLITE_UTF16LE], + **
  • [SQLITE_UTF16BE], + **
  • [SQLITE_UTF16], or + **
  • [SQLITE_UTF16_ALIGNED]. + **
)^ + ** ^The eTextRep argument determines the encoding of strings passed + ** to the collating function callback, xCompare. + ** ^The [SQLITE_UTF16] and [SQLITE_UTF16_ALIGNED] values for eTextRep + ** force strings to be UTF16 with native byte order. + ** ^The [SQLITE_UTF16_ALIGNED] value for eTextRep forces strings to begin + ** on an even byte address. + ** + ** ^The fourth argument, pArg, is an application data pointer that is passed + ** through as the first argument to the collating function callback. + ** + ** ^The fifth argument, xCompare, is a pointer to the collating function. + ** ^Multiple collating functions can be registered using the same name but + ** with different eTextRep parameters and SQLite will use whichever + ** function requires the least amount of data transformation. + ** ^If the xCompare argument is NULL then the collating function is + ** deleted. ^When all collating functions having the same name are deleted, + ** that collation is no longer usable. + ** + ** ^The collating function callback is invoked with a copy of the pArg + ** application data pointer and with two strings in the encoding specified + ** by the eTextRep argument. The two integer parameters to the collating + ** function callback are the length of the two strings, in bytes. The collating + ** function must return an integer that is negative, zero, or positive + ** if the first string is less than, equal to, or greater than the second, + ** respectively. A collating function must always return the same answer + ** given the same inputs. If two or more collating functions are registered + ** to the same collation name (using different eTextRep values) then all + ** must give an equivalent answer when invoked with equivalent strings. + ** The collating function must obey the following properties for all + ** strings A, B, and C: + ** + **
    + **
  1. If A==B then B==A. + **
  2. If A==B and B==C then A==C. + **
  3. If A<B THEN B>A. + **
  4. If A<B and B<C then A<C. + **
+ ** + ** If a collating function fails any of the above constraints and that + ** collating function is registered and used, then the behavior of SQLite + ** is undefined. + ** + ** ^The sqlite3_create_collation_v2() works like sqlite3_create_collation() + ** with the addition that the xDestroy callback is invoked on pArg when + ** the collating function is deleted. + ** ^Collating functions are deleted when they are overridden by later + ** calls to the collation creation functions or when the + ** [database connection] is closed using [sqlite3_close()]. + ** + ** ^The xDestroy callback is not called if the + ** sqlite3_create_collation_v2() function fails. Applications that invoke + ** sqlite3_create_collation_v2() with a non-NULL xDestroy argument should + ** check the return code and dispose of the application data pointer + ** themselves rather than expecting SQLite to deal with it for them. + ** This is different from every other SQLite interface. The inconsistency + ** is unfortunate but cannot be changed without breaking backwards + ** compatibility. + ** + ** See also: [sqlite3_collation_needed()] and [sqlite3_collation_needed16()]. + */ + SQLITE_API int sqlite3_create_collation(sqlite3*, + const char* zName, + int eTextRep, + void* pArg, + int (*xCompare)(void*, int, const void*, int, const void*)); + SQLITE_API int sqlite3_create_collation_v2(sqlite3*, + const char* zName, + int eTextRep, + void* pArg, + int (*xCompare)(void*, int, const void*, int, const void*), + void (*xDestroy)(void*)); + SQLITE_API int sqlite3_create_collation16(sqlite3*, + const void* zName, + int eTextRep, + void* pArg, + int (*xCompare)(void*, int, const void*, int, const void*)); + + /* + ** CAPI3REF: Collation Needed Callbacks + ** METHOD: sqlite3 + ** + ** ^To avoid having to register all collation sequences before a database + ** can be used, a single callback function may be registered with the + ** [database connection] to be invoked whenever an undefined collation + ** sequence is required. + ** + ** ^If the function is registered using the sqlite3_collation_needed() API, + ** then it is passed the names of undefined collation sequences as strings + ** encoded in UTF-8. ^If sqlite3_collation_needed16() is used, + ** the names are passed as UTF-16 in machine native byte order. + ** ^A call to either function replaces the existing collation-needed callback. + ** + ** ^(When the callback is invoked, the first argument passed is a copy + ** of the second argument to sqlite3_collation_needed() or + ** sqlite3_collation_needed16(). The second argument is the database + ** connection. The third argument is one of [SQLITE_UTF8], [SQLITE_UTF16BE], + ** or [SQLITE_UTF16LE], indicating the most desirable form of the collation + ** sequence function required. The fourth parameter is the name of the + ** required collation sequence.)^ + ** + ** The callback function should register the desired collation using + ** [sqlite3_create_collation()], [sqlite3_create_collation16()], or + ** [sqlite3_create_collation_v2()]. + */ + SQLITE_API int sqlite3_collation_needed(sqlite3*, void*, void (*)(void*, sqlite3*, int eTextRep, const char*)); + SQLITE_API int sqlite3_collation_needed16(sqlite3*, void*, void (*)(void*, sqlite3*, int eTextRep, const void*)); #ifdef SQLITE_ENABLE_CEROD -/* -** Specify the activation key for a CEROD database. Unless -** activated, none of the CEROD routines will work. -*/ -SQLITE_API void sqlite3_activate_cerod( - const char *zPassPhrase /* Activation phrase */ -); + /* + ** Specify the activation key for a CEROD database. Unless + ** activated, none of the CEROD routines will work. + */ + SQLITE_API void sqlite3_activate_cerod(const char* zPassPhrase /* Activation phrase */ + ); #endif -/* -** CAPI3REF: Suspend Execution For A Short Time -** -** The sqlite3_sleep() function causes the current thread to suspend execution -** for at least a number of milliseconds specified in its parameter. -** -** If the operating system does not support sleep requests with -** millisecond time resolution, then the time will be rounded up to -** the nearest second. The number of milliseconds of sleep actually -** requested from the operating system is returned. -** -** ^SQLite implements this interface by calling the xSleep() -** method of the default [sqlite3_vfs] object. If the xSleep() method -** of the default VFS is not implemented correctly, or not implemented at -** all, then the behavior of sqlite3_sleep() may deviate from the description -** in the previous paragraphs. -*/ -SQLITE_API int sqlite3_sleep(int); - -/* -** CAPI3REF: Name Of The Folder Holding Temporary Files -** -** ^(If this global variable is made to point to a string which is -** the name of a folder (a.k.a. directory), then all temporary files -** created by SQLite when using a built-in [sqlite3_vfs | VFS] -** will be placed in that directory.)^ ^If this variable -** is a NULL pointer, then SQLite performs a search for an appropriate -** temporary file directory. -** -** Applications are strongly discouraged from using this global variable. -** It is required to set a temporary folder on Windows Runtime (WinRT). -** But for all other platforms, it is highly recommended that applications -** neither read nor write this variable. This global variable is a relic -** that exists for backwards compatibility of legacy applications and should -** be avoided in new projects. -** -** It is not safe to read or modify this variable in more than one -** thread at a time. It is not safe to read or modify this variable -** if a [database connection] is being used at the same time in a separate -** thread. -** It is intended that this variable be set once -** as part of process initialization and before any SQLite interface -** routines have been called and that this variable remain unchanged -** thereafter. -** -** ^The [temp_store_directory pragma] may modify this variable and cause -** it to point to memory obtained from [sqlite3_malloc]. ^Furthermore, -** the [temp_store_directory pragma] always assumes that any string -** that this variable points to is held in memory obtained from -** [sqlite3_malloc] and the pragma may attempt to free that memory -** using [sqlite3_free]. -** Hence, if this variable is modified directly, either it should be -** made NULL or made to point to memory obtained from [sqlite3_malloc] -** or else the use of the [temp_store_directory pragma] should be avoided. -** Except when requested by the [temp_store_directory pragma], SQLite -** does not free the memory that sqlite3_temp_directory points to. If -** the application wants that memory to be freed, it must do -** so itself, taking care to only do so after all [database connection] -** objects have been destroyed. -** -** Note to Windows Runtime users: The temporary directory must be set -** prior to calling [sqlite3_open] or [sqlite3_open_v2]. Otherwise, various -** features that require the use of temporary files may fail. Here is an -** example of how to do this using C++ with the Windows Runtime: -** -**
-** LPCWSTR zPath = Windows::Storage::ApplicationData::Current->
-**       TemporaryFolder->Path->Data();
-** char zPathBuf[MAX_PATH + 1];
-** memset(zPathBuf, 0, sizeof(zPathBuf));
-** WideCharToMultiByte(CP_UTF8, 0, zPath, -1, zPathBuf, sizeof(zPathBuf),
-**       NULL, NULL);
-** sqlite3_temp_directory = sqlite3_mprintf("%s", zPathBuf);
-** 
-*/ -SQLITE_API SQLITE_EXTERN char *sqlite3_temp_directory; - -/* -** CAPI3REF: Name Of The Folder Holding Database Files -** -** ^(If this global variable is made to point to a string which is -** the name of a folder (a.k.a. directory), then all database files -** specified with a relative pathname and created or accessed by -** SQLite when using a built-in windows [sqlite3_vfs | VFS] will be assumed -** to be relative to that directory.)^ ^If this variable is a NULL -** pointer, then SQLite assumes that all database files specified -** with a relative pathname are relative to the current directory -** for the process. Only the windows VFS makes use of this global -** variable; it is ignored by the unix VFS. -** -** Changing the value of this variable while a database connection is -** open can result in a corrupt database. -** -** It is not safe to read or modify this variable in more than one -** thread at a time. It is not safe to read or modify this variable -** if a [database connection] is being used at the same time in a separate -** thread. -** It is intended that this variable be set once -** as part of process initialization and before any SQLite interface -** routines have been called and that this variable remain unchanged -** thereafter. -** -** ^The [data_store_directory pragma] may modify this variable and cause -** it to point to memory obtained from [sqlite3_malloc]. ^Furthermore, -** the [data_store_directory pragma] always assumes that any string -** that this variable points to is held in memory obtained from -** [sqlite3_malloc] and the pragma may attempt to free that memory -** using [sqlite3_free]. -** Hence, if this variable is modified directly, either it should be -** made NULL or made to point to memory obtained from [sqlite3_malloc] -** or else the use of the [data_store_directory pragma] should be avoided. -*/ -SQLITE_API SQLITE_EXTERN char *sqlite3_data_directory; - -/* -** CAPI3REF: Win32 Specific Interface -** -** These interfaces are available only on Windows. The -** [sqlite3_win32_set_directory] interface is used to set the value associated -** with the [sqlite3_temp_directory] or [sqlite3_data_directory] variable, to -** zValue, depending on the value of the type parameter. The zValue parameter -** should be NULL to cause the previous value to be freed via [sqlite3_free]; -** a non-NULL value will be copied into memory obtained from [sqlite3_malloc] -** prior to being used. The [sqlite3_win32_set_directory] interface returns -** [SQLITE_OK] to indicate success, [SQLITE_ERROR] if the type is unsupported, -** or [SQLITE_NOMEM] if memory could not be allocated. The value of the -** [sqlite3_data_directory] variable is intended to act as a replacement for -** the current directory on the sub-platforms of Win32 where that concept is -** not present, e.g. WinRT and UWP. The [sqlite3_win32_set_directory8] and -** [sqlite3_win32_set_directory16] interfaces behave exactly the same as the -** sqlite3_win32_set_directory interface except the string parameter must be -** UTF-8 or UTF-16, respectively. -*/ -SQLITE_API int sqlite3_win32_set_directory( - unsigned long type, /* Identifier for directory being set or reset */ - void *zValue /* New value for directory being set or reset */ -); -SQLITE_API int sqlite3_win32_set_directory8(unsigned long type, const char *zValue); -SQLITE_API int sqlite3_win32_set_directory16(unsigned long type, const void *zValue); + /* + ** CAPI3REF: Suspend Execution For A Short Time + ** + ** The sqlite3_sleep() function causes the current thread to suspend execution + ** for at least a number of milliseconds specified in its parameter. + ** + ** If the operating system does not support sleep requests with + ** millisecond time resolution, then the time will be rounded up to + ** the nearest second. The number of milliseconds of sleep actually + ** requested from the operating system is returned. + ** + ** ^SQLite implements this interface by calling the xSleep() + ** method of the default [sqlite3_vfs] object. If the xSleep() method + ** of the default VFS is not implemented correctly, or not implemented at + ** all, then the behavior of sqlite3_sleep() may deviate from the description + ** in the previous paragraphs. + */ + SQLITE_API int sqlite3_sleep(int); + + /* + ** CAPI3REF: Name Of The Folder Holding Temporary Files + ** + ** ^(If this global variable is made to point to a string which is + ** the name of a folder (a.k.a. directory), then all temporary files + ** created by SQLite when using a built-in [sqlite3_vfs | VFS] + ** will be placed in that directory.)^ ^If this variable + ** is a NULL pointer, then SQLite performs a search for an appropriate + ** temporary file directory. + ** + ** Applications are strongly discouraged from using this global variable. + ** It is required to set a temporary folder on Windows Runtime (WinRT). + ** But for all other platforms, it is highly recommended that applications + ** neither read nor write this variable. This global variable is a relic + ** that exists for backwards compatibility of legacy applications and should + ** be avoided in new projects. + ** + ** It is not safe to read or modify this variable in more than one + ** thread at a time. It is not safe to read or modify this variable + ** if a [database connection] is being used at the same time in a separate + ** thread. + ** It is intended that this variable be set once + ** as part of process initialization and before any SQLite interface + ** routines have been called and that this variable remain unchanged + ** thereafter. + ** + ** ^The [temp_store_directory pragma] may modify this variable and cause + ** it to point to memory obtained from [sqlite3_malloc]. ^Furthermore, + ** the [temp_store_directory pragma] always assumes that any string + ** that this variable points to is held in memory obtained from + ** [sqlite3_malloc] and the pragma may attempt to free that memory + ** using [sqlite3_free]. + ** Hence, if this variable is modified directly, either it should be + ** made NULL or made to point to memory obtained from [sqlite3_malloc] + ** or else the use of the [temp_store_directory pragma] should be avoided. + ** Except when requested by the [temp_store_directory pragma], SQLite + ** does not free the memory that sqlite3_temp_directory points to. If + ** the application wants that memory to be freed, it must do + ** so itself, taking care to only do so after all [database connection] + ** objects have been destroyed. + ** + ** Note to Windows Runtime users: The temporary directory must be set + ** prior to calling [sqlite3_open] or [sqlite3_open_v2]. Otherwise, various + ** features that require the use of temporary files may fail. Here is an + ** example of how to do this using C++ with the Windows Runtime: + ** + **
+    ** LPCWSTR zPath = Windows::Storage::ApplicationData::Current->
+    **       TemporaryFolder->Path->Data();
+    ** char zPathBuf[MAX_PATH + 1];
+    ** memset(zPathBuf, 0, sizeof(zPathBuf));
+    ** WideCharToMultiByte(CP_UTF8, 0, zPath, -1, zPathBuf, sizeof(zPathBuf),
+    **       NULL, NULL);
+    ** sqlite3_temp_directory = sqlite3_mprintf("%s", zPathBuf);
+    ** 
+ */ + SQLITE_API SQLITE_EXTERN char* sqlite3_temp_directory; + + /* + ** CAPI3REF: Name Of The Folder Holding Database Files + ** + ** ^(If this global variable is made to point to a string which is + ** the name of a folder (a.k.a. directory), then all database files + ** specified with a relative pathname and created or accessed by + ** SQLite when using a built-in windows [sqlite3_vfs | VFS] will be assumed + ** to be relative to that directory.)^ ^If this variable is a NULL + ** pointer, then SQLite assumes that all database files specified + ** with a relative pathname are relative to the current directory + ** for the process. Only the windows VFS makes use of this global + ** variable; it is ignored by the unix VFS. + ** + ** Changing the value of this variable while a database connection is + ** open can result in a corrupt database. + ** + ** It is not safe to read or modify this variable in more than one + ** thread at a time. It is not safe to read or modify this variable + ** if a [database connection] is being used at the same time in a separate + ** thread. + ** It is intended that this variable be set once + ** as part of process initialization and before any SQLite interface + ** routines have been called and that this variable remain unchanged + ** thereafter. + ** + ** ^The [data_store_directory pragma] may modify this variable and cause + ** it to point to memory obtained from [sqlite3_malloc]. ^Furthermore, + ** the [data_store_directory pragma] always assumes that any string + ** that this variable points to is held in memory obtained from + ** [sqlite3_malloc] and the pragma may attempt to free that memory + ** using [sqlite3_free]. + ** Hence, if this variable is modified directly, either it should be + ** made NULL or made to point to memory obtained from [sqlite3_malloc] + ** or else the use of the [data_store_directory pragma] should be avoided. + */ + SQLITE_API SQLITE_EXTERN char* sqlite3_data_directory; + + /* + ** CAPI3REF: Win32 Specific Interface + ** + ** These interfaces are available only on Windows. The + ** [sqlite3_win32_set_directory] interface is used to set the value associated + ** with the [sqlite3_temp_directory] or [sqlite3_data_directory] variable, to + ** zValue, depending on the value of the type parameter. The zValue parameter + ** should be NULL to cause the previous value to be freed via [sqlite3_free]; + ** a non-NULL value will be copied into memory obtained from [sqlite3_malloc] + ** prior to being used. The [sqlite3_win32_set_directory] interface returns + ** [SQLITE_OK] to indicate success, [SQLITE_ERROR] if the type is unsupported, + ** or [SQLITE_NOMEM] if memory could not be allocated. The value of the + ** [sqlite3_data_directory] variable is intended to act as a replacement for + ** the current directory on the sub-platforms of Win32 where that concept is + ** not present, e.g. WinRT and UWP. The [sqlite3_win32_set_directory8] and + ** [sqlite3_win32_set_directory16] interfaces behave exactly the same as the + ** sqlite3_win32_set_directory interface except the string parameter must be + ** UTF-8 or UTF-16, respectively. + */ + SQLITE_API int sqlite3_win32_set_directory(unsigned long type, /* Identifier for directory being set or reset */ + void* zValue /* New value for directory being set or reset */ + ); + SQLITE_API int sqlite3_win32_set_directory8(unsigned long type, const char* zValue); + SQLITE_API int sqlite3_win32_set_directory16(unsigned long type, const void* zValue); /* ** CAPI3REF: Win32 Directory Types @@ -6231,105 +6182,105 @@ SQLITE_API int sqlite3_win32_set_directory16(unsigned long type, const void *zVa ** These macros are only available on Windows. They define the allowed values ** for the type argument to the [sqlite3_win32_set_directory] interface. */ -#define SQLITE_WIN32_DATA_DIRECTORY_TYPE 1 -#define SQLITE_WIN32_TEMP_DIRECTORY_TYPE 2 - -/* -** CAPI3REF: Test For Auto-Commit Mode -** KEYWORDS: {autocommit mode} -** METHOD: sqlite3 -** -** ^The sqlite3_get_autocommit() interface returns non-zero or -** zero if the given database connection is or is not in autocommit mode, -** respectively. ^Autocommit mode is on by default. -** ^Autocommit mode is disabled by a [BEGIN] statement. -** ^Autocommit mode is re-enabled by a [COMMIT] or [ROLLBACK]. -** -** If certain kinds of errors occur on a statement within a multi-statement -** transaction (errors including [SQLITE_FULL], [SQLITE_IOERR], -** [SQLITE_NOMEM], [SQLITE_BUSY], and [SQLITE_INTERRUPT]) then the -** transaction might be rolled back automatically. The only way to -** find out whether SQLite automatically rolled back the transaction after -** an error is to use this function. -** -** If another thread changes the autocommit status of the database -** connection while this routine is running, then the return value -** is undefined. -*/ -SQLITE_API int sqlite3_get_autocommit(sqlite3*); - -/* -** CAPI3REF: Find The Database Handle Of A Prepared Statement -** METHOD: sqlite3_stmt -** -** ^The sqlite3_db_handle interface returns the [database connection] handle -** to which a [prepared statement] belongs. ^The [database connection] -** returned by sqlite3_db_handle is the same [database connection] -** that was the first argument -** to the [sqlite3_prepare_v2()] call (or its variants) that was used to -** create the statement in the first place. -*/ -SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*); - -/* -** CAPI3REF: Return The Filename For A Database Connection -** METHOD: sqlite3 -** -** ^The sqlite3_db_filename(D,N) interface returns a pointer to the filename -** associated with database N of connection D. -** ^If there is no attached database N on the database -** connection D, or if database N is a temporary or in-memory database, then -** this function will return either a NULL pointer or an empty string. -** -** ^The string value returned by this routine is owned and managed by -** the database connection. ^The value will be valid until the database N -** is [DETACH]-ed or until the database connection closes. -** -** ^The filename returned by this function is the output of the -** xFullPathname method of the [VFS]. ^In other words, the filename -** will be an absolute pathname, even if the filename used -** to open the database originally was a URI or relative pathname. -** -** If the filename pointer returned by this routine is not NULL, then it -** can be used as the filename input parameter to these routines: -**
    -**
  • [sqlite3_uri_parameter()] -**
  • [sqlite3_uri_boolean()] -**
  • [sqlite3_uri_int64()] -**
  • [sqlite3_filename_database()] -**
  • [sqlite3_filename_journal()] -**
  • [sqlite3_filename_wal()] -**
-*/ -SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName); - -/* -** CAPI3REF: Determine if a database is read-only -** METHOD: sqlite3 -** -** ^The sqlite3_db_readonly(D,N) interface returns 1 if the database N -** of connection D is read-only, 0 if it is read/write, or -1 if N is not -** the name of a database on connection D. -*/ -SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName); - -/* -** CAPI3REF: Determine the transaction state of a database -** METHOD: sqlite3 -** -** ^The sqlite3_txn_state(D,S) interface returns the current -** [transaction state] of schema S in database connection D. ^If S is NULL, -** then the highest transaction state of any schema on database connection D -** is returned. Transaction states are (in order of lowest to highest): -**
    -**
  1. SQLITE_TXN_NONE -**
  2. SQLITE_TXN_READ -**
  3. SQLITE_TXN_WRITE -**
-** ^If the S argument to sqlite3_txn_state(D,S) is not the name of -** a valid schema, then -1 is returned. -*/ -SQLITE_API int sqlite3_txn_state(sqlite3*,const char *zSchema); +#define SQLITE_WIN32_DATA_DIRECTORY_TYPE 1 +#define SQLITE_WIN32_TEMP_DIRECTORY_TYPE 2 + + /* + ** CAPI3REF: Test For Auto-Commit Mode + ** KEYWORDS: {autocommit mode} + ** METHOD: sqlite3 + ** + ** ^The sqlite3_get_autocommit() interface returns non-zero or + ** zero if the given database connection is or is not in autocommit mode, + ** respectively. ^Autocommit mode is on by default. + ** ^Autocommit mode is disabled by a [BEGIN] statement. + ** ^Autocommit mode is re-enabled by a [COMMIT] or [ROLLBACK]. + ** + ** If certain kinds of errors occur on a statement within a multi-statement + ** transaction (errors including [SQLITE_FULL], [SQLITE_IOERR], + ** [SQLITE_NOMEM], [SQLITE_BUSY], and [SQLITE_INTERRUPT]) then the + ** transaction might be rolled back automatically. The only way to + ** find out whether SQLite automatically rolled back the transaction after + ** an error is to use this function. + ** + ** If another thread changes the autocommit status of the database + ** connection while this routine is running, then the return value + ** is undefined. + */ + SQLITE_API int sqlite3_get_autocommit(sqlite3*); + + /* + ** CAPI3REF: Find The Database Handle Of A Prepared Statement + ** METHOD: sqlite3_stmt + ** + ** ^The sqlite3_db_handle interface returns the [database connection] handle + ** to which a [prepared statement] belongs. ^The [database connection] + ** returned by sqlite3_db_handle is the same [database connection] + ** that was the first argument + ** to the [sqlite3_prepare_v2()] call (or its variants) that was used to + ** create the statement in the first place. + */ + SQLITE_API sqlite3* sqlite3_db_handle(sqlite3_stmt*); + + /* + ** CAPI3REF: Return The Filename For A Database Connection + ** METHOD: sqlite3 + ** + ** ^The sqlite3_db_filename(D,N) interface returns a pointer to the filename + ** associated with database N of connection D. + ** ^If there is no attached database N on the database + ** connection D, or if database N is a temporary or in-memory database, then + ** this function will return either a NULL pointer or an empty string. + ** + ** ^The string value returned by this routine is owned and managed by + ** the database connection. ^The value will be valid until the database N + ** is [DETACH]-ed or until the database connection closes. + ** + ** ^The filename returned by this function is the output of the + ** xFullPathname method of the [VFS]. ^In other words, the filename + ** will be an absolute pathname, even if the filename used + ** to open the database originally was a URI or relative pathname. + ** + ** If the filename pointer returned by this routine is not NULL, then it + ** can be used as the filename input parameter to these routines: + **
    + **
  • [sqlite3_uri_parameter()] + **
  • [sqlite3_uri_boolean()] + **
  • [sqlite3_uri_int64()] + **
  • [sqlite3_filename_database()] + **
  • [sqlite3_filename_journal()] + **
  • [sqlite3_filename_wal()] + **
+ */ + SQLITE_API const char* sqlite3_db_filename(sqlite3* db, const char* zDbName); + + /* + ** CAPI3REF: Determine if a database is read-only + ** METHOD: sqlite3 + ** + ** ^The sqlite3_db_readonly(D,N) interface returns 1 if the database N + ** of connection D is read-only, 0 if it is read/write, or -1 if N is not + ** the name of a database on connection D. + */ + SQLITE_API int sqlite3_db_readonly(sqlite3* db, const char* zDbName); + + /* + ** CAPI3REF: Determine the transaction state of a database + ** METHOD: sqlite3 + ** + ** ^The sqlite3_txn_state(D,S) interface returns the current + ** [transaction state] of schema S in database connection D. ^If S is NULL, + ** then the highest transaction state of any schema on database connection D + ** is returned. Transaction states are (in order of lowest to highest): + **
    + **
  1. SQLITE_TXN_NONE + **
  2. SQLITE_TXN_READ + **
  3. SQLITE_TXN_WRITE + **
+ ** ^If the S argument to sqlite3_txn_state(D,S) is not the name of + ** a valid schema, then -1 is returned. + */ + SQLITE_API int sqlite3_txn_state(sqlite3*, const char* zSchema); /* ** CAPI3REF: Allowed return values from [sqlite3_txn_state()] @@ -6360,1467 +6311,1458 @@ SQLITE_API int sqlite3_txn_state(sqlite3*,const char *zSchema); ** but has not yet committed. The transaction state will change to ** to SQLITE_TXN_NONE at the next [ROLLBACK] or [COMMIT]. */ -#define SQLITE_TXN_NONE 0 -#define SQLITE_TXN_READ 1 +#define SQLITE_TXN_NONE 0 +#define SQLITE_TXN_READ 1 #define SQLITE_TXN_WRITE 2 -/* -** CAPI3REF: Find the next prepared statement -** METHOD: sqlite3 -** -** ^This interface returns a pointer to the next [prepared statement] after -** pStmt associated with the [database connection] pDb. ^If pStmt is NULL -** then this interface returns a pointer to the first prepared statement -** associated with the database connection pDb. ^If no prepared statement -** satisfies the conditions of this routine, it returns NULL. -** -** The [database connection] pointer D in a call to -** [sqlite3_next_stmt(D,S)] must refer to an open database -** connection and in particular must not be a NULL pointer. -*/ -SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt); + /* + ** CAPI3REF: Find the next prepared statement + ** METHOD: sqlite3 + ** + ** ^This interface returns a pointer to the next [prepared statement] after + ** pStmt associated with the [database connection] pDb. ^If pStmt is NULL + ** then this interface returns a pointer to the first prepared statement + ** associated with the database connection pDb. ^If no prepared statement + ** satisfies the conditions of this routine, it returns NULL. + ** + ** The [database connection] pointer D in a call to + ** [sqlite3_next_stmt(D,S)] must refer to an open database + ** connection and in particular must not be a NULL pointer. + */ + SQLITE_API sqlite3_stmt* sqlite3_next_stmt(sqlite3* pDb, sqlite3_stmt* pStmt); + + /* + ** CAPI3REF: Commit And Rollback Notification Callbacks + ** METHOD: sqlite3 + ** + ** ^The sqlite3_commit_hook() interface registers a callback + ** function to be invoked whenever a transaction is [COMMIT | committed]. + ** ^Any callback set by a previous call to sqlite3_commit_hook() + ** for the same database connection is overridden. + ** ^The sqlite3_rollback_hook() interface registers a callback + ** function to be invoked whenever a transaction is [ROLLBACK | rolled back]. + ** ^Any callback set by a previous call to sqlite3_rollback_hook() + ** for the same database connection is overridden. + ** ^The pArg argument is passed through to the callback. + ** ^If the callback on a commit hook function returns non-zero, + ** then the commit is converted into a rollback. + ** + ** ^The sqlite3_commit_hook(D,C,P) and sqlite3_rollback_hook(D,C,P) functions + ** return the P argument from the previous call of the same function + ** on the same [database connection] D, or NULL for + ** the first call for each function on D. + ** + ** The commit and rollback hook callbacks are not reentrant. + ** The callback implementation must not do anything that will modify + ** the database connection that invoked the callback. Any actions + ** to modify the database connection must be deferred until after the + ** completion of the [sqlite3_step()] call that triggered the commit + ** or rollback hook in the first place. + ** Note that running any other SQL statements, including SELECT statements, + ** or merely calling [sqlite3_prepare_v2()] and [sqlite3_step()] will modify + ** the database connections for the meaning of "modify" in this paragraph. + ** + ** ^Registering a NULL function disables the callback. + ** + ** ^When the commit hook callback routine returns zero, the [COMMIT] + ** operation is allowed to continue normally. ^If the commit hook + ** returns non-zero, then the [COMMIT] is converted into a [ROLLBACK]. + ** ^The rollback hook is invoked on a rollback that results from a commit + ** hook returning non-zero, just as it would be with any other rollback. + ** + ** ^For the purposes of this API, a transaction is said to have been + ** rolled back if an explicit "ROLLBACK" statement is executed, or + ** an error or constraint causes an implicit rollback to occur. + ** ^The rollback callback is not invoked if a transaction is + ** automatically rolled back because the database connection is closed. + ** + ** See also the [sqlite3_update_hook()] interface. + */ + SQLITE_API void* sqlite3_commit_hook(sqlite3*, int (*)(void*), void*); + SQLITE_API void* sqlite3_rollback_hook(sqlite3*, void (*)(void*), void*); + + /* + ** CAPI3REF: Autovacuum Compaction Amount Callback + ** METHOD: sqlite3 + ** + ** ^The sqlite3_autovacuum_pages(D,C,P,X) interface registers a callback + ** function C that is invoked prior to each autovacuum of the database + ** file. ^The callback is passed a copy of the generic data pointer (P), + ** the schema-name of the attached database that is being autovacuumed, + ** the the size of the database file in pages, the number of free pages, + ** and the number of bytes per page, respectively. The callback should + ** return the number of free pages that should be removed by the + ** autovacuum. ^If the callback returns zero, then no autovacuum happens. + ** ^If the value returned is greater than or equal to the number of + ** free pages, then a complete autovacuum happens. + ** + **

^If there are multiple ATTACH-ed database files that are being + ** modified as part of a transaction commit, then the autovacuum pages + ** callback is invoked separately for each file. + ** + **

The callback is not reentrant. The callback function should + ** not attempt to invoke any other SQLite interface. If it does, bad + ** things may happen, including segmentation faults and corrupt database + ** files. The callback function should be a simple function that + ** does some arithmetic on its input parameters and returns a result. + ** + ** ^The X parameter to sqlite3_autovacuum_pages(D,C,P,X) is an optional + ** destructor for the P parameter. ^If X is not NULL, then X(P) is + ** invoked whenever the database connection closes or when the callback + ** is overwritten by another invocation of sqlite3_autovacuum_pages(). + ** + **

^There is only one autovacuum pages callback per database connection. + ** ^Each call to the sqlite3_autovacuum_pages() interface overrides all + ** previous invocations for that database connection. ^If the callback + ** argument (C) to sqlite3_autovacuum_pages(D,C,P,X) is a NULL pointer, + ** then the autovacuum steps callback is cancelled. The return value + ** from sqlite3_autovacuum_pages() is normally SQLITE_OK, but might + ** be some other error code if something goes wrong. The current + ** implementation will only return SQLITE_OK or SQLITE_MISUSE, but other + ** return codes might be added in future releases. + ** + **

If no autovacuum pages callback is specified (the usual case) or + ** a NULL pointer is provided for the callback, + ** then the default behavior is to vacuum all free pages. So, in other + ** words, the default behavior is the same as if the callback function + ** were something like this: + ** + **

+    **     unsigned int demonstration_autovac_pages_callback(
+    **       void *pClientData,
+    **       const char *zSchema,
+    **       unsigned int nDbPage,
+    **       unsigned int nFreePage,
+    **       unsigned int nBytePerPage
+    **     ){
+    **       return nFreePage;
+    **     }
+    ** 
+ */ + SQLITE_API int + sqlite3_autovacuum_pages(sqlite3* db, + unsigned int (*)(void*, const char*, unsigned int, unsigned int, unsigned int), + void*, + void (*)(void*)); + + /* + ** CAPI3REF: Data Change Notification Callbacks + ** METHOD: sqlite3 + ** + ** ^The sqlite3_update_hook() interface registers a callback function + ** with the [database connection] identified by the first argument + ** to be invoked whenever a row is updated, inserted or deleted in + ** a [rowid table]. + ** ^Any callback set by a previous call to this function + ** for the same database connection is overridden. + ** + ** ^The second argument is a pointer to the function to invoke when a + ** row is updated, inserted or deleted in a rowid table. + ** ^The first argument to the callback is a copy of the third argument + ** to sqlite3_update_hook(). + ** ^The second callback argument is one of [SQLITE_INSERT], [SQLITE_DELETE], + ** or [SQLITE_UPDATE], depending on the operation that caused the callback + ** to be invoked. + ** ^The third and fourth arguments to the callback contain pointers to the + ** database and table name containing the affected row. + ** ^The final callback parameter is the [rowid] of the row. + ** ^In the case of an update, this is the [rowid] after the update takes place. + ** + ** ^(The update hook is not invoked when internal system tables are + ** modified (i.e. sqlite_sequence).)^ + ** ^The update hook is not invoked when [WITHOUT ROWID] tables are modified. + ** + ** ^In the current implementation, the update hook + ** is not invoked when conflicting rows are deleted because of an + ** [ON CONFLICT | ON CONFLICT REPLACE] clause. ^Nor is the update hook + ** invoked when rows are deleted using the [truncate optimization]. + ** The exceptions defined in this paragraph might change in a future + ** release of SQLite. + ** + ** The update hook implementation must not do anything that will modify + ** the database connection that invoked the update hook. Any actions + ** to modify the database connection must be deferred until after the + ** completion of the [sqlite3_step()] call that triggered the update hook. + ** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their + ** database connections for the meaning of "modify" in this paragraph. + ** + ** ^The sqlite3_update_hook(D,C,P) function + ** returns the P argument from the previous call + ** on the same [database connection] D, or NULL for + ** the first call on D. + ** + ** See also the [sqlite3_commit_hook()], [sqlite3_rollback_hook()], + ** and [sqlite3_preupdate_hook()] interfaces. + */ + SQLITE_API void* sqlite3_update_hook(sqlite3*, void (*)(void*, int, char const*, char const*, sqlite3_int64), void*); + + /* + ** CAPI3REF: Enable Or Disable Shared Pager Cache + ** + ** ^(This routine enables or disables the sharing of the database cache + ** and schema data structures between [database connection | connections] + ** to the same database. Sharing is enabled if the argument is true + ** and disabled if the argument is false.)^ + ** + ** ^Cache sharing is enabled and disabled for an entire process. + ** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]). + ** In prior versions of SQLite, + ** sharing was enabled or disabled for each thread separately. + ** + ** ^(The cache sharing mode set by this interface effects all subsequent + ** calls to [sqlite3_open()], [sqlite3_open_v2()], and [sqlite3_open16()]. + ** Existing database connections continue to use the sharing mode + ** that was in effect at the time they were opened.)^ + ** + ** ^(This routine returns [SQLITE_OK] if shared cache was enabled or disabled + ** successfully. An [error code] is returned otherwise.)^ + ** + ** ^Shared cache is disabled by default. It is recommended that it stay + ** that way. In other words, do not use this routine. This interface + ** continues to be provided for historical compatibility, but its use is + ** discouraged. Any use of shared cache is discouraged. If shared cache + ** must be used, it is recommended that shared cache only be enabled for + ** individual database connections using the [sqlite3_open_v2()] interface + ** with the [SQLITE_OPEN_SHAREDCACHE] flag. + ** + ** Note: This method is disabled on MacOS X 10.7 and iOS version 5.0 + ** and will always return SQLITE_MISUSE. On those systems, + ** shared cache mode should be enabled per-database connection via + ** [sqlite3_open_v2()] with [SQLITE_OPEN_SHAREDCACHE]. + ** + ** This interface is threadsafe on processors where writing a + ** 32-bit integer is atomic. + ** + ** See Also: [SQLite Shared-Cache Mode] + */ + SQLITE_API int sqlite3_enable_shared_cache(int); + + /* + ** CAPI3REF: Attempt To Free Heap Memory + ** + ** ^The sqlite3_release_memory() interface attempts to free N bytes + ** of heap memory by deallocating non-essential memory allocations + ** held by the database library. Memory used to cache database + ** pages to improve performance is an example of non-essential memory. + ** ^sqlite3_release_memory() returns the number of bytes actually freed, + ** which might be more or less than the amount requested. + ** ^The sqlite3_release_memory() routine is a no-op returning zero + ** if SQLite is not compiled with [SQLITE_ENABLE_MEMORY_MANAGEMENT]. + ** + ** See also: [sqlite3_db_release_memory()] + */ + SQLITE_API int sqlite3_release_memory(int); + + /* + ** CAPI3REF: Free Memory Used By A Database Connection + ** METHOD: sqlite3 + ** + ** ^The sqlite3_db_release_memory(D) interface attempts to free as much heap + ** memory as possible from database connection D. Unlike the + ** [sqlite3_release_memory()] interface, this interface is in effect even + ** when the [SQLITE_ENABLE_MEMORY_MANAGEMENT] compile-time option is + ** omitted. + ** + ** See also: [sqlite3_release_memory()] + */ + SQLITE_API int sqlite3_db_release_memory(sqlite3*); + + /* + ** CAPI3REF: Impose A Limit On Heap Size + ** + ** These interfaces impose limits on the amount of heap memory that will be + ** by all database connections within a single process. + ** + ** ^The sqlite3_soft_heap_limit64() interface sets and/or queries the + ** soft limit on the amount of heap memory that may be allocated by SQLite. + ** ^SQLite strives to keep heap memory utilization below the soft heap + ** limit by reducing the number of pages held in the page cache + ** as heap memory usages approaches the limit. + ** ^The soft heap limit is "soft" because even though SQLite strives to stay + ** below the limit, it will exceed the limit rather than generate + ** an [SQLITE_NOMEM] error. In other words, the soft heap limit + ** is advisory only. + ** + ** ^The sqlite3_hard_heap_limit64(N) interface sets a hard upper bound of + ** N bytes on the amount of memory that will be allocated. ^The + ** sqlite3_hard_heap_limit64(N) interface is similar to + ** sqlite3_soft_heap_limit64(N) except that memory allocations will fail + ** when the hard heap limit is reached. + ** + ** ^The return value from both sqlite3_soft_heap_limit64() and + ** sqlite3_hard_heap_limit64() is the size of + ** the heap limit prior to the call, or negative in the case of an + ** error. ^If the argument N is negative + ** then no change is made to the heap limit. Hence, the current + ** size of heap limits can be determined by invoking + ** sqlite3_soft_heap_limit64(-1) or sqlite3_hard_heap_limit(-1). + ** + ** ^Setting the heap limits to zero disables the heap limiter mechanism. + ** + ** ^The soft heap limit may not be greater than the hard heap limit. + ** ^If the hard heap limit is enabled and if sqlite3_soft_heap_limit(N) + ** is invoked with a value of N that is greater than the hard heap limit, + ** the the soft heap limit is set to the value of the hard heap limit. + ** ^The soft heap limit is automatically enabled whenever the hard heap + ** limit is enabled. ^When sqlite3_hard_heap_limit64(N) is invoked and + ** the soft heap limit is outside the range of 1..N, then the soft heap + ** limit is set to N. ^Invoking sqlite3_soft_heap_limit64(0) when the + ** hard heap limit is enabled makes the soft heap limit equal to the + ** hard heap limit. + ** + ** The memory allocation limits can also be adjusted using + ** [PRAGMA soft_heap_limit] and [PRAGMA hard_heap_limit]. + ** + ** ^(The heap limits are not enforced in the current implementation + ** if one or more of following conditions are true: + ** + **
    + **
  • The limit value is set to zero. + **
  • Memory accounting is disabled using a combination of the + ** [sqlite3_config]([SQLITE_CONFIG_MEMSTATUS],...) start-time option and + ** the [SQLITE_DEFAULT_MEMSTATUS] compile-time option. + **
  • An alternative page cache implementation is specified using + ** [sqlite3_config]([SQLITE_CONFIG_PCACHE2],...). + **
  • The page cache allocates from its own memory pool supplied + ** by [sqlite3_config]([SQLITE_CONFIG_PAGECACHE],...) rather than + ** from the heap. + **
)^ + ** + ** The circumstances under which SQLite will enforce the heap limits may + ** changes in future releases of SQLite. + */ + SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N); + SQLITE_API sqlite3_int64 sqlite3_hard_heap_limit64(sqlite3_int64 N); + + /* + ** CAPI3REF: Deprecated Soft Heap Limit Interface + ** DEPRECATED + ** + ** This is a deprecated version of the [sqlite3_soft_heap_limit64()] + ** interface. This routine is provided for historical compatibility + ** only. All new applications should use the + ** [sqlite3_soft_heap_limit64()] interface rather than this one. + */ + SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N); + + /* + ** CAPI3REF: Extract Metadata About A Column Of A Table + ** METHOD: sqlite3 + ** + ** ^(The sqlite3_table_column_metadata(X,D,T,C,....) routine returns + ** information about column C of table T in database D + ** on [database connection] X.)^ ^The sqlite3_table_column_metadata() + ** interface returns SQLITE_OK and fills in the non-NULL pointers in + ** the final five arguments with appropriate values if the specified + ** column exists. ^The sqlite3_table_column_metadata() interface returns + ** SQLITE_ERROR if the specified column does not exist. + ** ^If the column-name parameter to sqlite3_table_column_metadata() is a + ** NULL pointer, then this routine simply checks for the existence of the + ** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it + ** does not. If the table name parameter T in a call to + ** sqlite3_table_column_metadata(X,D,T,C,...) is NULL then the result is + ** undefined behavior. + ** + ** ^The column is identified by the second, third and fourth parameters to + ** this function. ^(The second parameter is either the name of the database + ** (i.e. "main", "temp", or an attached database) containing the specified + ** table or NULL.)^ ^If it is NULL, then all attached databases are searched + ** for the table using the same algorithm used by the database engine to + ** resolve unqualified table references. + ** + ** ^The third and fourth parameters to this function are the table and column + ** name of the desired column, respectively. + ** + ** ^Metadata is returned by writing to the memory locations passed as the 5th + ** and subsequent parameters to this function. ^Any of these arguments may be + ** NULL, in which case the corresponding element of metadata is omitted. + ** + ** ^(
+ ** + **
Parameter Output
Type
Description + ** + **
5th const char* Data type + **
6th const char* Name of default collation sequence + **
7th int True if column has a NOT NULL constraint + **
8th int True if column is part of the PRIMARY KEY + **
9th int True if column is [AUTOINCREMENT] + **
+ **
)^ + ** + ** ^The memory pointed to by the character pointers returned for the + ** declaration type and collation sequence is valid until the next + ** call to any SQLite API function. + ** + ** ^If the specified table is actually a view, an [error code] is returned. + ** + ** ^If the specified column is "rowid", "oid" or "_rowid_" and the table + ** is not a [WITHOUT ROWID] table and an + ** [INTEGER PRIMARY KEY] column has been explicitly declared, then the output + ** parameters are set for the explicitly declared column. ^(If there is no + ** [INTEGER PRIMARY KEY] column, then the outputs + ** for the [rowid] are set as follows: + ** + **
+    **     data type: "INTEGER"
+    **     collation sequence: "BINARY"
+    **     not null: 0
+    **     primary key: 1
+    **     auto increment: 0
+    ** 
)^ + ** + ** ^This function causes all database schemas to be read from disk and + ** parsed, if that has not already been done, and returns an error if + ** any errors are encountered while loading the schema. + */ + SQLITE_API int sqlite3_table_column_metadata(sqlite3* db, /* Connection handle */ + const char* zDbName, /* Database name or NULL */ + const char* zTableName, /* Table name */ + const char* zColumnName, /* Column name */ + char const** pzDataType, /* OUTPUT: Declared data type */ + char const** pzCollSeq, /* OUTPUT: Collation sequence name */ + int* pNotNull, /* OUTPUT: True if NOT NULL constraint exists */ + int* pPrimaryKey, /* OUTPUT: True if column part of PK */ + int* pAutoinc /* OUTPUT: True if column is auto-increment */ + ); + + /* + ** CAPI3REF: Load An Extension + ** METHOD: sqlite3 + ** + ** ^This interface loads an SQLite extension library from the named file. + ** + ** ^The sqlite3_load_extension() interface attempts to load an + ** [SQLite extension] library contained in the file zFile. If + ** the file cannot be loaded directly, attempts are made to load + ** with various operating-system specific extensions added. + ** So for example, if "samplelib" cannot be loaded, then names like + ** "samplelib.so" or "samplelib.dylib" or "samplelib.dll" might + ** be tried also. + ** + ** ^The entry point is zProc. + ** ^(zProc may be 0, in which case SQLite will try to come up with an + ** entry point name on its own. It first tries "sqlite3_extension_init". + ** If that does not work, it constructs a name "sqlite3_X_init" where the + ** X is consists of the lower-case equivalent of all ASCII alphabetic + ** characters in the filename from the last "/" to the first following + ** "." and omitting any initial "lib".)^ + ** ^The sqlite3_load_extension() interface returns + ** [SQLITE_OK] on success and [SQLITE_ERROR] if something goes wrong. + ** ^If an error occurs and pzErrMsg is not 0, then the + ** [sqlite3_load_extension()] interface shall attempt to + ** fill *pzErrMsg with error message text stored in memory + ** obtained from [sqlite3_malloc()]. The calling function + ** should free this memory by calling [sqlite3_free()]. + ** + ** ^Extension loading must be enabled using + ** [sqlite3_enable_load_extension()] or + ** [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],1,NULL) + ** prior to calling this API, + ** otherwise an error will be returned. + ** + ** Security warning: It is recommended that the + ** [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method be used to enable only this + ** interface. The use of the [sqlite3_enable_load_extension()] interface + ** should be avoided. This will keep the SQL function [load_extension()] + ** disabled and prevent SQL injections from giving attackers + ** access to extension loading capabilities. + ** + ** See also the [load_extension() SQL function]. + */ + SQLITE_API int sqlite3_load_extension(sqlite3* db, /* Load the extension into this database connection */ + const char* zFile, /* Name of the shared library containing extension */ + const char* zProc, /* Entry point. Derived from zFile if 0 */ + char** pzErrMsg /* Put error message here if not 0 */ + ); + + /* + ** CAPI3REF: Enable Or Disable Extension Loading + ** METHOD: sqlite3 + ** + ** ^So as not to open security holes in older applications that are + ** unprepared to deal with [extension loading], and as a means of disabling + ** [extension loading] while evaluating user-entered SQL, the following API + ** is provided to turn the [sqlite3_load_extension()] mechanism on and off. + ** + ** ^Extension loading is off by default. + ** ^Call the sqlite3_enable_load_extension() routine with onoff==1 + ** to turn extension loading on and call it with onoff==0 to turn + ** it back off again. + ** + ** ^This interface enables or disables both the C-API + ** [sqlite3_load_extension()] and the SQL function [load_extension()]. + ** ^(Use [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],..) + ** to enable or disable only the C-API.)^ + ** + ** Security warning: It is recommended that extension loading + ** be enabled using the [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method + ** rather than this interface, so the [load_extension()] SQL function + ** remains disabled. This will prevent SQL injections from giving attackers + ** access to extension loading capabilities. + */ + SQLITE_API int sqlite3_enable_load_extension(sqlite3* db, int onoff); + + /* + ** CAPI3REF: Automatically Load Statically Linked Extensions + ** + ** ^This interface causes the xEntryPoint() function to be invoked for + ** each new [database connection] that is created. The idea here is that + ** xEntryPoint() is the entry point for a statically linked [SQLite extension] + ** that is to be automatically loaded into all new database connections. + ** + ** ^(Even though the function prototype shows that xEntryPoint() takes + ** no arguments and returns void, SQLite invokes xEntryPoint() with three + ** arguments and expects an integer result as if the signature of the + ** entry point where as follows: + ** + **
+    **    int xEntryPoint(
+    **      sqlite3 *db,
+    **      const char **pzErrMsg,
+    **      const struct sqlite3_api_routines *pThunk
+    **    );
+    ** 
)^ + ** + ** If the xEntryPoint routine encounters an error, it should make *pzErrMsg + ** point to an appropriate error message (obtained from [sqlite3_mprintf()]) + ** and return an appropriate [error code]. ^SQLite ensures that *pzErrMsg + ** is NULL before calling the xEntryPoint(). ^SQLite will invoke + ** [sqlite3_free()] on *pzErrMsg after xEntryPoint() returns. ^If any + ** xEntryPoint() returns an error, the [sqlite3_open()], [sqlite3_open16()], + ** or [sqlite3_open_v2()] call that provoked the xEntryPoint() will fail. + ** + ** ^Calling sqlite3_auto_extension(X) with an entry point X that is already + ** on the list of automatic extensions is a harmless no-op. ^No entry point + ** will be called more than once for each database connection that is opened. + ** + ** See also: [sqlite3_reset_auto_extension()] + ** and [sqlite3_cancel_auto_extension()] + */ + SQLITE_API int sqlite3_auto_extension(void (*xEntryPoint)(void)); + + /* + ** CAPI3REF: Cancel Automatic Extension Loading + ** + ** ^The [sqlite3_cancel_auto_extension(X)] interface unregisters the + ** initialization routine X that was registered using a prior call to + ** [sqlite3_auto_extension(X)]. ^The [sqlite3_cancel_auto_extension(X)] + ** routine returns 1 if initialization routine X was successfully + ** unregistered and it returns 0 if X was not on the list of initialization + ** routines. + */ + SQLITE_API int sqlite3_cancel_auto_extension(void (*xEntryPoint)(void)); + + /* + ** CAPI3REF: Reset Automatic Extension Loading + ** + ** ^This interface disables all automatic extensions previously + ** registered using [sqlite3_auto_extension()]. + */ + SQLITE_API void sqlite3_reset_auto_extension(void); + + /* + ** The interface to the virtual-table mechanism is currently considered + ** to be experimental. The interface might change in incompatible ways. + ** If this is a problem for you, do not use the interface at this time. + ** + ** When the virtual-table mechanism stabilizes, we will declare the + ** interface fixed, support it indefinitely, and remove this comment. + */ + + /* + ** Structures used by the virtual table interface + */ + typedef struct sqlite3_vtab sqlite3_vtab; + typedef struct sqlite3_index_info sqlite3_index_info; + typedef struct sqlite3_vtab_cursor sqlite3_vtab_cursor; + typedef struct sqlite3_module sqlite3_module; + + /* + ** CAPI3REF: Virtual Table Object + ** KEYWORDS: sqlite3_module {virtual table module} + ** + ** This structure, sometimes called a "virtual table module", + ** defines the implementation of a [virtual table]. + ** This structure consists mostly of methods for the module. + ** + ** ^A virtual table module is created by filling in a persistent + ** instance of this structure and passing a pointer to that instance + ** to [sqlite3_create_module()] or [sqlite3_create_module_v2()]. + ** ^The registration remains valid until it is replaced by a different + ** module or until the [database connection] closes. The content + ** of this structure must not change while it is registered with + ** any database connection. + */ + struct sqlite3_module + { + int iVersion; + int (*xCreate)(sqlite3*, void* pAux, int argc, const char* const* argv, sqlite3_vtab** ppVTab, char**); + int (*xConnect)(sqlite3*, void* pAux, int argc, const char* const* argv, sqlite3_vtab** ppVTab, char**); + int (*xBestIndex)(sqlite3_vtab* pVTab, sqlite3_index_info*); + int (*xDisconnect)(sqlite3_vtab* pVTab); + int (*xDestroy)(sqlite3_vtab* pVTab); + int (*xOpen)(sqlite3_vtab* pVTab, sqlite3_vtab_cursor** ppCursor); + int (*xClose)(sqlite3_vtab_cursor*); + int (*xFilter)(sqlite3_vtab_cursor*, int idxNum, const char* idxStr, int argc, sqlite3_value** argv); + int (*xNext)(sqlite3_vtab_cursor*); + int (*xEof)(sqlite3_vtab_cursor*); + int (*xColumn)(sqlite3_vtab_cursor*, sqlite3_context*, int); + int (*xRowid)(sqlite3_vtab_cursor*, sqlite3_int64* pRowid); + int (*xUpdate)(sqlite3_vtab*, int, sqlite3_value**, sqlite3_int64*); + int (*xBegin)(sqlite3_vtab* pVTab); + int (*xSync)(sqlite3_vtab* pVTab); + int (*xCommit)(sqlite3_vtab* pVTab); + int (*xRollback)(sqlite3_vtab* pVTab); + int (*xFindFunction)(sqlite3_vtab* pVtab, + int nArg, + const char* zName, + void (**pxFunc)(sqlite3_context*, int, sqlite3_value**), + void** ppArg); + int (*xRename)(sqlite3_vtab* pVtab, const char* zNew); + /* The methods above are in version 1 of the sqlite_module object. Those + ** below are for version 2 and greater. */ + int (*xSavepoint)(sqlite3_vtab* pVTab, int); + int (*xRelease)(sqlite3_vtab* pVTab, int); + int (*xRollbackTo)(sqlite3_vtab* pVTab, int); + /* The methods above are in versions 1 and 2 of the sqlite_module object. + ** Those below are for version 3 and greater. */ + int (*xShadowName)(const char*); + }; + + /* + ** CAPI3REF: Virtual Table Indexing Information + ** KEYWORDS: sqlite3_index_info + ** + ** The sqlite3_index_info structure and its substructures is used as part + ** of the [virtual table] interface to + ** pass information into and receive the reply from the [xBestIndex] + ** method of a [virtual table module]. The fields under **Inputs** are the + ** inputs to xBestIndex and are read-only. xBestIndex inserts its + ** results into the **Outputs** fields. + ** + ** ^(The aConstraint[] array records WHERE clause constraints of the form: + ** + **
column OP expr
+ ** + ** where OP is =, <, <=, >, or >=.)^ ^(The particular operator is + ** stored in aConstraint[].op using one of the + ** [SQLITE_INDEX_CONSTRAINT_EQ | SQLITE_INDEX_CONSTRAINT_ values].)^ + ** ^(The index of the column is stored in + ** aConstraint[].iColumn.)^ ^(aConstraint[].usable is TRUE if the + ** expr on the right-hand side can be evaluated (and thus the constraint + ** is usable) and false if it cannot.)^ + ** + ** ^The optimizer automatically inverts terms of the form "expr OP column" + ** and makes other simplifications to the WHERE clause in an attempt to + ** get as many WHERE clause terms into the form shown above as possible. + ** ^The aConstraint[] array only reports WHERE clause terms that are + ** relevant to the particular virtual table being queried. + ** + ** ^Information about the ORDER BY clause is stored in aOrderBy[]. + ** ^Each term of aOrderBy records a column of the ORDER BY clause. + ** + ** The colUsed field indicates which columns of the virtual table may be + ** required by the current scan. Virtual table columns are numbered from + ** zero in the order in which they appear within the CREATE TABLE statement + ** passed to sqlite3_declare_vtab(). For the first 63 columns (columns 0-62), + ** the corresponding bit is set within the colUsed mask if the column may be + ** required by SQLite. If the table has at least 64 columns and any column + ** to the right of the first 63 is required, then bit 63 of colUsed is also + ** set. In other words, column iCol may be required if the expression + ** (colUsed & ((sqlite3_uint64)1 << (iCol>=63 ? 63 : iCol))) evaluates to + ** non-zero. + ** + ** The [xBestIndex] method must fill aConstraintUsage[] with information + ** about what parameters to pass to xFilter. ^If argvIndex>0 then + ** the right-hand side of the corresponding aConstraint[] is evaluated + ** and becomes the argvIndex-th entry in argv. ^(If aConstraintUsage[].omit + ** is true, then the constraint is assumed to be fully handled by the + ** virtual table and might not be checked again by the byte code.)^ ^(The + ** aConstraintUsage[].omit flag is an optimization hint. When the omit flag + ** is left in its default setting of false, the constraint will always be + ** checked separately in byte code. If the omit flag is change to true, then + ** the constraint may or may not be checked in byte code. In other words, + ** when the omit flag is true there is no guarantee that the constraint will + ** not be checked again using byte code.)^ + ** + ** ^The idxNum and idxPtr values are recorded and passed into the + ** [xFilter] method. + ** ^[sqlite3_free()] is used to free idxPtr if and only if + ** needToFreeIdxPtr is true. + ** + ** ^The orderByConsumed means that output from [xFilter]/[xNext] will occur in + ** the correct order to satisfy the ORDER BY clause so that no separate + ** sorting step is required. + ** + ** ^The estimatedCost value is an estimate of the cost of a particular + ** strategy. A cost of N indicates that the cost of the strategy is similar + ** to a linear scan of an SQLite table with N rows. A cost of log(N) + ** indicates that the expense of the operation is similar to that of a + ** binary search on a unique indexed field of an SQLite table with N rows. + ** + ** ^The estimatedRows value is an estimate of the number of rows that + ** will be returned by the strategy. + ** + ** The xBestIndex method may optionally populate the idxFlags field with a + ** mask of SQLITE_INDEX_SCAN_* flags. Currently there is only one such flag - + ** SQLITE_INDEX_SCAN_UNIQUE. If the xBestIndex method sets this flag, SQLite + ** assumes that the strategy may visit at most one row. + ** + ** Additionally, if xBestIndex sets the SQLITE_INDEX_SCAN_UNIQUE flag, then + ** SQLite also assumes that if a call to the xUpdate() method is made as + ** part of the same statement to delete or update a virtual table row and the + ** implementation returns SQLITE_CONSTRAINT, then there is no need to rollback + ** any database changes. In other words, if the xUpdate() returns + ** SQLITE_CONSTRAINT, the database contents must be exactly as they were + ** before xUpdate was called. By contrast, if SQLITE_INDEX_SCAN_UNIQUE is not + ** set and xUpdate returns SQLITE_CONSTRAINT, any database changes made by + ** the xUpdate method are automatically rolled back by SQLite. + ** + ** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info + ** structure for SQLite [version 3.8.2] ([dateof:3.8.2]). + ** If a virtual table extension is + ** used with an SQLite version earlier than 3.8.2, the results of attempting + ** to read or write the estimatedRows field are undefined (but are likely + ** to include crashing the application). The estimatedRows field should + ** therefore only be used if [sqlite3_libversion_number()] returns a + ** value greater than or equal to 3008002. Similarly, the idxFlags field + ** was added for [version 3.9.0] ([dateof:3.9.0]). + ** It may therefore only be used if + ** sqlite3_libversion_number() returns a value greater than or equal to + ** 3009000. + */ + struct sqlite3_index_info + { + /* Inputs */ + int nConstraint; /* Number of entries in aConstraint */ + struct sqlite3_index_constraint + { + int iColumn; /* Column constrained. -1 for ROWID */ + unsigned char op; /* Constraint operator */ + unsigned char usable; /* True if this constraint is usable */ + int iTermOffset; /* Used internally - xBestIndex should ignore */ + } * aConstraint; /* Table of WHERE clause constraints */ + int nOrderBy; /* Number of terms in the ORDER BY clause */ + struct sqlite3_index_orderby + { + int iColumn; /* Column number */ + unsigned char desc; /* True for DESC. False for ASC. */ + } * aOrderBy; /* The ORDER BY clause */ + /* Outputs */ + struct sqlite3_index_constraint_usage + { + int argvIndex; /* if >0, constraint is part of argv to xFilter */ + unsigned char omit; /* Do not code a test for this constraint */ + } * aConstraintUsage; + int idxNum; /* Number used to identify the index */ + char* idxStr; /* String, possibly obtained from sqlite3_malloc */ + int needToFreeIdxStr; /* Free idxStr using sqlite3_free() if true */ + int orderByConsumed; /* True if output is already ordered */ + double estimatedCost; /* Estimated cost of using this index */ + /* Fields below are only available in SQLite 3.8.2 and later */ + sqlite3_int64 estimatedRows; /* Estimated number of rows returned */ + /* Fields below are only available in SQLite 3.9.0 and later */ + int idxFlags; /* Mask of SQLITE_INDEX_SCAN_* flags */ + /* Fields below are only available in SQLite 3.10.0 and later */ + sqlite3_uint64 colUsed; /* Input: Mask of columns used by statement */ + }; /* -** CAPI3REF: Commit And Rollback Notification Callbacks -** METHOD: sqlite3 +** CAPI3REF: Virtual Table Scan Flags ** -** ^The sqlite3_commit_hook() interface registers a callback -** function to be invoked whenever a transaction is [COMMIT | committed]. -** ^Any callback set by a previous call to sqlite3_commit_hook() -** for the same database connection is overridden. -** ^The sqlite3_rollback_hook() interface registers a callback -** function to be invoked whenever a transaction is [ROLLBACK | rolled back]. -** ^Any callback set by a previous call to sqlite3_rollback_hook() -** for the same database connection is overridden. -** ^The pArg argument is passed through to the callback. -** ^If the callback on a commit hook function returns non-zero, -** then the commit is converted into a rollback. -** -** ^The sqlite3_commit_hook(D,C,P) and sqlite3_rollback_hook(D,C,P) functions -** return the P argument from the previous call of the same function -** on the same [database connection] D, or NULL for -** the first call for each function on D. -** -** The commit and rollback hook callbacks are not reentrant. -** The callback implementation must not do anything that will modify -** the database connection that invoked the callback. Any actions -** to modify the database connection must be deferred until after the -** completion of the [sqlite3_step()] call that triggered the commit -** or rollback hook in the first place. -** Note that running any other SQL statements, including SELECT statements, -** or merely calling [sqlite3_prepare_v2()] and [sqlite3_step()] will modify -** the database connections for the meaning of "modify" in this paragraph. -** -** ^Registering a NULL function disables the callback. -** -** ^When the commit hook callback routine returns zero, the [COMMIT] -** operation is allowed to continue normally. ^If the commit hook -** returns non-zero, then the [COMMIT] is converted into a [ROLLBACK]. -** ^The rollback hook is invoked on a rollback that results from a commit -** hook returning non-zero, just as it would be with any other rollback. -** -** ^For the purposes of this API, a transaction is said to have been -** rolled back if an explicit "ROLLBACK" statement is executed, or -** an error or constraint causes an implicit rollback to occur. -** ^The rollback callback is not invoked if a transaction is -** automatically rolled back because the database connection is closed. -** -** See also the [sqlite3_update_hook()] interface. +** Virtual table implementations are allowed to set the +** [sqlite3_index_info].idxFlags field to some combination of +** these bits. */ -SQLITE_API void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*); -SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); +#define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */ /* -** CAPI3REF: Autovacuum Compaction Amount Callback -** METHOD: sqlite3 +** CAPI3REF: Virtual Table Constraint Operator Codes ** -** ^The sqlite3_autovacuum_pages(D,C,P,X) interface registers a callback -** function C that is invoked prior to each autovacuum of the database -** file. ^The callback is passed a copy of the generic data pointer (P), -** the schema-name of the attached database that is being autovacuumed, -** the the size of the database file in pages, the number of free pages, -** and the number of bytes per page, respectively. The callback should -** return the number of free pages that should be removed by the -** autovacuum. ^If the callback returns zero, then no autovacuum happens. -** ^If the value returned is greater than or equal to the number of -** free pages, then a complete autovacuum happens. -** -**

^If there are multiple ATTACH-ed database files that are being -** modified as part of a transaction commit, then the autovacuum pages -** callback is invoked separately for each file. -** -**

The callback is not reentrant. The callback function should -** not attempt to invoke any other SQLite interface. If it does, bad -** things may happen, including segmentation faults and corrupt database -** files. The callback function should be a simple function that -** does some arithmetic on its input parameters and returns a result. -** -** ^The X parameter to sqlite3_autovacuum_pages(D,C,P,X) is an optional -** destructor for the P parameter. ^If X is not NULL, then X(P) is -** invoked whenever the database connection closes or when the callback -** is overwritten by another invocation of sqlite3_autovacuum_pages(). -** -**

^There is only one autovacuum pages callback per database connection. -** ^Each call to the sqlite3_autovacuum_pages() interface overrides all -** previous invocations for that database connection. ^If the callback -** argument (C) to sqlite3_autovacuum_pages(D,C,P,X) is a NULL pointer, -** then the autovacuum steps callback is cancelled. The return value -** from sqlite3_autovacuum_pages() is normally SQLITE_OK, but might -** be some other error code if something goes wrong. The current -** implementation will only return SQLITE_OK or SQLITE_MISUSE, but other -** return codes might be added in future releases. -** -**

If no autovacuum pages callback is specified (the usual case) or -** a NULL pointer is provided for the callback, -** then the default behavior is to vacuum all free pages. So, in other -** words, the default behavior is the same as if the callback function -** were something like this: -** -**

-**     unsigned int demonstration_autovac_pages_callback(
-**       void *pClientData,
-**       const char *zSchema,
-**       unsigned int nDbPage,
-**       unsigned int nFreePage,
-**       unsigned int nBytePerPage
-**     ){
-**       return nFreePage;
-**     }
-** 
-*/ -SQLITE_API int sqlite3_autovacuum_pages( - sqlite3 *db, - unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int), - void*, - void(*)(void*) -); - - -/* -** CAPI3REF: Data Change Notification Callbacks -** METHOD: sqlite3 +** These macros define the allowed values for the +** [sqlite3_index_info].aConstraint[].op field. Each value represents +** an operator that is part of a constraint term in the WHERE clause of +** a query that uses a [virtual table]. ** -** ^The sqlite3_update_hook() interface registers a callback function -** with the [database connection] identified by the first argument -** to be invoked whenever a row is updated, inserted or deleted in -** a [rowid table]. -** ^Any callback set by a previous call to this function -** for the same database connection is overridden. -** -** ^The second argument is a pointer to the function to invoke when a -** row is updated, inserted or deleted in a rowid table. -** ^The first argument to the callback is a copy of the third argument -** to sqlite3_update_hook(). -** ^The second callback argument is one of [SQLITE_INSERT], [SQLITE_DELETE], -** or [SQLITE_UPDATE], depending on the operation that caused the callback -** to be invoked. -** ^The third and fourth arguments to the callback contain pointers to the -** database and table name containing the affected row. -** ^The final callback parameter is the [rowid] of the row. -** ^In the case of an update, this is the [rowid] after the update takes place. -** -** ^(The update hook is not invoked when internal system tables are -** modified (i.e. sqlite_sequence).)^ -** ^The update hook is not invoked when [WITHOUT ROWID] tables are modified. -** -** ^In the current implementation, the update hook -** is not invoked when conflicting rows are deleted because of an -** [ON CONFLICT | ON CONFLICT REPLACE] clause. ^Nor is the update hook -** invoked when rows are deleted using the [truncate optimization]. -** The exceptions defined in this paragraph might change in a future -** release of SQLite. +** ^The left-hand operand of the operator is given by the corresponding +** aConstraint[].iColumn field. ^An iColumn of -1 indicates the left-hand +** operand is the rowid. +** The SQLITE_INDEX_CONSTRAINT_LIMIT and SQLITE_INDEX_CONSTRAINT_OFFSET +** operators have no left-hand operand, and so for those operators the +** corresponding aConstraint[].iColumn is meaningless and should not be +** used. ** -** The update hook implementation must not do anything that will modify -** the database connection that invoked the update hook. Any actions -** to modify the database connection must be deferred until after the -** completion of the [sqlite3_step()] call that triggered the update hook. -** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their -** database connections for the meaning of "modify" in this paragraph. +** All operator values from SQLITE_INDEX_CONSTRAINT_FUNCTION through +** value 255 are reserved to represent functions that are overloaded +** by the [xFindFunction|xFindFunction method] of the virtual table +** implementation. ** -** ^The sqlite3_update_hook(D,C,P) function -** returns the P argument from the previous call -** on the same [database connection] D, or NULL for -** the first call on D. +** The right-hand operands for each constraint might be accessible using +** the [sqlite3_vtab_rhs_value()] interface. Usually the right-hand +** operand is only available if it appears as a single constant literal +** in the input SQL. If the right-hand operand is another column or an +** expression (even a constant expression) or a parameter, then the +** sqlite3_vtab_rhs_value() probably will not be able to extract it. +** ^The SQLITE_INDEX_CONSTRAINT_ISNULL and +** SQLITE_INDEX_CONSTRAINT_ISNOTNULL operators have no right-hand operand +** and hence calls to sqlite3_vtab_rhs_value() for those operators will +** always return SQLITE_NOTFOUND. ** -** See also the [sqlite3_commit_hook()], [sqlite3_rollback_hook()], -** and [sqlite3_preupdate_hook()] interfaces. -*/ -SQLITE_API void *sqlite3_update_hook( - sqlite3*, - void(*)(void *,int ,char const *,char const *,sqlite3_int64), - void* -); - -/* -** CAPI3REF: Enable Or Disable Shared Pager Cache -** -** ^(This routine enables or disables the sharing of the database cache -** and schema data structures between [database connection | connections] -** to the same database. Sharing is enabled if the argument is true -** and disabled if the argument is false.)^ -** -** ^Cache sharing is enabled and disabled for an entire process. -** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]). -** In prior versions of SQLite, -** sharing was enabled or disabled for each thread separately. -** -** ^(The cache sharing mode set by this interface effects all subsequent -** calls to [sqlite3_open()], [sqlite3_open_v2()], and [sqlite3_open16()]. -** Existing database connections continue to use the sharing mode -** that was in effect at the time they were opened.)^ -** -** ^(This routine returns [SQLITE_OK] if shared cache was enabled or disabled -** successfully. An [error code] is returned otherwise.)^ -** -** ^Shared cache is disabled by default. It is recommended that it stay -** that way. In other words, do not use this routine. This interface -** continues to be provided for historical compatibility, but its use is -** discouraged. Any use of shared cache is discouraged. If shared cache -** must be used, it is recommended that shared cache only be enabled for -** individual database connections using the [sqlite3_open_v2()] interface -** with the [SQLITE_OPEN_SHAREDCACHE] flag. -** -** Note: This method is disabled on MacOS X 10.7 and iOS version 5.0 -** and will always return SQLITE_MISUSE. On those systems, -** shared cache mode should be enabled per-database connection via -** [sqlite3_open_v2()] with [SQLITE_OPEN_SHAREDCACHE]. -** -** This interface is threadsafe on processors where writing a -** 32-bit integer is atomic. -** -** See Also: [SQLite Shared-Cache Mode] -*/ -SQLITE_API int sqlite3_enable_shared_cache(int); - -/* -** CAPI3REF: Attempt To Free Heap Memory -** -** ^The sqlite3_release_memory() interface attempts to free N bytes -** of heap memory by deallocating non-essential memory allocations -** held by the database library. Memory used to cache database -** pages to improve performance is an example of non-essential memory. -** ^sqlite3_release_memory() returns the number of bytes actually freed, -** which might be more or less than the amount requested. -** ^The sqlite3_release_memory() routine is a no-op returning zero -** if SQLite is not compiled with [SQLITE_ENABLE_MEMORY_MANAGEMENT]. -** -** See also: [sqlite3_db_release_memory()] +** The collating sequence to be used for comparison can be found using +** the [sqlite3_vtab_collation()] interface. For most real-world virtual +** tables, the collating sequence of constraints does not matter (for example +** because the constraints are numeric) and so the sqlite3_vtab_collation() +** interface is no commonly needed. */ -SQLITE_API int sqlite3_release_memory(int); +#define SQLITE_INDEX_CONSTRAINT_EQ 2 +#define SQLITE_INDEX_CONSTRAINT_GT 4 +#define SQLITE_INDEX_CONSTRAINT_LE 8 +#define SQLITE_INDEX_CONSTRAINT_LT 16 +#define SQLITE_INDEX_CONSTRAINT_GE 32 +#define SQLITE_INDEX_CONSTRAINT_MATCH 64 +#define SQLITE_INDEX_CONSTRAINT_LIKE 65 +#define SQLITE_INDEX_CONSTRAINT_GLOB 66 +#define SQLITE_INDEX_CONSTRAINT_REGEXP 67 +#define SQLITE_INDEX_CONSTRAINT_NE 68 +#define SQLITE_INDEX_CONSTRAINT_ISNOT 69 +#define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70 +#define SQLITE_INDEX_CONSTRAINT_ISNULL 71 +#define SQLITE_INDEX_CONSTRAINT_IS 72 +#define SQLITE_INDEX_CONSTRAINT_LIMIT 73 +#define SQLITE_INDEX_CONSTRAINT_OFFSET 74 +#define SQLITE_INDEX_CONSTRAINT_FUNCTION 150 + + /* + ** CAPI3REF: Register A Virtual Table Implementation + ** METHOD: sqlite3 + ** + ** ^These routines are used to register a new [virtual table module] name. + ** ^Module names must be registered before + ** creating a new [virtual table] using the module and before using a + ** preexisting [virtual table] for the module. + ** + ** ^The module name is registered on the [database connection] specified + ** by the first parameter. ^The name of the module is given by the + ** second parameter. ^The third parameter is a pointer to + ** the implementation of the [virtual table module]. ^The fourth + ** parameter is an arbitrary client data pointer that is passed through + ** into the [xCreate] and [xConnect] methods of the virtual table module + ** when a new virtual table is be being created or reinitialized. + ** + ** ^The sqlite3_create_module_v2() interface has a fifth parameter which + ** is a pointer to a destructor for the pClientData. ^SQLite will + ** invoke the destructor function (if it is not NULL) when SQLite + ** no longer needs the pClientData pointer. ^The destructor will also + ** be invoked if the call to sqlite3_create_module_v2() fails. + ** ^The sqlite3_create_module() + ** interface is equivalent to sqlite3_create_module_v2() with a NULL + ** destructor. + ** + ** ^If the third parameter (the pointer to the sqlite3_module object) is + ** NULL then no new module is created and any existing modules with the + ** same name are dropped. + ** + ** See also: [sqlite3_drop_modules()] + */ + SQLITE_API int sqlite3_create_module(sqlite3* db, /* SQLite connection to register module with */ + const char* zName, /* Name of the module */ + const sqlite3_module* p, /* Methods for the module */ + void* pClientData /* Client data for xCreate/xConnect */ + ); + SQLITE_API int sqlite3_create_module_v2(sqlite3* db, /* SQLite connection to register module with */ + const char* zName, /* Name of the module */ + const sqlite3_module* p, /* Methods for the module */ + void* pClientData, /* Client data for xCreate/xConnect */ + void (*xDestroy)(void*) /* Module destructor function */ + ); + + /* + ** CAPI3REF: Remove Unnecessary Virtual Table Implementations + ** METHOD: sqlite3 + ** + ** ^The sqlite3_drop_modules(D,L) interface removes all virtual + ** table modules from database connection D except those named on list L. + ** The L parameter must be either NULL or a pointer to an array of pointers + ** to strings where the array is terminated by a single NULL pointer. + ** ^If the L parameter is NULL, then all virtual table modules are removed. + ** + ** See also: [sqlite3_create_module()] + */ + SQLITE_API int sqlite3_drop_modules(sqlite3* db, /* Remove modules from this connection */ + const char** azKeep /* Except, do not remove the ones named here */ + ); + + /* + ** CAPI3REF: Virtual Table Instance Object + ** KEYWORDS: sqlite3_vtab + ** + ** Every [virtual table module] implementation uses a subclass + ** of this object to describe a particular instance + ** of the [virtual table]. Each subclass will + ** be tailored to the specific needs of the module implementation. + ** The purpose of this superclass is to define certain fields that are + ** common to all module implementations. + ** + ** ^Virtual tables methods can set an error message by assigning a + ** string obtained from [sqlite3_mprintf()] to zErrMsg. The method should + ** take care that any prior string is freed by a call to [sqlite3_free()] + ** prior to assigning a new string to zErrMsg. ^After the error message + ** is delivered up to the client application, the string will be automatically + ** freed by sqlite3_free() and the zErrMsg field will be zeroed. + */ + struct sqlite3_vtab + { + const sqlite3_module* pModule; /* The module for this virtual table */ + int nRef; /* Number of open cursors */ + char* zErrMsg; /* Error message from sqlite3_mprintf() */ + /* Virtual table implementations will typically add additional fields */ + }; + + /* + ** CAPI3REF: Virtual Table Cursor Object + ** KEYWORDS: sqlite3_vtab_cursor {virtual table cursor} + ** + ** Every [virtual table module] implementation uses a subclass of the + ** following structure to describe cursors that point into the + ** [virtual table] and are used + ** to loop through the virtual table. Cursors are created using the + ** [sqlite3_module.xOpen | xOpen] method of the module and are destroyed + ** by the [sqlite3_module.xClose | xClose] method. Cursors are used + ** by the [xFilter], [xNext], [xEof], [xColumn], and [xRowid] methods + ** of the module. Each module implementation will define + ** the content of a cursor structure to suit its own needs. + ** + ** This superclass exists in order to define fields of the cursor that + ** are common to all implementations. + */ + struct sqlite3_vtab_cursor + { + sqlite3_vtab* pVtab; /* Virtual table of this cursor */ + /* Virtual table implementations will typically add additional fields */ + }; + + /* + ** CAPI3REF: Declare The Schema Of A Virtual Table + ** + ** ^The [xCreate] and [xConnect] methods of a + ** [virtual table module] call this interface + ** to declare the format (the names and datatypes of the columns) of + ** the virtual tables they implement. + */ + SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char* zSQL); + + /* + ** CAPI3REF: Overload A Function For A Virtual Table + ** METHOD: sqlite3 + ** + ** ^(Virtual tables can provide alternative implementations of functions + ** using the [xFindFunction] method of the [virtual table module]. + ** But global versions of those functions + ** must exist in order to be overloaded.)^ + ** + ** ^(This API makes sure a global version of a function with a particular + ** name and number of parameters exists. If no such function exists + ** before this API is called, a new function is created.)^ ^The implementation + ** of the new function always causes an exception to be thrown. So + ** the new function is not good for anything by itself. Its only + ** purpose is to be a placeholder function that can be overloaded + ** by a [virtual table]. + */ + SQLITE_API int sqlite3_overload_function(sqlite3*, const char* zFuncName, int nArg); + + /* + ** The interface to the virtual-table mechanism defined above (back up + ** to a comment remarkably similar to this one) is currently considered + ** to be experimental. The interface might change in incompatible ways. + ** If this is a problem for you, do not use the interface at this time. + ** + ** When the virtual-table mechanism stabilizes, we will declare the + ** interface fixed, support it indefinitely, and remove this comment. + */ + + /* + ** CAPI3REF: A Handle To An Open BLOB + ** KEYWORDS: {BLOB handle} {BLOB handles} + ** + ** An instance of this object represents an open BLOB on which + ** [sqlite3_blob_open | incremental BLOB I/O] can be performed. + ** ^Objects of this type are created by [sqlite3_blob_open()] + ** and destroyed by [sqlite3_blob_close()]. + ** ^The [sqlite3_blob_read()] and [sqlite3_blob_write()] interfaces + ** can be used to read or write small subsections of the BLOB. + ** ^The [sqlite3_blob_bytes()] interface returns the size of the BLOB in bytes. + */ + typedef struct sqlite3_blob sqlite3_blob; + + /* + ** CAPI3REF: Open A BLOB For Incremental I/O + ** METHOD: sqlite3 + ** CONSTRUCTOR: sqlite3_blob + ** + ** ^(This interfaces opens a [BLOB handle | handle] to the BLOB located + ** in row iRow, column zColumn, table zTable in database zDb; + ** in other words, the same BLOB that would be selected by: + ** + **
+    **     SELECT zColumn FROM zDb.zTable WHERE [rowid] = iRow;
+    ** 
)^ + ** + ** ^(Parameter zDb is not the filename that contains the database, but + ** rather the symbolic name of the database. For attached databases, this is + ** the name that appears after the AS keyword in the [ATTACH] statement. + ** For the main database file, the database name is "main". For TEMP + ** tables, the database name is "temp".)^ + ** + ** ^If the flags parameter is non-zero, then the BLOB is opened for read + ** and write access. ^If the flags parameter is zero, the BLOB is opened for + ** read-only access. + ** + ** ^(On success, [SQLITE_OK] is returned and the new [BLOB handle] is stored + ** in *ppBlob. Otherwise an [error code] is returned and, unless the error + ** code is SQLITE_MISUSE, *ppBlob is set to NULL.)^ ^This means that, provided + ** the API is not misused, it is always safe to call [sqlite3_blob_close()] + ** on *ppBlob after this function it returns. + ** + ** This function fails with SQLITE_ERROR if any of the following are true: + **
    + **
  • ^(Database zDb does not exist)^, + **
  • ^(Table zTable does not exist within database zDb)^, + **
  • ^(Table zTable is a WITHOUT ROWID table)^, + **
  • ^(Column zColumn does not exist)^, + **
  • ^(Row iRow is not present in the table)^, + **
  • ^(The specified column of row iRow contains a value that is not + ** a TEXT or BLOB value)^, + **
  • ^(Column zColumn is part of an index, PRIMARY KEY or UNIQUE + ** constraint and the blob is being opened for read/write access)^, + **
  • ^([foreign key constraints | Foreign key constraints] are enabled, + ** column zColumn is part of a [child key] definition and the blob is + ** being opened for read/write access)^. + **
+ ** + ** ^Unless it returns SQLITE_MISUSE, this function sets the + ** [database connection] error code and message accessible via + ** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions. + ** + ** A BLOB referenced by sqlite3_blob_open() may be read using the + ** [sqlite3_blob_read()] interface and modified by using + ** [sqlite3_blob_write()]. The [BLOB handle] can be moved to a + ** different row of the same table using the [sqlite3_blob_reopen()] + ** interface. However, the column, table, or database of a [BLOB handle] + ** cannot be changed after the [BLOB handle] is opened. + ** + ** ^(If the row that a BLOB handle points to is modified by an + ** [UPDATE], [DELETE], or by [ON CONFLICT] side-effects + ** then the BLOB handle is marked as "expired". + ** This is true if any column of the row is changed, even a column + ** other than the one the BLOB handle is open on.)^ + ** ^Calls to [sqlite3_blob_read()] and [sqlite3_blob_write()] for + ** an expired BLOB handle fail with a return code of [SQLITE_ABORT]. + ** ^(Changes written into a BLOB prior to the BLOB expiring are not + ** rolled back by the expiration of the BLOB. Such changes will eventually + ** commit if the transaction continues to completion.)^ + ** + ** ^Use the [sqlite3_blob_bytes()] interface to determine the size of + ** the opened blob. ^The size of a blob may not be changed by this + ** interface. Use the [UPDATE] SQL command to change the size of a + ** blob. + ** + ** ^The [sqlite3_bind_zeroblob()] and [sqlite3_result_zeroblob()] interfaces + ** and the built-in [zeroblob] SQL function may be used to create a + ** zero-filled blob to read or write using the incremental-blob interface. + ** + ** To avoid a resource leak, every open [BLOB handle] should eventually + ** be released by a call to [sqlite3_blob_close()]. + ** + ** See also: [sqlite3_blob_close()], + ** [sqlite3_blob_reopen()], [sqlite3_blob_read()], + ** [sqlite3_blob_bytes()], [sqlite3_blob_write()]. + */ + SQLITE_API int sqlite3_blob_open(sqlite3*, + const char* zDb, + const char* zTable, + const char* zColumn, + sqlite3_int64 iRow, + int flags, + sqlite3_blob** ppBlob); + + /* + ** CAPI3REF: Move a BLOB Handle to a New Row + ** METHOD: sqlite3_blob + ** + ** ^This function is used to move an existing [BLOB handle] so that it points + ** to a different row of the same database table. ^The new row is identified + ** by the rowid value passed as the second argument. Only the row can be + ** changed. ^The database, table and column on which the blob handle is open + ** remain the same. Moving an existing [BLOB handle] to a new row is + ** faster than closing the existing handle and opening a new one. + ** + ** ^(The new row must meet the same criteria as for [sqlite3_blob_open()] - + ** it must exist and there must be either a blob or text value stored in + ** the nominated column.)^ ^If the new row is not present in the table, or if + ** it does not contain a blob or text value, or if another error occurs, an + ** SQLite error code is returned and the blob handle is considered aborted. + ** ^All subsequent calls to [sqlite3_blob_read()], [sqlite3_blob_write()] or + ** [sqlite3_blob_reopen()] on an aborted blob handle immediately return + ** SQLITE_ABORT. ^Calling [sqlite3_blob_bytes()] on an aborted blob handle + ** always returns zero. + ** + ** ^This function sets the database handle error code and message. + */ + SQLITE_API int sqlite3_blob_reopen(sqlite3_blob*, sqlite3_int64); + + /* + ** CAPI3REF: Close A BLOB Handle + ** DESTRUCTOR: sqlite3_blob + ** + ** ^This function closes an open [BLOB handle]. ^(The BLOB handle is closed + ** unconditionally. Even if this routine returns an error code, the + ** handle is still closed.)^ + ** + ** ^If the blob handle being closed was opened for read-write access, and if + ** the database is in auto-commit mode and there are no other open read-write + ** blob handles or active write statements, the current transaction is + ** committed. ^If an error occurs while committing the transaction, an error + ** code is returned and the transaction rolled back. + ** + ** Calling this function with an argument that is not a NULL pointer or an + ** open blob handle results in undefined behaviour. ^Calling this routine + ** with a null pointer (such as would be returned by a failed call to + ** [sqlite3_blob_open()]) is a harmless no-op. ^Otherwise, if this function + ** is passed a valid open blob handle, the values returned by the + ** sqlite3_errcode() and sqlite3_errmsg() functions are set before returning. + */ + SQLITE_API int sqlite3_blob_close(sqlite3_blob*); + + /* + ** CAPI3REF: Return The Size Of An Open BLOB + ** METHOD: sqlite3_blob + ** + ** ^Returns the size in bytes of the BLOB accessible via the + ** successfully opened [BLOB handle] in its only argument. ^The + ** incremental blob I/O routines can only read or overwriting existing + ** blob content; they cannot change the size of a blob. + ** + ** This routine only works on a [BLOB handle] which has been created + ** by a prior successful call to [sqlite3_blob_open()] and which has not + ** been closed by [sqlite3_blob_close()]. Passing any other pointer in + ** to this routine results in undefined and probably undesirable behavior. + */ + SQLITE_API int sqlite3_blob_bytes(sqlite3_blob*); + + /* + ** CAPI3REF: Read Data From A BLOB Incrementally + ** METHOD: sqlite3_blob + ** + ** ^(This function is used to read data from an open [BLOB handle] into a + ** caller-supplied buffer. N bytes of data are copied into buffer Z + ** from the open BLOB, starting at offset iOffset.)^ + ** + ** ^If offset iOffset is less than N bytes from the end of the BLOB, + ** [SQLITE_ERROR] is returned and no data is read. ^If N or iOffset is + ** less than zero, [SQLITE_ERROR] is returned and no data is read. + ** ^The size of the blob (and hence the maximum value of N+iOffset) + ** can be determined using the [sqlite3_blob_bytes()] interface. + ** + ** ^An attempt to read from an expired [BLOB handle] fails with an + ** error code of [SQLITE_ABORT]. + ** + ** ^(On success, sqlite3_blob_read() returns SQLITE_OK. + ** Otherwise, an [error code] or an [extended error code] is returned.)^ + ** + ** This routine only works on a [BLOB handle] which has been created + ** by a prior successful call to [sqlite3_blob_open()] and which has not + ** been closed by [sqlite3_blob_close()]. Passing any other pointer in + ** to this routine results in undefined and probably undesirable behavior. + ** + ** See also: [sqlite3_blob_write()]. + */ + SQLITE_API int sqlite3_blob_read(sqlite3_blob*, void* Z, int N, int iOffset); + + /* + ** CAPI3REF: Write Data Into A BLOB Incrementally + ** METHOD: sqlite3_blob + ** + ** ^(This function is used to write data into an open [BLOB handle] from a + ** caller-supplied buffer. N bytes of data are copied from the buffer Z + ** into the open BLOB, starting at offset iOffset.)^ + ** + ** ^(On success, sqlite3_blob_write() returns SQLITE_OK. + ** Otherwise, an [error code] or an [extended error code] is returned.)^ + ** ^Unless SQLITE_MISUSE is returned, this function sets the + ** [database connection] error code and message accessible via + ** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions. + ** + ** ^If the [BLOB handle] passed as the first argument was not opened for + ** writing (the flags parameter to [sqlite3_blob_open()] was zero), + ** this function returns [SQLITE_READONLY]. + ** + ** This function may only modify the contents of the BLOB; it is + ** not possible to increase the size of a BLOB using this API. + ** ^If offset iOffset is less than N bytes from the end of the BLOB, + ** [SQLITE_ERROR] is returned and no data is written. The size of the + ** BLOB (and hence the maximum value of N+iOffset) can be determined + ** using the [sqlite3_blob_bytes()] interface. ^If N or iOffset are less + ** than zero [SQLITE_ERROR] is returned and no data is written. + ** + ** ^An attempt to write to an expired [BLOB handle] fails with an + ** error code of [SQLITE_ABORT]. ^Writes to the BLOB that occurred + ** before the [BLOB handle] expired are not rolled back by the + ** expiration of the handle, though of course those changes might + ** have been overwritten by the statement that expired the BLOB handle + ** or by other independent statements. + ** + ** This routine only works on a [BLOB handle] which has been created + ** by a prior successful call to [sqlite3_blob_open()] and which has not + ** been closed by [sqlite3_blob_close()]. Passing any other pointer in + ** to this routine results in undefined and probably undesirable behavior. + ** + ** See also: [sqlite3_blob_read()]. + */ + SQLITE_API int sqlite3_blob_write(sqlite3_blob*, const void* z, int n, int iOffset); + + /* + ** CAPI3REF: Virtual File System Objects + ** + ** A virtual filesystem (VFS) is an [sqlite3_vfs] object + ** that SQLite uses to interact + ** with the underlying operating system. Most SQLite builds come with a + ** single default VFS that is appropriate for the host computer. + ** New VFSes can be registered and existing VFSes can be unregistered. + ** The following interfaces are provided. + ** + ** ^The sqlite3_vfs_find() interface returns a pointer to a VFS given its name. + ** ^Names are case sensitive. + ** ^Names are zero-terminated UTF-8 strings. + ** ^If there is no match, a NULL pointer is returned. + ** ^If zVfsName is NULL then the default VFS is returned. + ** + ** ^New VFSes are registered with sqlite3_vfs_register(). + ** ^Each new VFS becomes the default VFS if the makeDflt flag is set. + ** ^The same VFS can be registered multiple times without injury. + ** ^To make an existing VFS into the default VFS, register it again + ** with the makeDflt flag set. If two different VFSes with the + ** same name are registered, the behavior is undefined. If a + ** VFS is registered with a name that is NULL or an empty string, + ** then the behavior is undefined. + ** + ** ^Unregister a VFS with the sqlite3_vfs_unregister() interface. + ** ^(If the default VFS is unregistered, another VFS is chosen as + ** the default. The choice for the new VFS is arbitrary.)^ + */ + SQLITE_API sqlite3_vfs* sqlite3_vfs_find(const char* zVfsName); + SQLITE_API int sqlite3_vfs_register(sqlite3_vfs*, int makeDflt); + SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*); + + /* + ** CAPI3REF: Mutexes + ** + ** The SQLite core uses these routines for thread + ** synchronization. Though they are intended for internal + ** use by SQLite, code that links against SQLite is + ** permitted to use any of these routines. + ** + ** The SQLite source code contains multiple implementations + ** of these mutex routines. An appropriate implementation + ** is selected automatically at compile-time. The following + ** implementations are available in the SQLite core: + ** + **
    + **
  • SQLITE_MUTEX_PTHREADS + **
  • SQLITE_MUTEX_W32 + **
  • SQLITE_MUTEX_NOOP + **
+ ** + ** The SQLITE_MUTEX_NOOP implementation is a set of routines + ** that does no real locking and is appropriate for use in + ** a single-threaded application. The SQLITE_MUTEX_PTHREADS and + ** SQLITE_MUTEX_W32 implementations are appropriate for use on Unix + ** and Windows. + ** + ** If SQLite is compiled with the SQLITE_MUTEX_APPDEF preprocessor + ** macro defined (with "-DSQLITE_MUTEX_APPDEF=1"), then no mutex + ** implementation is included with the library. In this case the + ** application must supply a custom mutex implementation using the + ** [SQLITE_CONFIG_MUTEX] option of the sqlite3_config() function + ** before calling sqlite3_initialize() or any other public sqlite3_ + ** function that calls sqlite3_initialize(). + ** + ** ^The sqlite3_mutex_alloc() routine allocates a new + ** mutex and returns a pointer to it. ^The sqlite3_mutex_alloc() + ** routine returns NULL if it is unable to allocate the requested + ** mutex. The argument to sqlite3_mutex_alloc() must one of these + ** integer constants: + ** + **
    + **
  • SQLITE_MUTEX_FAST + **
  • SQLITE_MUTEX_RECURSIVE + **
  • SQLITE_MUTEX_STATIC_MAIN + **
  • SQLITE_MUTEX_STATIC_MEM + **
  • SQLITE_MUTEX_STATIC_OPEN + **
  • SQLITE_MUTEX_STATIC_PRNG + **
  • SQLITE_MUTEX_STATIC_LRU + **
  • SQLITE_MUTEX_STATIC_PMEM + **
  • SQLITE_MUTEX_STATIC_APP1 + **
  • SQLITE_MUTEX_STATIC_APP2 + **
  • SQLITE_MUTEX_STATIC_APP3 + **
  • SQLITE_MUTEX_STATIC_VFS1 + **
  • SQLITE_MUTEX_STATIC_VFS2 + **
  • SQLITE_MUTEX_STATIC_VFS3 + **
+ ** + ** ^The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) + ** cause sqlite3_mutex_alloc() to create + ** a new mutex. ^The new mutex is recursive when SQLITE_MUTEX_RECURSIVE + ** is used but not necessarily so when SQLITE_MUTEX_FAST is used. + ** The mutex implementation does not need to make a distinction + ** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does + ** not want to. SQLite will only request a recursive mutex in + ** cases where it really needs one. If a faster non-recursive mutex + ** implementation is available on the host platform, the mutex subsystem + ** might return such a mutex in response to SQLITE_MUTEX_FAST. + ** + ** ^The other allowed parameters to sqlite3_mutex_alloc() (anything other + ** than SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) each return + ** a pointer to a static preexisting mutex. ^Nine static mutexes are + ** used by the current version of SQLite. Future versions of SQLite + ** may add additional static mutexes. Static mutexes are for internal + ** use by SQLite only. Applications that use SQLite mutexes should + ** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or + ** SQLITE_MUTEX_RECURSIVE. + ** + ** ^Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST + ** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc() + ** returns a different mutex on every call. ^For the static + ** mutex types, the same mutex is returned on every call that has + ** the same type number. + ** + ** ^The sqlite3_mutex_free() routine deallocates a previously + ** allocated dynamic mutex. Attempting to deallocate a static + ** mutex results in undefined behavior. + ** + ** ^The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt + ** to enter a mutex. ^If another thread is already within the mutex, + ** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return + ** SQLITE_BUSY. ^The sqlite3_mutex_try() interface returns [SQLITE_OK] + ** upon successful entry. ^(Mutexes created using + ** SQLITE_MUTEX_RECURSIVE can be entered multiple times by the same thread. + ** In such cases, the + ** mutex must be exited an equal number of times before another thread + ** can enter.)^ If the same thread tries to enter any mutex other + ** than an SQLITE_MUTEX_RECURSIVE more than once, the behavior is undefined. + ** + ** ^(Some systems (for example, Windows 95) do not support the operation + ** implemented by sqlite3_mutex_try(). On those systems, sqlite3_mutex_try() + ** will always return SQLITE_BUSY. The SQLite core only ever uses + ** sqlite3_mutex_try() as an optimization so this is acceptable + ** behavior.)^ + ** + ** ^The sqlite3_mutex_leave() routine exits a mutex that was + ** previously entered by the same thread. The behavior + ** is undefined if the mutex is not currently entered by the + ** calling thread or is not currently allocated. + ** + ** ^If the argument to sqlite3_mutex_enter(), sqlite3_mutex_try(), or + ** sqlite3_mutex_leave() is a NULL pointer, then all three routines + ** behave as no-ops. + ** + ** See also: [sqlite3_mutex_held()] and [sqlite3_mutex_notheld()]. + */ + SQLITE_API sqlite3_mutex* sqlite3_mutex_alloc(int); + SQLITE_API void sqlite3_mutex_free(sqlite3_mutex*); + SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex*); + SQLITE_API int sqlite3_mutex_try(sqlite3_mutex*); + SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*); + + /* + ** CAPI3REF: Mutex Methods Object + ** + ** An instance of this structure defines the low-level routines + ** used to allocate and use mutexes. + ** + ** Usually, the default mutex implementations provided by SQLite are + ** sufficient, however the application has the option of substituting a custom + ** implementation for specialized deployments or systems for which SQLite + ** does not provide a suitable implementation. In this case, the application + ** creates and populates an instance of this structure to pass + ** to sqlite3_config() along with the [SQLITE_CONFIG_MUTEX] option. + ** Additionally, an instance of this structure can be used as an + ** output variable when querying the system for the current mutex + ** implementation, using the [SQLITE_CONFIG_GETMUTEX] option. + ** + ** ^The xMutexInit method defined by this structure is invoked as + ** part of system initialization by the sqlite3_initialize() function. + ** ^The xMutexInit routine is called by SQLite exactly once for each + ** effective call to [sqlite3_initialize()]. + ** + ** ^The xMutexEnd method defined by this structure is invoked as + ** part of system shutdown by the sqlite3_shutdown() function. The + ** implementation of this method is expected to release all outstanding + ** resources obtained by the mutex methods implementation, especially + ** those obtained by the xMutexInit method. ^The xMutexEnd() + ** interface is invoked exactly once for each call to [sqlite3_shutdown()]. + ** + ** ^(The remaining seven methods defined by this structure (xMutexAlloc, + ** xMutexFree, xMutexEnter, xMutexTry, xMutexLeave, xMutexHeld and + ** xMutexNotheld) implement the following interfaces (respectively): + ** + **
    + **
  • [sqlite3_mutex_alloc()]
  • + **
  • [sqlite3_mutex_free()]
  • + **
  • [sqlite3_mutex_enter()]
  • + **
  • [sqlite3_mutex_try()]
  • + **
  • [sqlite3_mutex_leave()]
  • + **
  • [sqlite3_mutex_held()]
  • + **
  • [sqlite3_mutex_notheld()]
  • + **
)^ + ** + ** The only difference is that the public sqlite3_XXX functions enumerated + ** above silently ignore any invocations that pass a NULL pointer instead + ** of a valid mutex handle. The implementations of the methods defined + ** by this structure are not required to handle this case. The results + ** of passing a NULL pointer instead of a valid mutex handle are undefined + ** (i.e. it is acceptable to provide an implementation that segfaults if + ** it is passed a NULL pointer). + ** + ** The xMutexInit() method must be threadsafe. It must be harmless to + ** invoke xMutexInit() multiple times within the same process and without + ** intervening calls to xMutexEnd(). Second and subsequent calls to + ** xMutexInit() must be no-ops. + ** + ** xMutexInit() must not use SQLite memory allocation ([sqlite3_malloc()] + ** and its associates). Similarly, xMutexAlloc() must not use SQLite memory + ** allocation for a static mutex. ^However xMutexAlloc() may use SQLite + ** memory allocation for a fast or recursive mutex. + ** + ** ^SQLite will invoke the xMutexEnd() method when [sqlite3_shutdown()] is + ** called, but only if the prior call to xMutexInit returned SQLITE_OK. + ** If xMutexInit fails in any way, it is expected to clean up after itself + ** prior to returning. + */ + typedef struct sqlite3_mutex_methods sqlite3_mutex_methods; + struct sqlite3_mutex_methods + { + int (*xMutexInit)(void); + int (*xMutexEnd)(void); + sqlite3_mutex* (*xMutexAlloc)(int); + void (*xMutexFree)(sqlite3_mutex*); + void (*xMutexEnter)(sqlite3_mutex*); + int (*xMutexTry)(sqlite3_mutex*); + void (*xMutexLeave)(sqlite3_mutex*); + int (*xMutexHeld)(sqlite3_mutex*); + int (*xMutexNotheld)(sqlite3_mutex*); + }; /* -** CAPI3REF: Free Memory Used By A Database Connection -** METHOD: sqlite3 +** CAPI3REF: Mutex Verification Routines ** -** ^The sqlite3_db_release_memory(D) interface attempts to free as much heap -** memory as possible from database connection D. Unlike the -** [sqlite3_release_memory()] interface, this interface is in effect even -** when the [SQLITE_ENABLE_MEMORY_MANAGEMENT] compile-time option is -** omitted. -** -** See also: [sqlite3_release_memory()] -*/ -SQLITE_API int sqlite3_db_release_memory(sqlite3*); - -/* -** CAPI3REF: Impose A Limit On Heap Size -** -** These interfaces impose limits on the amount of heap memory that will be -** by all database connections within a single process. -** -** ^The sqlite3_soft_heap_limit64() interface sets and/or queries the -** soft limit on the amount of heap memory that may be allocated by SQLite. -** ^SQLite strives to keep heap memory utilization below the soft heap -** limit by reducing the number of pages held in the page cache -** as heap memory usages approaches the limit. -** ^The soft heap limit is "soft" because even though SQLite strives to stay -** below the limit, it will exceed the limit rather than generate -** an [SQLITE_NOMEM] error. In other words, the soft heap limit -** is advisory only. -** -** ^The sqlite3_hard_heap_limit64(N) interface sets a hard upper bound of -** N bytes on the amount of memory that will be allocated. ^The -** sqlite3_hard_heap_limit64(N) interface is similar to -** sqlite3_soft_heap_limit64(N) except that memory allocations will fail -** when the hard heap limit is reached. -** -** ^The return value from both sqlite3_soft_heap_limit64() and -** sqlite3_hard_heap_limit64() is the size of -** the heap limit prior to the call, or negative in the case of an -** error. ^If the argument N is negative -** then no change is made to the heap limit. Hence, the current -** size of heap limits can be determined by invoking -** sqlite3_soft_heap_limit64(-1) or sqlite3_hard_heap_limit(-1). -** -** ^Setting the heap limits to zero disables the heap limiter mechanism. -** -** ^The soft heap limit may not be greater than the hard heap limit. -** ^If the hard heap limit is enabled and if sqlite3_soft_heap_limit(N) -** is invoked with a value of N that is greater than the hard heap limit, -** the the soft heap limit is set to the value of the hard heap limit. -** ^The soft heap limit is automatically enabled whenever the hard heap -** limit is enabled. ^When sqlite3_hard_heap_limit64(N) is invoked and -** the soft heap limit is outside the range of 1..N, then the soft heap -** limit is set to N. ^Invoking sqlite3_soft_heap_limit64(0) when the -** hard heap limit is enabled makes the soft heap limit equal to the -** hard heap limit. -** -** The memory allocation limits can also be adjusted using -** [PRAGMA soft_heap_limit] and [PRAGMA hard_heap_limit]. -** -** ^(The heap limits are not enforced in the current implementation -** if one or more of following conditions are true: -** -**
    -**
  • The limit value is set to zero. -**
  • Memory accounting is disabled using a combination of the -** [sqlite3_config]([SQLITE_CONFIG_MEMSTATUS],...) start-time option and -** the [SQLITE_DEFAULT_MEMSTATUS] compile-time option. -**
  • An alternative page cache implementation is specified using -** [sqlite3_config]([SQLITE_CONFIG_PCACHE2],...). -**
  • The page cache allocates from its own memory pool supplied -** by [sqlite3_config]([SQLITE_CONFIG_PAGECACHE],...) rather than -** from the heap. -**
)^ -** -** The circumstances under which SQLite will enforce the heap limits may -** changes in future releases of SQLite. -*/ -SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N); -SQLITE_API sqlite3_int64 sqlite3_hard_heap_limit64(sqlite3_int64 N); - -/* -** CAPI3REF: Deprecated Soft Heap Limit Interface -** DEPRECATED -** -** This is a deprecated version of the [sqlite3_soft_heap_limit64()] -** interface. This routine is provided for historical compatibility -** only. All new applications should use the -** [sqlite3_soft_heap_limit64()] interface rather than this one. -*/ -SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N); - - -/* -** CAPI3REF: Extract Metadata About A Column Of A Table -** METHOD: sqlite3 -** -** ^(The sqlite3_table_column_metadata(X,D,T,C,....) routine returns -** information about column C of table T in database D -** on [database connection] X.)^ ^The sqlite3_table_column_metadata() -** interface returns SQLITE_OK and fills in the non-NULL pointers in -** the final five arguments with appropriate values if the specified -** column exists. ^The sqlite3_table_column_metadata() interface returns -** SQLITE_ERROR if the specified column does not exist. -** ^If the column-name parameter to sqlite3_table_column_metadata() is a -** NULL pointer, then this routine simply checks for the existence of the -** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it -** does not. If the table name parameter T in a call to -** sqlite3_table_column_metadata(X,D,T,C,...) is NULL then the result is -** undefined behavior. -** -** ^The column is identified by the second, third and fourth parameters to -** this function. ^(The second parameter is either the name of the database -** (i.e. "main", "temp", or an attached database) containing the specified -** table or NULL.)^ ^If it is NULL, then all attached databases are searched -** for the table using the same algorithm used by the database engine to -** resolve unqualified table references. -** -** ^The third and fourth parameters to this function are the table and column -** name of the desired column, respectively. -** -** ^Metadata is returned by writing to the memory locations passed as the 5th -** and subsequent parameters to this function. ^Any of these arguments may be -** NULL, in which case the corresponding element of metadata is omitted. -** -** ^(
-** -**
Parameter Output
Type
Description -** -**
5th const char* Data type -**
6th const char* Name of default collation sequence -**
7th int True if column has a NOT NULL constraint -**
8th int True if column is part of the PRIMARY KEY -**
9th int True if column is [AUTOINCREMENT] -**
-**
)^ -** -** ^The memory pointed to by the character pointers returned for the -** declaration type and collation sequence is valid until the next -** call to any SQLite API function. -** -** ^If the specified table is actually a view, an [error code] is returned. -** -** ^If the specified column is "rowid", "oid" or "_rowid_" and the table -** is not a [WITHOUT ROWID] table and an -** [INTEGER PRIMARY KEY] column has been explicitly declared, then the output -** parameters are set for the explicitly declared column. ^(If there is no -** [INTEGER PRIMARY KEY] column, then the outputs -** for the [rowid] are set as follows: -** -**
-**     data type: "INTEGER"
-**     collation sequence: "BINARY"
-**     not null: 0
-**     primary key: 1
-**     auto increment: 0
-** 
)^ -** -** ^This function causes all database schemas to be read from disk and -** parsed, if that has not already been done, and returns an error if -** any errors are encountered while loading the schema. -*/ -SQLITE_API int sqlite3_table_column_metadata( - sqlite3 *db, /* Connection handle */ - const char *zDbName, /* Database name or NULL */ - const char *zTableName, /* Table name */ - const char *zColumnName, /* Column name */ - char const **pzDataType, /* OUTPUT: Declared data type */ - char const **pzCollSeq, /* OUTPUT: Collation sequence name */ - int *pNotNull, /* OUTPUT: True if NOT NULL constraint exists */ - int *pPrimaryKey, /* OUTPUT: True if column part of PK */ - int *pAutoinc /* OUTPUT: True if column is auto-increment */ -); - -/* -** CAPI3REF: Load An Extension -** METHOD: sqlite3 -** -** ^This interface loads an SQLite extension library from the named file. -** -** ^The sqlite3_load_extension() interface attempts to load an -** [SQLite extension] library contained in the file zFile. If -** the file cannot be loaded directly, attempts are made to load -** with various operating-system specific extensions added. -** So for example, if "samplelib" cannot be loaded, then names like -** "samplelib.so" or "samplelib.dylib" or "samplelib.dll" might -** be tried also. -** -** ^The entry point is zProc. -** ^(zProc may be 0, in which case SQLite will try to come up with an -** entry point name on its own. It first tries "sqlite3_extension_init". -** If that does not work, it constructs a name "sqlite3_X_init" where the -** X is consists of the lower-case equivalent of all ASCII alphabetic -** characters in the filename from the last "/" to the first following -** "." and omitting any initial "lib".)^ -** ^The sqlite3_load_extension() interface returns -** [SQLITE_OK] on success and [SQLITE_ERROR] if something goes wrong. -** ^If an error occurs and pzErrMsg is not 0, then the -** [sqlite3_load_extension()] interface shall attempt to -** fill *pzErrMsg with error message text stored in memory -** obtained from [sqlite3_malloc()]. The calling function -** should free this memory by calling [sqlite3_free()]. -** -** ^Extension loading must be enabled using -** [sqlite3_enable_load_extension()] or -** [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],1,NULL) -** prior to calling this API, -** otherwise an error will be returned. -** -** Security warning: It is recommended that the -** [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method be used to enable only this -** interface. The use of the [sqlite3_enable_load_extension()] interface -** should be avoided. This will keep the SQL function [load_extension()] -** disabled and prevent SQL injections from giving attackers -** access to extension loading capabilities. -** -** See also the [load_extension() SQL function]. -*/ -SQLITE_API int sqlite3_load_extension( - sqlite3 *db, /* Load the extension into this database connection */ - const char *zFile, /* Name of the shared library containing extension */ - const char *zProc, /* Entry point. Derived from zFile if 0 */ - char **pzErrMsg /* Put error message here if not 0 */ -); - -/* -** CAPI3REF: Enable Or Disable Extension Loading -** METHOD: sqlite3 -** -** ^So as not to open security holes in older applications that are -** unprepared to deal with [extension loading], and as a means of disabling -** [extension loading] while evaluating user-entered SQL, the following API -** is provided to turn the [sqlite3_load_extension()] mechanism on and off. -** -** ^Extension loading is off by default. -** ^Call the sqlite3_enable_load_extension() routine with onoff==1 -** to turn extension loading on and call it with onoff==0 to turn -** it back off again. -** -** ^This interface enables or disables both the C-API -** [sqlite3_load_extension()] and the SQL function [load_extension()]. -** ^(Use [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],..) -** to enable or disable only the C-API.)^ -** -** Security warning: It is recommended that extension loading -** be enabled using the [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method -** rather than this interface, so the [load_extension()] SQL function -** remains disabled. This will prevent SQL injections from giving attackers -** access to extension loading capabilities. -*/ -SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff); - -/* -** CAPI3REF: Automatically Load Statically Linked Extensions -** -** ^This interface causes the xEntryPoint() function to be invoked for -** each new [database connection] that is created. The idea here is that -** xEntryPoint() is the entry point for a statically linked [SQLite extension] -** that is to be automatically loaded into all new database connections. -** -** ^(Even though the function prototype shows that xEntryPoint() takes -** no arguments and returns void, SQLite invokes xEntryPoint() with three -** arguments and expects an integer result as if the signature of the -** entry point where as follows: -** -**
-**    int xEntryPoint(
-**      sqlite3 *db,
-**      const char **pzErrMsg,
-**      const struct sqlite3_api_routines *pThunk
-**    );
-** 
)^ -** -** If the xEntryPoint routine encounters an error, it should make *pzErrMsg -** point to an appropriate error message (obtained from [sqlite3_mprintf()]) -** and return an appropriate [error code]. ^SQLite ensures that *pzErrMsg -** is NULL before calling the xEntryPoint(). ^SQLite will invoke -** [sqlite3_free()] on *pzErrMsg after xEntryPoint() returns. ^If any -** xEntryPoint() returns an error, the [sqlite3_open()], [sqlite3_open16()], -** or [sqlite3_open_v2()] call that provoked the xEntryPoint() will fail. -** -** ^Calling sqlite3_auto_extension(X) with an entry point X that is already -** on the list of automatic extensions is a harmless no-op. ^No entry point -** will be called more than once for each database connection that is opened. -** -** See also: [sqlite3_reset_auto_extension()] -** and [sqlite3_cancel_auto_extension()] -*/ -SQLITE_API int sqlite3_auto_extension(void(*xEntryPoint)(void)); - -/* -** CAPI3REF: Cancel Automatic Extension Loading -** -** ^The [sqlite3_cancel_auto_extension(X)] interface unregisters the -** initialization routine X that was registered using a prior call to -** [sqlite3_auto_extension(X)]. ^The [sqlite3_cancel_auto_extension(X)] -** routine returns 1 if initialization routine X was successfully -** unregistered and it returns 0 if X was not on the list of initialization -** routines. -*/ -SQLITE_API int sqlite3_cancel_auto_extension(void(*xEntryPoint)(void)); - -/* -** CAPI3REF: Reset Automatic Extension Loading -** -** ^This interface disables all automatic extensions previously -** registered using [sqlite3_auto_extension()]. -*/ -SQLITE_API void sqlite3_reset_auto_extension(void); - -/* -** The interface to the virtual-table mechanism is currently considered -** to be experimental. The interface might change in incompatible ways. -** If this is a problem for you, do not use the interface at this time. -** -** When the virtual-table mechanism stabilizes, we will declare the -** interface fixed, support it indefinitely, and remove this comment. -*/ - -/* -** Structures used by the virtual table interface -*/ -typedef struct sqlite3_vtab sqlite3_vtab; -typedef struct sqlite3_index_info sqlite3_index_info; -typedef struct sqlite3_vtab_cursor sqlite3_vtab_cursor; -typedef struct sqlite3_module sqlite3_module; - -/* -** CAPI3REF: Virtual Table Object -** KEYWORDS: sqlite3_module {virtual table module} -** -** This structure, sometimes called a "virtual table module", -** defines the implementation of a [virtual table]. -** This structure consists mostly of methods for the module. -** -** ^A virtual table module is created by filling in a persistent -** instance of this structure and passing a pointer to that instance -** to [sqlite3_create_module()] or [sqlite3_create_module_v2()]. -** ^The registration remains valid until it is replaced by a different -** module or until the [database connection] closes. The content -** of this structure must not change while it is registered with -** any database connection. -*/ -struct sqlite3_module { - int iVersion; - int (*xCreate)(sqlite3*, void *pAux, - int argc, const char *const*argv, - sqlite3_vtab **ppVTab, char**); - int (*xConnect)(sqlite3*, void *pAux, - int argc, const char *const*argv, - sqlite3_vtab **ppVTab, char**); - int (*xBestIndex)(sqlite3_vtab *pVTab, sqlite3_index_info*); - int (*xDisconnect)(sqlite3_vtab *pVTab); - int (*xDestroy)(sqlite3_vtab *pVTab); - int (*xOpen)(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor); - int (*xClose)(sqlite3_vtab_cursor*); - int (*xFilter)(sqlite3_vtab_cursor*, int idxNum, const char *idxStr, - int argc, sqlite3_value **argv); - int (*xNext)(sqlite3_vtab_cursor*); - int (*xEof)(sqlite3_vtab_cursor*); - int (*xColumn)(sqlite3_vtab_cursor*, sqlite3_context*, int); - int (*xRowid)(sqlite3_vtab_cursor*, sqlite3_int64 *pRowid); - int (*xUpdate)(sqlite3_vtab *, int, sqlite3_value **, sqlite3_int64 *); - int (*xBegin)(sqlite3_vtab *pVTab); - int (*xSync)(sqlite3_vtab *pVTab); - int (*xCommit)(sqlite3_vtab *pVTab); - int (*xRollback)(sqlite3_vtab *pVTab); - int (*xFindFunction)(sqlite3_vtab *pVtab, int nArg, const char *zName, - void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), - void **ppArg); - int (*xRename)(sqlite3_vtab *pVtab, const char *zNew); - /* The methods above are in version 1 of the sqlite_module object. Those - ** below are for version 2 and greater. */ - int (*xSavepoint)(sqlite3_vtab *pVTab, int); - int (*xRelease)(sqlite3_vtab *pVTab, int); - int (*xRollbackTo)(sqlite3_vtab *pVTab, int); - /* The methods above are in versions 1 and 2 of the sqlite_module object. - ** Those below are for version 3 and greater. */ - int (*xShadowName)(const char*); -}; - -/* -** CAPI3REF: Virtual Table Indexing Information -** KEYWORDS: sqlite3_index_info -** -** The sqlite3_index_info structure and its substructures is used as part -** of the [virtual table] interface to -** pass information into and receive the reply from the [xBestIndex] -** method of a [virtual table module]. The fields under **Inputs** are the -** inputs to xBestIndex and are read-only. xBestIndex inserts its -** results into the **Outputs** fields. -** -** ^(The aConstraint[] array records WHERE clause constraints of the form: -** -**
column OP expr
-** -** where OP is =, <, <=, >, or >=.)^ ^(The particular operator is -** stored in aConstraint[].op using one of the -** [SQLITE_INDEX_CONSTRAINT_EQ | SQLITE_INDEX_CONSTRAINT_ values].)^ -** ^(The index of the column is stored in -** aConstraint[].iColumn.)^ ^(aConstraint[].usable is TRUE if the -** expr on the right-hand side can be evaluated (and thus the constraint -** is usable) and false if it cannot.)^ -** -** ^The optimizer automatically inverts terms of the form "expr OP column" -** and makes other simplifications to the WHERE clause in an attempt to -** get as many WHERE clause terms into the form shown above as possible. -** ^The aConstraint[] array only reports WHERE clause terms that are -** relevant to the particular virtual table being queried. -** -** ^Information about the ORDER BY clause is stored in aOrderBy[]. -** ^Each term of aOrderBy records a column of the ORDER BY clause. -** -** The colUsed field indicates which columns of the virtual table may be -** required by the current scan. Virtual table columns are numbered from -** zero in the order in which they appear within the CREATE TABLE statement -** passed to sqlite3_declare_vtab(). For the first 63 columns (columns 0-62), -** the corresponding bit is set within the colUsed mask if the column may be -** required by SQLite. If the table has at least 64 columns and any column -** to the right of the first 63 is required, then bit 63 of colUsed is also -** set. In other words, column iCol may be required if the expression -** (colUsed & ((sqlite3_uint64)1 << (iCol>=63 ? 63 : iCol))) evaluates to -** non-zero. -** -** The [xBestIndex] method must fill aConstraintUsage[] with information -** about what parameters to pass to xFilter. ^If argvIndex>0 then -** the right-hand side of the corresponding aConstraint[] is evaluated -** and becomes the argvIndex-th entry in argv. ^(If aConstraintUsage[].omit -** is true, then the constraint is assumed to be fully handled by the -** virtual table and might not be checked again by the byte code.)^ ^(The -** aConstraintUsage[].omit flag is an optimization hint. When the omit flag -** is left in its default setting of false, the constraint will always be -** checked separately in byte code. If the omit flag is change to true, then -** the constraint may or may not be checked in byte code. In other words, -** when the omit flag is true there is no guarantee that the constraint will -** not be checked again using byte code.)^ -** -** ^The idxNum and idxPtr values are recorded and passed into the -** [xFilter] method. -** ^[sqlite3_free()] is used to free idxPtr if and only if -** needToFreeIdxPtr is true. -** -** ^The orderByConsumed means that output from [xFilter]/[xNext] will occur in -** the correct order to satisfy the ORDER BY clause so that no separate -** sorting step is required. -** -** ^The estimatedCost value is an estimate of the cost of a particular -** strategy. A cost of N indicates that the cost of the strategy is similar -** to a linear scan of an SQLite table with N rows. A cost of log(N) -** indicates that the expense of the operation is similar to that of a -** binary search on a unique indexed field of an SQLite table with N rows. -** -** ^The estimatedRows value is an estimate of the number of rows that -** will be returned by the strategy. -** -** The xBestIndex method may optionally populate the idxFlags field with a -** mask of SQLITE_INDEX_SCAN_* flags. Currently there is only one such flag - -** SQLITE_INDEX_SCAN_UNIQUE. If the xBestIndex method sets this flag, SQLite -** assumes that the strategy may visit at most one row. -** -** Additionally, if xBestIndex sets the SQLITE_INDEX_SCAN_UNIQUE flag, then -** SQLite also assumes that if a call to the xUpdate() method is made as -** part of the same statement to delete or update a virtual table row and the -** implementation returns SQLITE_CONSTRAINT, then there is no need to rollback -** any database changes. In other words, if the xUpdate() returns -** SQLITE_CONSTRAINT, the database contents must be exactly as they were -** before xUpdate was called. By contrast, if SQLITE_INDEX_SCAN_UNIQUE is not -** set and xUpdate returns SQLITE_CONSTRAINT, any database changes made by -** the xUpdate method are automatically rolled back by SQLite. -** -** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info -** structure for SQLite [version 3.8.2] ([dateof:3.8.2]). -** If a virtual table extension is -** used with an SQLite version earlier than 3.8.2, the results of attempting -** to read or write the estimatedRows field are undefined (but are likely -** to include crashing the application). The estimatedRows field should -** therefore only be used if [sqlite3_libversion_number()] returns a -** value greater than or equal to 3008002. Similarly, the idxFlags field -** was added for [version 3.9.0] ([dateof:3.9.0]). -** It may therefore only be used if -** sqlite3_libversion_number() returns a value greater than or equal to -** 3009000. -*/ -struct sqlite3_index_info { - /* Inputs */ - int nConstraint; /* Number of entries in aConstraint */ - struct sqlite3_index_constraint { - int iColumn; /* Column constrained. -1 for ROWID */ - unsigned char op; /* Constraint operator */ - unsigned char usable; /* True if this constraint is usable */ - int iTermOffset; /* Used internally - xBestIndex should ignore */ - } *aConstraint; /* Table of WHERE clause constraints */ - int nOrderBy; /* Number of terms in the ORDER BY clause */ - struct sqlite3_index_orderby { - int iColumn; /* Column number */ - unsigned char desc; /* True for DESC. False for ASC. */ - } *aOrderBy; /* The ORDER BY clause */ - /* Outputs */ - struct sqlite3_index_constraint_usage { - int argvIndex; /* if >0, constraint is part of argv to xFilter */ - unsigned char omit; /* Do not code a test for this constraint */ - } *aConstraintUsage; - int idxNum; /* Number used to identify the index */ - char *idxStr; /* String, possibly obtained from sqlite3_malloc */ - int needToFreeIdxStr; /* Free idxStr using sqlite3_free() if true */ - int orderByConsumed; /* True if output is already ordered */ - double estimatedCost; /* Estimated cost of using this index */ - /* Fields below are only available in SQLite 3.8.2 and later */ - sqlite3_int64 estimatedRows; /* Estimated number of rows returned */ - /* Fields below are only available in SQLite 3.9.0 and later */ - int idxFlags; /* Mask of SQLITE_INDEX_SCAN_* flags */ - /* Fields below are only available in SQLite 3.10.0 and later */ - sqlite3_uint64 colUsed; /* Input: Mask of columns used by statement */ -}; - -/* -** CAPI3REF: Virtual Table Scan Flags -** -** Virtual table implementations are allowed to set the -** [sqlite3_index_info].idxFlags field to some combination of -** these bits. -*/ -#define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */ - -/* -** CAPI3REF: Virtual Table Constraint Operator Codes -** -** These macros define the allowed values for the -** [sqlite3_index_info].aConstraint[].op field. Each value represents -** an operator that is part of a constraint term in the WHERE clause of -** a query that uses a [virtual table]. -** -** ^The left-hand operand of the operator is given by the corresponding -** aConstraint[].iColumn field. ^An iColumn of -1 indicates the left-hand -** operand is the rowid. -** The SQLITE_INDEX_CONSTRAINT_LIMIT and SQLITE_INDEX_CONSTRAINT_OFFSET -** operators have no left-hand operand, and so for those operators the -** corresponding aConstraint[].iColumn is meaningless and should not be -** used. -** -** All operator values from SQLITE_INDEX_CONSTRAINT_FUNCTION through -** value 255 are reserved to represent functions that are overloaded -** by the [xFindFunction|xFindFunction method] of the virtual table -** implementation. -** -** The right-hand operands for each constraint might be accessible using -** the [sqlite3_vtab_rhs_value()] interface. Usually the right-hand -** operand is only available if it appears as a single constant literal -** in the input SQL. If the right-hand operand is another column or an -** expression (even a constant expression) or a parameter, then the -** sqlite3_vtab_rhs_value() probably will not be able to extract it. -** ^The SQLITE_INDEX_CONSTRAINT_ISNULL and -** SQLITE_INDEX_CONSTRAINT_ISNOTNULL operators have no right-hand operand -** and hence calls to sqlite3_vtab_rhs_value() for those operators will -** always return SQLITE_NOTFOUND. -** -** The collating sequence to be used for comparison can be found using -** the [sqlite3_vtab_collation()] interface. For most real-world virtual -** tables, the collating sequence of constraints does not matter (for example -** because the constraints are numeric) and so the sqlite3_vtab_collation() -** interface is no commonly needed. -*/ -#define SQLITE_INDEX_CONSTRAINT_EQ 2 -#define SQLITE_INDEX_CONSTRAINT_GT 4 -#define SQLITE_INDEX_CONSTRAINT_LE 8 -#define SQLITE_INDEX_CONSTRAINT_LT 16 -#define SQLITE_INDEX_CONSTRAINT_GE 32 -#define SQLITE_INDEX_CONSTRAINT_MATCH 64 -#define SQLITE_INDEX_CONSTRAINT_LIKE 65 -#define SQLITE_INDEX_CONSTRAINT_GLOB 66 -#define SQLITE_INDEX_CONSTRAINT_REGEXP 67 -#define SQLITE_INDEX_CONSTRAINT_NE 68 -#define SQLITE_INDEX_CONSTRAINT_ISNOT 69 -#define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70 -#define SQLITE_INDEX_CONSTRAINT_ISNULL 71 -#define SQLITE_INDEX_CONSTRAINT_IS 72 -#define SQLITE_INDEX_CONSTRAINT_LIMIT 73 -#define SQLITE_INDEX_CONSTRAINT_OFFSET 74 -#define SQLITE_INDEX_CONSTRAINT_FUNCTION 150 - -/* -** CAPI3REF: Register A Virtual Table Implementation -** METHOD: sqlite3 -** -** ^These routines are used to register a new [virtual table module] name. -** ^Module names must be registered before -** creating a new [virtual table] using the module and before using a -** preexisting [virtual table] for the module. -** -** ^The module name is registered on the [database connection] specified -** by the first parameter. ^The name of the module is given by the -** second parameter. ^The third parameter is a pointer to -** the implementation of the [virtual table module]. ^The fourth -** parameter is an arbitrary client data pointer that is passed through -** into the [xCreate] and [xConnect] methods of the virtual table module -** when a new virtual table is be being created or reinitialized. -** -** ^The sqlite3_create_module_v2() interface has a fifth parameter which -** is a pointer to a destructor for the pClientData. ^SQLite will -** invoke the destructor function (if it is not NULL) when SQLite -** no longer needs the pClientData pointer. ^The destructor will also -** be invoked if the call to sqlite3_create_module_v2() fails. -** ^The sqlite3_create_module() -** interface is equivalent to sqlite3_create_module_v2() with a NULL -** destructor. -** -** ^If the third parameter (the pointer to the sqlite3_module object) is -** NULL then no new module is created and any existing modules with the -** same name are dropped. -** -** See also: [sqlite3_drop_modules()] -*/ -SQLITE_API int sqlite3_create_module( - sqlite3 *db, /* SQLite connection to register module with */ - const char *zName, /* Name of the module */ - const sqlite3_module *p, /* Methods for the module */ - void *pClientData /* Client data for xCreate/xConnect */ -); -SQLITE_API int sqlite3_create_module_v2( - sqlite3 *db, /* SQLite connection to register module with */ - const char *zName, /* Name of the module */ - const sqlite3_module *p, /* Methods for the module */ - void *pClientData, /* Client data for xCreate/xConnect */ - void(*xDestroy)(void*) /* Module destructor function */ -); - -/* -** CAPI3REF: Remove Unnecessary Virtual Table Implementations -** METHOD: sqlite3 -** -** ^The sqlite3_drop_modules(D,L) interface removes all virtual -** table modules from database connection D except those named on list L. -** The L parameter must be either NULL or a pointer to an array of pointers -** to strings where the array is terminated by a single NULL pointer. -** ^If the L parameter is NULL, then all virtual table modules are removed. -** -** See also: [sqlite3_create_module()] -*/ -SQLITE_API int sqlite3_drop_modules( - sqlite3 *db, /* Remove modules from this connection */ - const char **azKeep /* Except, do not remove the ones named here */ -); - -/* -** CAPI3REF: Virtual Table Instance Object -** KEYWORDS: sqlite3_vtab -** -** Every [virtual table module] implementation uses a subclass -** of this object to describe a particular instance -** of the [virtual table]. Each subclass will -** be tailored to the specific needs of the module implementation. -** The purpose of this superclass is to define certain fields that are -** common to all module implementations. -** -** ^Virtual tables methods can set an error message by assigning a -** string obtained from [sqlite3_mprintf()] to zErrMsg. The method should -** take care that any prior string is freed by a call to [sqlite3_free()] -** prior to assigning a new string to zErrMsg. ^After the error message -** is delivered up to the client application, the string will be automatically -** freed by sqlite3_free() and the zErrMsg field will be zeroed. -*/ -struct sqlite3_vtab { - const sqlite3_module *pModule; /* The module for this virtual table */ - int nRef; /* Number of open cursors */ - char *zErrMsg; /* Error message from sqlite3_mprintf() */ - /* Virtual table implementations will typically add additional fields */ -}; - -/* -** CAPI3REF: Virtual Table Cursor Object -** KEYWORDS: sqlite3_vtab_cursor {virtual table cursor} -** -** Every [virtual table module] implementation uses a subclass of the -** following structure to describe cursors that point into the -** [virtual table] and are used -** to loop through the virtual table. Cursors are created using the -** [sqlite3_module.xOpen | xOpen] method of the module and are destroyed -** by the [sqlite3_module.xClose | xClose] method. Cursors are used -** by the [xFilter], [xNext], [xEof], [xColumn], and [xRowid] methods -** of the module. Each module implementation will define -** the content of a cursor structure to suit its own needs. -** -** This superclass exists in order to define fields of the cursor that -** are common to all implementations. -*/ -struct sqlite3_vtab_cursor { - sqlite3_vtab *pVtab; /* Virtual table of this cursor */ - /* Virtual table implementations will typically add additional fields */ -}; - -/* -** CAPI3REF: Declare The Schema Of A Virtual Table -** -** ^The [xCreate] and [xConnect] methods of a -** [virtual table module] call this interface -** to declare the format (the names and datatypes of the columns) of -** the virtual tables they implement. -*/ -SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL); - -/* -** CAPI3REF: Overload A Function For A Virtual Table -** METHOD: sqlite3 -** -** ^(Virtual tables can provide alternative implementations of functions -** using the [xFindFunction] method of the [virtual table module]. -** But global versions of those functions -** must exist in order to be overloaded.)^ -** -** ^(This API makes sure a global version of a function with a particular -** name and number of parameters exists. If no such function exists -** before this API is called, a new function is created.)^ ^The implementation -** of the new function always causes an exception to be thrown. So -** the new function is not good for anything by itself. Its only -** purpose is to be a placeholder function that can be overloaded -** by a [virtual table]. -*/ -SQLITE_API int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg); - -/* -** The interface to the virtual-table mechanism defined above (back up -** to a comment remarkably similar to this one) is currently considered -** to be experimental. The interface might change in incompatible ways. -** If this is a problem for you, do not use the interface at this time. -** -** When the virtual-table mechanism stabilizes, we will declare the -** interface fixed, support it indefinitely, and remove this comment. -*/ - -/* -** CAPI3REF: A Handle To An Open BLOB -** KEYWORDS: {BLOB handle} {BLOB handles} -** -** An instance of this object represents an open BLOB on which -** [sqlite3_blob_open | incremental BLOB I/O] can be performed. -** ^Objects of this type are created by [sqlite3_blob_open()] -** and destroyed by [sqlite3_blob_close()]. -** ^The [sqlite3_blob_read()] and [sqlite3_blob_write()] interfaces -** can be used to read or write small subsections of the BLOB. -** ^The [sqlite3_blob_bytes()] interface returns the size of the BLOB in bytes. -*/ -typedef struct sqlite3_blob sqlite3_blob; - -/* -** CAPI3REF: Open A BLOB For Incremental I/O -** METHOD: sqlite3 -** CONSTRUCTOR: sqlite3_blob -** -** ^(This interfaces opens a [BLOB handle | handle] to the BLOB located -** in row iRow, column zColumn, table zTable in database zDb; -** in other words, the same BLOB that would be selected by: -** -**
-**     SELECT zColumn FROM zDb.zTable WHERE [rowid] = iRow;
-** 
)^ -** -** ^(Parameter zDb is not the filename that contains the database, but -** rather the symbolic name of the database. For attached databases, this is -** the name that appears after the AS keyword in the [ATTACH] statement. -** For the main database file, the database name is "main". For TEMP -** tables, the database name is "temp".)^ -** -** ^If the flags parameter is non-zero, then the BLOB is opened for read -** and write access. ^If the flags parameter is zero, the BLOB is opened for -** read-only access. -** -** ^(On success, [SQLITE_OK] is returned and the new [BLOB handle] is stored -** in *ppBlob. Otherwise an [error code] is returned and, unless the error -** code is SQLITE_MISUSE, *ppBlob is set to NULL.)^ ^This means that, provided -** the API is not misused, it is always safe to call [sqlite3_blob_close()] -** on *ppBlob after this function it returns. -** -** This function fails with SQLITE_ERROR if any of the following are true: -**
    -**
  • ^(Database zDb does not exist)^, -**
  • ^(Table zTable does not exist within database zDb)^, -**
  • ^(Table zTable is a WITHOUT ROWID table)^, -**
  • ^(Column zColumn does not exist)^, -**
  • ^(Row iRow is not present in the table)^, -**
  • ^(The specified column of row iRow contains a value that is not -** a TEXT or BLOB value)^, -**
  • ^(Column zColumn is part of an index, PRIMARY KEY or UNIQUE -** constraint and the blob is being opened for read/write access)^, -**
  • ^([foreign key constraints | Foreign key constraints] are enabled, -** column zColumn is part of a [child key] definition and the blob is -** being opened for read/write access)^. -**
-** -** ^Unless it returns SQLITE_MISUSE, this function sets the -** [database connection] error code and message accessible via -** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions. -** -** A BLOB referenced by sqlite3_blob_open() may be read using the -** [sqlite3_blob_read()] interface and modified by using -** [sqlite3_blob_write()]. The [BLOB handle] can be moved to a -** different row of the same table using the [sqlite3_blob_reopen()] -** interface. However, the column, table, or database of a [BLOB handle] -** cannot be changed after the [BLOB handle] is opened. -** -** ^(If the row that a BLOB handle points to is modified by an -** [UPDATE], [DELETE], or by [ON CONFLICT] side-effects -** then the BLOB handle is marked as "expired". -** This is true if any column of the row is changed, even a column -** other than the one the BLOB handle is open on.)^ -** ^Calls to [sqlite3_blob_read()] and [sqlite3_blob_write()] for -** an expired BLOB handle fail with a return code of [SQLITE_ABORT]. -** ^(Changes written into a BLOB prior to the BLOB expiring are not -** rolled back by the expiration of the BLOB. Such changes will eventually -** commit if the transaction continues to completion.)^ -** -** ^Use the [sqlite3_blob_bytes()] interface to determine the size of -** the opened blob. ^The size of a blob may not be changed by this -** interface. Use the [UPDATE] SQL command to change the size of a -** blob. -** -** ^The [sqlite3_bind_zeroblob()] and [sqlite3_result_zeroblob()] interfaces -** and the built-in [zeroblob] SQL function may be used to create a -** zero-filled blob to read or write using the incremental-blob interface. -** -** To avoid a resource leak, every open [BLOB handle] should eventually -** be released by a call to [sqlite3_blob_close()]. -** -** See also: [sqlite3_blob_close()], -** [sqlite3_blob_reopen()], [sqlite3_blob_read()], -** [sqlite3_blob_bytes()], [sqlite3_blob_write()]. -*/ -SQLITE_API int sqlite3_blob_open( - sqlite3*, - const char *zDb, - const char *zTable, - const char *zColumn, - sqlite3_int64 iRow, - int flags, - sqlite3_blob **ppBlob -); - -/* -** CAPI3REF: Move a BLOB Handle to a New Row -** METHOD: sqlite3_blob -** -** ^This function is used to move an existing [BLOB handle] so that it points -** to a different row of the same database table. ^The new row is identified -** by the rowid value passed as the second argument. Only the row can be -** changed. ^The database, table and column on which the blob handle is open -** remain the same. Moving an existing [BLOB handle] to a new row is -** faster than closing the existing handle and opening a new one. -** -** ^(The new row must meet the same criteria as for [sqlite3_blob_open()] - -** it must exist and there must be either a blob or text value stored in -** the nominated column.)^ ^If the new row is not present in the table, or if -** it does not contain a blob or text value, or if another error occurs, an -** SQLite error code is returned and the blob handle is considered aborted. -** ^All subsequent calls to [sqlite3_blob_read()], [sqlite3_blob_write()] or -** [sqlite3_blob_reopen()] on an aborted blob handle immediately return -** SQLITE_ABORT. ^Calling [sqlite3_blob_bytes()] on an aborted blob handle -** always returns zero. -** -** ^This function sets the database handle error code and message. -*/ -SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64); - -/* -** CAPI3REF: Close A BLOB Handle -** DESTRUCTOR: sqlite3_blob -** -** ^This function closes an open [BLOB handle]. ^(The BLOB handle is closed -** unconditionally. Even if this routine returns an error code, the -** handle is still closed.)^ -** -** ^If the blob handle being closed was opened for read-write access, and if -** the database is in auto-commit mode and there are no other open read-write -** blob handles or active write statements, the current transaction is -** committed. ^If an error occurs while committing the transaction, an error -** code is returned and the transaction rolled back. -** -** Calling this function with an argument that is not a NULL pointer or an -** open blob handle results in undefined behaviour. ^Calling this routine -** with a null pointer (such as would be returned by a failed call to -** [sqlite3_blob_open()]) is a harmless no-op. ^Otherwise, if this function -** is passed a valid open blob handle, the values returned by the -** sqlite3_errcode() and sqlite3_errmsg() functions are set before returning. -*/ -SQLITE_API int sqlite3_blob_close(sqlite3_blob *); - -/* -** CAPI3REF: Return The Size Of An Open BLOB -** METHOD: sqlite3_blob -** -** ^Returns the size in bytes of the BLOB accessible via the -** successfully opened [BLOB handle] in its only argument. ^The -** incremental blob I/O routines can only read or overwriting existing -** blob content; they cannot change the size of a blob. -** -** This routine only works on a [BLOB handle] which has been created -** by a prior successful call to [sqlite3_blob_open()] and which has not -** been closed by [sqlite3_blob_close()]. Passing any other pointer in -** to this routine results in undefined and probably undesirable behavior. -*/ -SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *); - -/* -** CAPI3REF: Read Data From A BLOB Incrementally -** METHOD: sqlite3_blob -** -** ^(This function is used to read data from an open [BLOB handle] into a -** caller-supplied buffer. N bytes of data are copied into buffer Z -** from the open BLOB, starting at offset iOffset.)^ -** -** ^If offset iOffset is less than N bytes from the end of the BLOB, -** [SQLITE_ERROR] is returned and no data is read. ^If N or iOffset is -** less than zero, [SQLITE_ERROR] is returned and no data is read. -** ^The size of the blob (and hence the maximum value of N+iOffset) -** can be determined using the [sqlite3_blob_bytes()] interface. -** -** ^An attempt to read from an expired [BLOB handle] fails with an -** error code of [SQLITE_ABORT]. -** -** ^(On success, sqlite3_blob_read() returns SQLITE_OK. -** Otherwise, an [error code] or an [extended error code] is returned.)^ -** -** This routine only works on a [BLOB handle] which has been created -** by a prior successful call to [sqlite3_blob_open()] and which has not -** been closed by [sqlite3_blob_close()]. Passing any other pointer in -** to this routine results in undefined and probably undesirable behavior. -** -** See also: [sqlite3_blob_write()]. -*/ -SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset); - -/* -** CAPI3REF: Write Data Into A BLOB Incrementally -** METHOD: sqlite3_blob -** -** ^(This function is used to write data into an open [BLOB handle] from a -** caller-supplied buffer. N bytes of data are copied from the buffer Z -** into the open BLOB, starting at offset iOffset.)^ -** -** ^(On success, sqlite3_blob_write() returns SQLITE_OK. -** Otherwise, an [error code] or an [extended error code] is returned.)^ -** ^Unless SQLITE_MISUSE is returned, this function sets the -** [database connection] error code and message accessible via -** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions. -** -** ^If the [BLOB handle] passed as the first argument was not opened for -** writing (the flags parameter to [sqlite3_blob_open()] was zero), -** this function returns [SQLITE_READONLY]. -** -** This function may only modify the contents of the BLOB; it is -** not possible to increase the size of a BLOB using this API. -** ^If offset iOffset is less than N bytes from the end of the BLOB, -** [SQLITE_ERROR] is returned and no data is written. The size of the -** BLOB (and hence the maximum value of N+iOffset) can be determined -** using the [sqlite3_blob_bytes()] interface. ^If N or iOffset are less -** than zero [SQLITE_ERROR] is returned and no data is written. -** -** ^An attempt to write to an expired [BLOB handle] fails with an -** error code of [SQLITE_ABORT]. ^Writes to the BLOB that occurred -** before the [BLOB handle] expired are not rolled back by the -** expiration of the handle, though of course those changes might -** have been overwritten by the statement that expired the BLOB handle -** or by other independent statements. -** -** This routine only works on a [BLOB handle] which has been created -** by a prior successful call to [sqlite3_blob_open()] and which has not -** been closed by [sqlite3_blob_close()]. Passing any other pointer in -** to this routine results in undefined and probably undesirable behavior. -** -** See also: [sqlite3_blob_read()]. -*/ -SQLITE_API int sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset); - -/* -** CAPI3REF: Virtual File System Objects -** -** A virtual filesystem (VFS) is an [sqlite3_vfs] object -** that SQLite uses to interact -** with the underlying operating system. Most SQLite builds come with a -** single default VFS that is appropriate for the host computer. -** New VFSes can be registered and existing VFSes can be unregistered. -** The following interfaces are provided. -** -** ^The sqlite3_vfs_find() interface returns a pointer to a VFS given its name. -** ^Names are case sensitive. -** ^Names are zero-terminated UTF-8 strings. -** ^If there is no match, a NULL pointer is returned. -** ^If zVfsName is NULL then the default VFS is returned. -** -** ^New VFSes are registered with sqlite3_vfs_register(). -** ^Each new VFS becomes the default VFS if the makeDflt flag is set. -** ^The same VFS can be registered multiple times without injury. -** ^To make an existing VFS into the default VFS, register it again -** with the makeDflt flag set. If two different VFSes with the -** same name are registered, the behavior is undefined. If a -** VFS is registered with a name that is NULL or an empty string, -** then the behavior is undefined. -** -** ^Unregister a VFS with the sqlite3_vfs_unregister() interface. -** ^(If the default VFS is unregistered, another VFS is chosen as -** the default. The choice for the new VFS is arbitrary.)^ -*/ -SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfsName); -SQLITE_API int sqlite3_vfs_register(sqlite3_vfs*, int makeDflt); -SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*); - -/* -** CAPI3REF: Mutexes -** -** The SQLite core uses these routines for thread -** synchronization. Though they are intended for internal -** use by SQLite, code that links against SQLite is -** permitted to use any of these routines. -** -** The SQLite source code contains multiple implementations -** of these mutex routines. An appropriate implementation -** is selected automatically at compile-time. The following -** implementations are available in the SQLite core: -** -**
    -**
  • SQLITE_MUTEX_PTHREADS -**
  • SQLITE_MUTEX_W32 -**
  • SQLITE_MUTEX_NOOP -**
-** -** The SQLITE_MUTEX_NOOP implementation is a set of routines -** that does no real locking and is appropriate for use in -** a single-threaded application. The SQLITE_MUTEX_PTHREADS and -** SQLITE_MUTEX_W32 implementations are appropriate for use on Unix -** and Windows. -** -** If SQLite is compiled with the SQLITE_MUTEX_APPDEF preprocessor -** macro defined (with "-DSQLITE_MUTEX_APPDEF=1"), then no mutex -** implementation is included with the library. In this case the -** application must supply a custom mutex implementation using the -** [SQLITE_CONFIG_MUTEX] option of the sqlite3_config() function -** before calling sqlite3_initialize() or any other public sqlite3_ -** function that calls sqlite3_initialize(). -** -** ^The sqlite3_mutex_alloc() routine allocates a new -** mutex and returns a pointer to it. ^The sqlite3_mutex_alloc() -** routine returns NULL if it is unable to allocate the requested -** mutex. The argument to sqlite3_mutex_alloc() must one of these -** integer constants: -** -**
    -**
  • SQLITE_MUTEX_FAST -**
  • SQLITE_MUTEX_RECURSIVE -**
  • SQLITE_MUTEX_STATIC_MAIN -**
  • SQLITE_MUTEX_STATIC_MEM -**
  • SQLITE_MUTEX_STATIC_OPEN -**
  • SQLITE_MUTEX_STATIC_PRNG -**
  • SQLITE_MUTEX_STATIC_LRU -**
  • SQLITE_MUTEX_STATIC_PMEM -**
  • SQLITE_MUTEX_STATIC_APP1 -**
  • SQLITE_MUTEX_STATIC_APP2 -**
  • SQLITE_MUTEX_STATIC_APP3 -**
  • SQLITE_MUTEX_STATIC_VFS1 -**
  • SQLITE_MUTEX_STATIC_VFS2 -**
  • SQLITE_MUTEX_STATIC_VFS3 -**
-** -** ^The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) -** cause sqlite3_mutex_alloc() to create -** a new mutex. ^The new mutex is recursive when SQLITE_MUTEX_RECURSIVE -** is used but not necessarily so when SQLITE_MUTEX_FAST is used. -** The mutex implementation does not need to make a distinction -** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does -** not want to. SQLite will only request a recursive mutex in -** cases where it really needs one. If a faster non-recursive mutex -** implementation is available on the host platform, the mutex subsystem -** might return such a mutex in response to SQLITE_MUTEX_FAST. -** -** ^The other allowed parameters to sqlite3_mutex_alloc() (anything other -** than SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) each return -** a pointer to a static preexisting mutex. ^Nine static mutexes are -** used by the current version of SQLite. Future versions of SQLite -** may add additional static mutexes. Static mutexes are for internal -** use by SQLite only. Applications that use SQLite mutexes should -** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or -** SQLITE_MUTEX_RECURSIVE. -** -** ^Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST -** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc() -** returns a different mutex on every call. ^For the static -** mutex types, the same mutex is returned on every call that has -** the same type number. -** -** ^The sqlite3_mutex_free() routine deallocates a previously -** allocated dynamic mutex. Attempting to deallocate a static -** mutex results in undefined behavior. -** -** ^The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt -** to enter a mutex. ^If another thread is already within the mutex, -** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return -** SQLITE_BUSY. ^The sqlite3_mutex_try() interface returns [SQLITE_OK] -** upon successful entry. ^(Mutexes created using -** SQLITE_MUTEX_RECURSIVE can be entered multiple times by the same thread. -** In such cases, the -** mutex must be exited an equal number of times before another thread -** can enter.)^ If the same thread tries to enter any mutex other -** than an SQLITE_MUTEX_RECURSIVE more than once, the behavior is undefined. -** -** ^(Some systems (for example, Windows 95) do not support the operation -** implemented by sqlite3_mutex_try(). On those systems, sqlite3_mutex_try() -** will always return SQLITE_BUSY. The SQLite core only ever uses -** sqlite3_mutex_try() as an optimization so this is acceptable -** behavior.)^ -** -** ^The sqlite3_mutex_leave() routine exits a mutex that was -** previously entered by the same thread. The behavior -** is undefined if the mutex is not currently entered by the -** calling thread or is not currently allocated. -** -** ^If the argument to sqlite3_mutex_enter(), sqlite3_mutex_try(), or -** sqlite3_mutex_leave() is a NULL pointer, then all three routines -** behave as no-ops. -** -** See also: [sqlite3_mutex_held()] and [sqlite3_mutex_notheld()]. -*/ -SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int); -SQLITE_API void sqlite3_mutex_free(sqlite3_mutex*); -SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex*); -SQLITE_API int sqlite3_mutex_try(sqlite3_mutex*); -SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*); - -/* -** CAPI3REF: Mutex Methods Object -** -** An instance of this structure defines the low-level routines -** used to allocate and use mutexes. -** -** Usually, the default mutex implementations provided by SQLite are -** sufficient, however the application has the option of substituting a custom -** implementation for specialized deployments or systems for which SQLite -** does not provide a suitable implementation. In this case, the application -** creates and populates an instance of this structure to pass -** to sqlite3_config() along with the [SQLITE_CONFIG_MUTEX] option. -** Additionally, an instance of this structure can be used as an -** output variable when querying the system for the current mutex -** implementation, using the [SQLITE_CONFIG_GETMUTEX] option. -** -** ^The xMutexInit method defined by this structure is invoked as -** part of system initialization by the sqlite3_initialize() function. -** ^The xMutexInit routine is called by SQLite exactly once for each -** effective call to [sqlite3_initialize()]. -** -** ^The xMutexEnd method defined by this structure is invoked as -** part of system shutdown by the sqlite3_shutdown() function. The -** implementation of this method is expected to release all outstanding -** resources obtained by the mutex methods implementation, especially -** those obtained by the xMutexInit method. ^The xMutexEnd() -** interface is invoked exactly once for each call to [sqlite3_shutdown()]. -** -** ^(The remaining seven methods defined by this structure (xMutexAlloc, -** xMutexFree, xMutexEnter, xMutexTry, xMutexLeave, xMutexHeld and -** xMutexNotheld) implement the following interfaces (respectively): -** -**
    -**
  • [sqlite3_mutex_alloc()]
  • -**
  • [sqlite3_mutex_free()]
  • -**
  • [sqlite3_mutex_enter()]
  • -**
  • [sqlite3_mutex_try()]
  • -**
  • [sqlite3_mutex_leave()]
  • -**
  • [sqlite3_mutex_held()]
  • -**
  • [sqlite3_mutex_notheld()]
  • -**
)^ -** -** The only difference is that the public sqlite3_XXX functions enumerated -** above silently ignore any invocations that pass a NULL pointer instead -** of a valid mutex handle. The implementations of the methods defined -** by this structure are not required to handle this case. The results -** of passing a NULL pointer instead of a valid mutex handle are undefined -** (i.e. it is acceptable to provide an implementation that segfaults if -** it is passed a NULL pointer). -** -** The xMutexInit() method must be threadsafe. It must be harmless to -** invoke xMutexInit() multiple times within the same process and without -** intervening calls to xMutexEnd(). Second and subsequent calls to -** xMutexInit() must be no-ops. -** -** xMutexInit() must not use SQLite memory allocation ([sqlite3_malloc()] -** and its associates). Similarly, xMutexAlloc() must not use SQLite memory -** allocation for a static mutex. ^However xMutexAlloc() may use SQLite -** memory allocation for a fast or recursive mutex. -** -** ^SQLite will invoke the xMutexEnd() method when [sqlite3_shutdown()] is -** called, but only if the prior call to xMutexInit returned SQLITE_OK. -** If xMutexInit fails in any way, it is expected to clean up after itself -** prior to returning. -*/ -typedef struct sqlite3_mutex_methods sqlite3_mutex_methods; -struct sqlite3_mutex_methods { - int (*xMutexInit)(void); - int (*xMutexEnd)(void); - sqlite3_mutex *(*xMutexAlloc)(int); - void (*xMutexFree)(sqlite3_mutex *); - void (*xMutexEnter)(sqlite3_mutex *); - int (*xMutexTry)(sqlite3_mutex *); - void (*xMutexLeave)(sqlite3_mutex *); - int (*xMutexHeld)(sqlite3_mutex *); - int (*xMutexNotheld)(sqlite3_mutex *); -}; - -/* -** CAPI3REF: Mutex Verification Routines -** -** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routines -** are intended for use inside assert() statements. The SQLite core -** never uses these routines except inside an assert() and applications -** are advised to follow the lead of the core. The SQLite core only -** provides implementations for these routines when it is compiled -** with the SQLITE_DEBUG flag. External mutex implementations -** are only required to provide these routines if SQLITE_DEBUG is -** defined and if NDEBUG is not defined. +** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routines +** are intended for use inside assert() statements. The SQLite core +** never uses these routines except inside an assert() and applications +** are advised to follow the lead of the core. The SQLite core only +** provides implementations for these routines when it is compiled +** with the SQLITE_DEBUG flag. External mutex implementations +** are only required to provide these routines if SQLITE_DEBUG is +** defined and if NDEBUG is not defined. ** ** These routines should return true if the mutex in their argument ** is held or not held, respectively, by the calling thread. @@ -7840,8 +7782,8 @@ struct sqlite3_mutex_methods { ** interface should also return 1 when given a NULL pointer. */ #ifndef NDEBUG -SQLITE_API int sqlite3_mutex_held(sqlite3_mutex*); -SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*); + SQLITE_API int sqlite3_mutex_held(sqlite3_mutex*); + SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*); #endif /* @@ -7854,100 +7796,99 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*); ** next. Applications that override the built-in mutex logic must be ** prepared to accommodate additional static mutexes. */ -#define SQLITE_MUTEX_FAST 0 -#define SQLITE_MUTEX_RECURSIVE 1 -#define SQLITE_MUTEX_STATIC_MAIN 2 -#define SQLITE_MUTEX_STATIC_MEM 3 /* sqlite3_malloc() */ -#define SQLITE_MUTEX_STATIC_MEM2 4 /* NOT USED */ -#define SQLITE_MUTEX_STATIC_OPEN 4 /* sqlite3BtreeOpen() */ -#define SQLITE_MUTEX_STATIC_PRNG 5 /* sqlite3_randomness() */ -#define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */ -#define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */ -#define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */ -#define SQLITE_MUTEX_STATIC_APP1 8 /* For use by application */ -#define SQLITE_MUTEX_STATIC_APP2 9 /* For use by application */ -#define SQLITE_MUTEX_STATIC_APP3 10 /* For use by application */ -#define SQLITE_MUTEX_STATIC_VFS1 11 /* For use by built-in VFS */ -#define SQLITE_MUTEX_STATIC_VFS2 12 /* For use by extension VFS */ -#define SQLITE_MUTEX_STATIC_VFS3 13 /* For use by application VFS */ +#define SQLITE_MUTEX_FAST 0 +#define SQLITE_MUTEX_RECURSIVE 1 +#define SQLITE_MUTEX_STATIC_MAIN 2 +#define SQLITE_MUTEX_STATIC_MEM 3 /* sqlite3_malloc() */ +#define SQLITE_MUTEX_STATIC_MEM2 4 /* NOT USED */ +#define SQLITE_MUTEX_STATIC_OPEN 4 /* sqlite3BtreeOpen() */ +#define SQLITE_MUTEX_STATIC_PRNG 5 /* sqlite3_randomness() */ +#define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */ +#define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */ +#define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */ +#define SQLITE_MUTEX_STATIC_APP1 8 /* For use by application */ +#define SQLITE_MUTEX_STATIC_APP2 9 /* For use by application */ +#define SQLITE_MUTEX_STATIC_APP3 10 /* For use by application */ +#define SQLITE_MUTEX_STATIC_VFS1 11 /* For use by built-in VFS */ +#define SQLITE_MUTEX_STATIC_VFS2 12 /* For use by extension VFS */ +#define SQLITE_MUTEX_STATIC_VFS3 13 /* For use by application VFS */ /* Legacy compatibility: */ -#define SQLITE_MUTEX_STATIC_MASTER 2 - - -/* -** CAPI3REF: Retrieve the mutex for a database connection -** METHOD: sqlite3 -** -** ^This interface returns a pointer the [sqlite3_mutex] object that -** serializes access to the [database connection] given in the argument -** when the [threading mode] is Serialized. -** ^If the [threading mode] is Single-thread or Multi-thread then this -** routine returns a NULL pointer. -*/ -SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*); - -/* -** CAPI3REF: Low-Level Control Of Database Files -** METHOD: sqlite3 -** KEYWORDS: {file control} -** -** ^The [sqlite3_file_control()] interface makes a direct call to the -** xFileControl method for the [sqlite3_io_methods] object associated -** with a particular database identified by the second argument. ^The -** name of the database is "main" for the main database or "temp" for the -** TEMP database, or the name that appears after the AS keyword for -** databases that are added using the [ATTACH] SQL command. -** ^A NULL pointer can be used in place of "main" to refer to the -** main database file. -** ^The third and fourth parameters to this routine -** are passed directly through to the second and third parameters of -** the xFileControl method. ^The return value of the xFileControl -** method becomes the return value of this routine. -** -** A few opcodes for [sqlite3_file_control()] are handled directly -** by the SQLite core and never invoke the -** sqlite3_io_methods.xFileControl method. -** ^The [SQLITE_FCNTL_FILE_POINTER] value for the op parameter causes -** a pointer to the underlying [sqlite3_file] object to be written into -** the space pointed to by the 4th parameter. The -** [SQLITE_FCNTL_JOURNAL_POINTER] works similarly except that it returns -** the [sqlite3_file] object associated with the journal file instead of -** the main database. The [SQLITE_FCNTL_VFS_POINTER] opcode returns -** a pointer to the underlying [sqlite3_vfs] object for the file. -** The [SQLITE_FCNTL_DATA_VERSION] returns the data version counter -** from the pager. -** -** ^If the second parameter (zDbName) does not match the name of any -** open database file, then SQLITE_ERROR is returned. ^This error -** code is not remembered and will not be recalled by [sqlite3_errcode()] -** or [sqlite3_errmsg()]. The underlying xFileControl method might -** also return SQLITE_ERROR. There is no way to distinguish between -** an incorrect zDbName and an SQLITE_ERROR return from the underlying -** xFileControl method. -** -** See also: [file control opcodes] -*/ -SQLITE_API int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*); - -/* -** CAPI3REF: Testing Interface -** -** ^The sqlite3_test_control() interface is used to read out internal -** state of SQLite and to inject faults into SQLite for testing -** purposes. ^The first parameter is an operation code that determines -** the number, meaning, and operation of all subsequent parameters. -** -** This interface is not for use by applications. It exists solely -** for verifying the correct operation of the SQLite library. Depending -** on how the SQLite library is compiled, this interface might not exist. -** -** The details of the operation codes, their meanings, the parameters -** they take, and what they do are all subject to change without notice. -** Unlike most of the SQLite API, this function is not guaranteed to -** operate consistently from one release to the next. -*/ -SQLITE_API int sqlite3_test_control(int op, ...); +#define SQLITE_MUTEX_STATIC_MASTER 2 + + /* + ** CAPI3REF: Retrieve the mutex for a database connection + ** METHOD: sqlite3 + ** + ** ^This interface returns a pointer the [sqlite3_mutex] object that + ** serializes access to the [database connection] given in the argument + ** when the [threading mode] is Serialized. + ** ^If the [threading mode] is Single-thread or Multi-thread then this + ** routine returns a NULL pointer. + */ + SQLITE_API sqlite3_mutex* sqlite3_db_mutex(sqlite3*); + + /* + ** CAPI3REF: Low-Level Control Of Database Files + ** METHOD: sqlite3 + ** KEYWORDS: {file control} + ** + ** ^The [sqlite3_file_control()] interface makes a direct call to the + ** xFileControl method for the [sqlite3_io_methods] object associated + ** with a particular database identified by the second argument. ^The + ** name of the database is "main" for the main database or "temp" for the + ** TEMP database, or the name that appears after the AS keyword for + ** databases that are added using the [ATTACH] SQL command. + ** ^A NULL pointer can be used in place of "main" to refer to the + ** main database file. + ** ^The third and fourth parameters to this routine + ** are passed directly through to the second and third parameters of + ** the xFileControl method. ^The return value of the xFileControl + ** method becomes the return value of this routine. + ** + ** A few opcodes for [sqlite3_file_control()] are handled directly + ** by the SQLite core and never invoke the + ** sqlite3_io_methods.xFileControl method. + ** ^The [SQLITE_FCNTL_FILE_POINTER] value for the op parameter causes + ** a pointer to the underlying [sqlite3_file] object to be written into + ** the space pointed to by the 4th parameter. The + ** [SQLITE_FCNTL_JOURNAL_POINTER] works similarly except that it returns + ** the [sqlite3_file] object associated with the journal file instead of + ** the main database. The [SQLITE_FCNTL_VFS_POINTER] opcode returns + ** a pointer to the underlying [sqlite3_vfs] object for the file. + ** The [SQLITE_FCNTL_DATA_VERSION] returns the data version counter + ** from the pager. + ** + ** ^If the second parameter (zDbName) does not match the name of any + ** open database file, then SQLITE_ERROR is returned. ^This error + ** code is not remembered and will not be recalled by [sqlite3_errcode()] + ** or [sqlite3_errmsg()]. The underlying xFileControl method might + ** also return SQLITE_ERROR. There is no way to distinguish between + ** an incorrect zDbName and an SQLITE_ERROR return from the underlying + ** xFileControl method. + ** + ** See also: [file control opcodes] + */ + SQLITE_API int sqlite3_file_control(sqlite3*, const char* zDbName, int op, void*); + + /* + ** CAPI3REF: Testing Interface + ** + ** ^The sqlite3_test_control() interface is used to read out internal + ** state of SQLite and to inject faults into SQLite for testing + ** purposes. ^The first parameter is an operation code that determines + ** the number, meaning, and operation of all subsequent parameters. + ** + ** This interface is not for use by applications. It exists solely + ** for verifying the correct operation of the SQLite library. Depending + ** on how the SQLite library is compiled, this interface might not exist. + ** + ** The details of the operation codes, their meanings, the parameters + ** they take, and what they do are all subject to change without notice. + ** Unlike most of the SQLite API, this function is not guaranteed to + ** operate consistently from one release to the next. + */ + SQLITE_API int sqlite3_test_control(int op, ...); /* ** CAPI3REF: Testing Interface Operation Codes @@ -7960,257 +7901,251 @@ SQLITE_API int sqlite3_test_control(int op, ...); ** Applications should not use any of these parameters or the ** [sqlite3_test_control()] interface. */ -#define SQLITE_TESTCTRL_FIRST 5 -#define SQLITE_TESTCTRL_PRNG_SAVE 5 -#define SQLITE_TESTCTRL_PRNG_RESTORE 6 -#define SQLITE_TESTCTRL_PRNG_RESET 7 /* NOT USED */ -#define SQLITE_TESTCTRL_BITVEC_TEST 8 -#define SQLITE_TESTCTRL_FAULT_INSTALL 9 -#define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS 10 -#define SQLITE_TESTCTRL_PENDING_BYTE 11 -#define SQLITE_TESTCTRL_ASSERT 12 -#define SQLITE_TESTCTRL_ALWAYS 13 -#define SQLITE_TESTCTRL_RESERVE 14 /* NOT USED */ -#define SQLITE_TESTCTRL_OPTIMIZATIONS 15 -#define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */ -#define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */ -#define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17 -#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 -#define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */ -#define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD 19 -#define SQLITE_TESTCTRL_NEVER_CORRUPT 20 -#define SQLITE_TESTCTRL_VDBE_COVERAGE 21 -#define SQLITE_TESTCTRL_BYTEORDER 22 -#define SQLITE_TESTCTRL_ISINIT 23 -#define SQLITE_TESTCTRL_SORTER_MMAP 24 -#define SQLITE_TESTCTRL_IMPOSTER 25 -#define SQLITE_TESTCTRL_PARSER_COVERAGE 26 -#define SQLITE_TESTCTRL_RESULT_INTREAL 27 -#define SQLITE_TESTCTRL_PRNG_SEED 28 -#define SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS 29 -#define SQLITE_TESTCTRL_SEEK_COUNT 30 -#define SQLITE_TESTCTRL_TRACEFLAGS 31 -#define SQLITE_TESTCTRL_TUNE 32 -#define SQLITE_TESTCTRL_LOGEST 33 -#define SQLITE_TESTCTRL_LAST 33 /* Largest TESTCTRL */ - -/* -** CAPI3REF: SQL Keyword Checking -** -** These routines provide access to the set of SQL language keywords -** recognized by SQLite. Applications can uses these routines to determine -** whether or not a specific identifier needs to be escaped (for example, -** by enclosing in double-quotes) so as not to confuse the parser. -** -** The sqlite3_keyword_count() interface returns the number of distinct -** keywords understood by SQLite. -** -** The sqlite3_keyword_name(N,Z,L) interface finds the N-th keyword and -** makes *Z point to that keyword expressed as UTF8 and writes the number -** of bytes in the keyword into *L. The string that *Z points to is not -** zero-terminated. The sqlite3_keyword_name(N,Z,L) routine returns -** SQLITE_OK if N is within bounds and SQLITE_ERROR if not. If either Z -** or L are NULL or invalid pointers then calls to -** sqlite3_keyword_name(N,Z,L) result in undefined behavior. -** -** The sqlite3_keyword_check(Z,L) interface checks to see whether or not -** the L-byte UTF8 identifier that Z points to is a keyword, returning non-zero -** if it is and zero if not. -** -** The parser used by SQLite is forgiving. It is often possible to use -** a keyword as an identifier as long as such use does not result in a -** parsing ambiguity. For example, the statement -** "CREATE TABLE BEGIN(REPLACE,PRAGMA,END);" is accepted by SQLite, and -** creates a new table named "BEGIN" with three columns named -** "REPLACE", "PRAGMA", and "END". Nevertheless, best practice is to avoid -** using keywords as identifiers. Common techniques used to avoid keyword -** name collisions include: -**
    -**
  • Put all identifier names inside double-quotes. This is the official -** SQL way to escape identifier names. -**
  • Put identifier names inside [...]. This is not standard SQL, -** but it is what SQL Server does and so lots of programmers use this -** technique. -**
  • Begin every identifier with the letter "Z" as no SQL keywords start -** with "Z". -**
  • Include a digit somewhere in every identifier name. -**
-** -** Note that the number of keywords understood by SQLite can depend on -** compile-time options. For example, "VACUUM" is not a keyword if -** SQLite is compiled with the [-DSQLITE_OMIT_VACUUM] option. Also, -** new keywords may be added to future releases of SQLite. -*/ -SQLITE_API int sqlite3_keyword_count(void); -SQLITE_API int sqlite3_keyword_name(int,const char**,int*); -SQLITE_API int sqlite3_keyword_check(const char*,int); - -/* -** CAPI3REF: Dynamic String Object -** KEYWORDS: {dynamic string} -** -** An instance of the sqlite3_str object contains a dynamically-sized -** string under construction. -** -** The lifecycle of an sqlite3_str object is as follows: -**
    -**
  1. ^The sqlite3_str object is created using [sqlite3_str_new()]. -**
  2. ^Text is appended to the sqlite3_str object using various -** methods, such as [sqlite3_str_appendf()]. -**
  3. ^The sqlite3_str object is destroyed and the string it created -** is returned using the [sqlite3_str_finish()] interface. -**
-*/ -typedef struct sqlite3_str sqlite3_str; - -/* -** CAPI3REF: Create A New Dynamic String Object -** CONSTRUCTOR: sqlite3_str -** -** ^The [sqlite3_str_new(D)] interface allocates and initializes -** a new [sqlite3_str] object. To avoid memory leaks, the object returned by -** [sqlite3_str_new()] must be freed by a subsequent call to -** [sqlite3_str_finish(X)]. -** -** ^The [sqlite3_str_new(D)] interface always returns a pointer to a -** valid [sqlite3_str] object, though in the event of an out-of-memory -** error the returned object might be a special singleton that will -** silently reject new text, always return SQLITE_NOMEM from -** [sqlite3_str_errcode()], always return 0 for -** [sqlite3_str_length()], and always return NULL from -** [sqlite3_str_finish(X)]. It is always safe to use the value -** returned by [sqlite3_str_new(D)] as the sqlite3_str parameter -** to any of the other [sqlite3_str] methods. -** -** The D parameter to [sqlite3_str_new(D)] may be NULL. If the -** D parameter in [sqlite3_str_new(D)] is not NULL, then the maximum -** length of the string contained in the [sqlite3_str] object will be -** the value set for [sqlite3_limit](D,[SQLITE_LIMIT_LENGTH]) instead -** of [SQLITE_MAX_LENGTH]. -*/ -SQLITE_API sqlite3_str *sqlite3_str_new(sqlite3*); - -/* -** CAPI3REF: Finalize A Dynamic String -** DESTRUCTOR: sqlite3_str -** -** ^The [sqlite3_str_finish(X)] interface destroys the sqlite3_str object X -** and returns a pointer to a memory buffer obtained from [sqlite3_malloc64()] -** that contains the constructed string. The calling application should -** pass the returned value to [sqlite3_free()] to avoid a memory leak. -** ^The [sqlite3_str_finish(X)] interface may return a NULL pointer if any -** errors were encountered during construction of the string. ^The -** [sqlite3_str_finish(X)] interface will also return a NULL pointer if the -** string in [sqlite3_str] object X is zero bytes long. -*/ -SQLITE_API char *sqlite3_str_finish(sqlite3_str*); - -/* -** CAPI3REF: Add Content To A Dynamic String -** METHOD: sqlite3_str -** -** These interfaces add content to an sqlite3_str object previously obtained -** from [sqlite3_str_new()]. -** -** ^The [sqlite3_str_appendf(X,F,...)] and -** [sqlite3_str_vappendf(X,F,V)] interfaces uses the [built-in printf] -** functionality of SQLite to append formatted text onto the end of -** [sqlite3_str] object X. -** -** ^The [sqlite3_str_append(X,S,N)] method appends exactly N bytes from string S -** onto the end of the [sqlite3_str] object X. N must be non-negative. -** S must contain at least N non-zero bytes of content. To append a -** zero-terminated string in its entirety, use the [sqlite3_str_appendall()] -** method instead. -** -** ^The [sqlite3_str_appendall(X,S)] method appends the complete content of -** zero-terminated string S onto the end of [sqlite3_str] object X. -** -** ^The [sqlite3_str_appendchar(X,N,C)] method appends N copies of the -** single-byte character C onto the end of [sqlite3_str] object X. -** ^This method can be used, for example, to add whitespace indentation. -** -** ^The [sqlite3_str_reset(X)] method resets the string under construction -** inside [sqlite3_str] object X back to zero bytes in length. -** -** These methods do not return a result code. ^If an error occurs, that fact -** is recorded in the [sqlite3_str] object and can be recovered by a -** subsequent call to [sqlite3_str_errcode(X)]. -*/ -SQLITE_API void sqlite3_str_appendf(sqlite3_str*, const char *zFormat, ...); -SQLITE_API void sqlite3_str_vappendf(sqlite3_str*, const char *zFormat, va_list); -SQLITE_API void sqlite3_str_append(sqlite3_str*, const char *zIn, int N); -SQLITE_API void sqlite3_str_appendall(sqlite3_str*, const char *zIn); -SQLITE_API void sqlite3_str_appendchar(sqlite3_str*, int N, char C); -SQLITE_API void sqlite3_str_reset(sqlite3_str*); - -/* -** CAPI3REF: Status Of A Dynamic String -** METHOD: sqlite3_str -** -** These interfaces return the current status of an [sqlite3_str] object. -** -** ^If any prior errors have occurred while constructing the dynamic string -** in sqlite3_str X, then the [sqlite3_str_errcode(X)] method will return -** an appropriate error code. ^The [sqlite3_str_errcode(X)] method returns -** [SQLITE_NOMEM] following any out-of-memory error, or -** [SQLITE_TOOBIG] if the size of the dynamic string exceeds -** [SQLITE_MAX_LENGTH], or [SQLITE_OK] if there have been no errors. -** -** ^The [sqlite3_str_length(X)] method returns the current length, in bytes, -** of the dynamic string under construction in [sqlite3_str] object X. -** ^The length returned by [sqlite3_str_length(X)] does not include the -** zero-termination byte. -** -** ^The [sqlite3_str_value(X)] method returns a pointer to the current -** content of the dynamic string under construction in X. The value -** returned by [sqlite3_str_value(X)] is managed by the sqlite3_str object X -** and might be freed or altered by any subsequent method on the same -** [sqlite3_str] object. Applications must not used the pointer returned -** [sqlite3_str_value(X)] after any subsequent method call on the same -** object. ^Applications may change the content of the string returned -** by [sqlite3_str_value(X)] as long as they do not write into any bytes -** outside the range of 0 to [sqlite3_str_length(X)] and do not read or -** write any byte after any subsequent sqlite3_str method call. -*/ -SQLITE_API int sqlite3_str_errcode(sqlite3_str*); -SQLITE_API int sqlite3_str_length(sqlite3_str*); -SQLITE_API char *sqlite3_str_value(sqlite3_str*); - -/* -** CAPI3REF: SQLite Runtime Status -** -** ^These interfaces are used to retrieve runtime status information -** about the performance of SQLite, and optionally to reset various -** highwater marks. ^The first argument is an integer code for -** the specific parameter to measure. ^(Recognized integer codes -** are of the form [status parameters | SQLITE_STATUS_...].)^ -** ^The current value of the parameter is returned into *pCurrent. -** ^The highest recorded value is returned in *pHighwater. ^If the -** resetFlag is true, then the highest record value is reset after -** *pHighwater is written. ^(Some parameters do not record the highest -** value. For those parameters -** nothing is written into *pHighwater and the resetFlag is ignored.)^ -** ^(Other parameters record only the highwater mark and not the current -** value. For these latter parameters nothing is written into *pCurrent.)^ -** -** ^The sqlite3_status() and sqlite3_status64() routines return -** SQLITE_OK on success and a non-zero [error code] on failure. -** -** If either the current value or the highwater mark is too large to -** be represented by a 32-bit integer, then the values returned by -** sqlite3_status() are undefined. -** -** See also: [sqlite3_db_status()] -*/ -SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag); -SQLITE_API int sqlite3_status64( - int op, - sqlite3_int64 *pCurrent, - sqlite3_int64 *pHighwater, - int resetFlag -); - +#define SQLITE_TESTCTRL_FIRST 5 +#define SQLITE_TESTCTRL_PRNG_SAVE 5 +#define SQLITE_TESTCTRL_PRNG_RESTORE 6 +#define SQLITE_TESTCTRL_PRNG_RESET 7 /* NOT USED */ +#define SQLITE_TESTCTRL_BITVEC_TEST 8 +#define SQLITE_TESTCTRL_FAULT_INSTALL 9 +#define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS 10 +#define SQLITE_TESTCTRL_PENDING_BYTE 11 +#define SQLITE_TESTCTRL_ASSERT 12 +#define SQLITE_TESTCTRL_ALWAYS 13 +#define SQLITE_TESTCTRL_RESERVE 14 /* NOT USED */ +#define SQLITE_TESTCTRL_OPTIMIZATIONS 15 +#define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */ +#define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */ +#define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17 +#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 +#define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */ +#define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD 19 +#define SQLITE_TESTCTRL_NEVER_CORRUPT 20 +#define SQLITE_TESTCTRL_VDBE_COVERAGE 21 +#define SQLITE_TESTCTRL_BYTEORDER 22 +#define SQLITE_TESTCTRL_ISINIT 23 +#define SQLITE_TESTCTRL_SORTER_MMAP 24 +#define SQLITE_TESTCTRL_IMPOSTER 25 +#define SQLITE_TESTCTRL_PARSER_COVERAGE 26 +#define SQLITE_TESTCTRL_RESULT_INTREAL 27 +#define SQLITE_TESTCTRL_PRNG_SEED 28 +#define SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS 29 +#define SQLITE_TESTCTRL_SEEK_COUNT 30 +#define SQLITE_TESTCTRL_TRACEFLAGS 31 +#define SQLITE_TESTCTRL_TUNE 32 +#define SQLITE_TESTCTRL_LOGEST 33 +#define SQLITE_TESTCTRL_LAST 33 /* Largest TESTCTRL */ + + /* + ** CAPI3REF: SQL Keyword Checking + ** + ** These routines provide access to the set of SQL language keywords + ** recognized by SQLite. Applications can uses these routines to determine + ** whether or not a specific identifier needs to be escaped (for example, + ** by enclosing in double-quotes) so as not to confuse the parser. + ** + ** The sqlite3_keyword_count() interface returns the number of distinct + ** keywords understood by SQLite. + ** + ** The sqlite3_keyword_name(N,Z,L) interface finds the N-th keyword and + ** makes *Z point to that keyword expressed as UTF8 and writes the number + ** of bytes in the keyword into *L. The string that *Z points to is not + ** zero-terminated. The sqlite3_keyword_name(N,Z,L) routine returns + ** SQLITE_OK if N is within bounds and SQLITE_ERROR if not. If either Z + ** or L are NULL or invalid pointers then calls to + ** sqlite3_keyword_name(N,Z,L) result in undefined behavior. + ** + ** The sqlite3_keyword_check(Z,L) interface checks to see whether or not + ** the L-byte UTF8 identifier that Z points to is a keyword, returning non-zero + ** if it is and zero if not. + ** + ** The parser used by SQLite is forgiving. It is often possible to use + ** a keyword as an identifier as long as such use does not result in a + ** parsing ambiguity. For example, the statement + ** "CREATE TABLE BEGIN(REPLACE,PRAGMA,END);" is accepted by SQLite, and + ** creates a new table named "BEGIN" with three columns named + ** "REPLACE", "PRAGMA", and "END". Nevertheless, best practice is to avoid + ** using keywords as identifiers. Common techniques used to avoid keyword + ** name collisions include: + **
    + **
  • Put all identifier names inside double-quotes. This is the official + ** SQL way to escape identifier names. + **
  • Put identifier names inside [...]. This is not standard SQL, + ** but it is what SQL Server does and so lots of programmers use this + ** technique. + **
  • Begin every identifier with the letter "Z" as no SQL keywords start + ** with "Z". + **
  • Include a digit somewhere in every identifier name. + **
+ ** + ** Note that the number of keywords understood by SQLite can depend on + ** compile-time options. For example, "VACUUM" is not a keyword if + ** SQLite is compiled with the [-DSQLITE_OMIT_VACUUM] option. Also, + ** new keywords may be added to future releases of SQLite. + */ + SQLITE_API int sqlite3_keyword_count(void); + SQLITE_API int sqlite3_keyword_name(int, const char**, int*); + SQLITE_API int sqlite3_keyword_check(const char*, int); + + /* + ** CAPI3REF: Dynamic String Object + ** KEYWORDS: {dynamic string} + ** + ** An instance of the sqlite3_str object contains a dynamically-sized + ** string under construction. + ** + ** The lifecycle of an sqlite3_str object is as follows: + **
    + **
  1. ^The sqlite3_str object is created using [sqlite3_str_new()]. + **
  2. ^Text is appended to the sqlite3_str object using various + ** methods, such as [sqlite3_str_appendf()]. + **
  3. ^The sqlite3_str object is destroyed and the string it created + ** is returned using the [sqlite3_str_finish()] interface. + **
+ */ + typedef struct sqlite3_str sqlite3_str; + + /* + ** CAPI3REF: Create A New Dynamic String Object + ** CONSTRUCTOR: sqlite3_str + ** + ** ^The [sqlite3_str_new(D)] interface allocates and initializes + ** a new [sqlite3_str] object. To avoid memory leaks, the object returned by + ** [sqlite3_str_new()] must be freed by a subsequent call to + ** [sqlite3_str_finish(X)]. + ** + ** ^The [sqlite3_str_new(D)] interface always returns a pointer to a + ** valid [sqlite3_str] object, though in the event of an out-of-memory + ** error the returned object might be a special singleton that will + ** silently reject new text, always return SQLITE_NOMEM from + ** [sqlite3_str_errcode()], always return 0 for + ** [sqlite3_str_length()], and always return NULL from + ** [sqlite3_str_finish(X)]. It is always safe to use the value + ** returned by [sqlite3_str_new(D)] as the sqlite3_str parameter + ** to any of the other [sqlite3_str] methods. + ** + ** The D parameter to [sqlite3_str_new(D)] may be NULL. If the + ** D parameter in [sqlite3_str_new(D)] is not NULL, then the maximum + ** length of the string contained in the [sqlite3_str] object will be + ** the value set for [sqlite3_limit](D,[SQLITE_LIMIT_LENGTH]) instead + ** of [SQLITE_MAX_LENGTH]. + */ + SQLITE_API sqlite3_str* sqlite3_str_new(sqlite3*); + + /* + ** CAPI3REF: Finalize A Dynamic String + ** DESTRUCTOR: sqlite3_str + ** + ** ^The [sqlite3_str_finish(X)] interface destroys the sqlite3_str object X + ** and returns a pointer to a memory buffer obtained from [sqlite3_malloc64()] + ** that contains the constructed string. The calling application should + ** pass the returned value to [sqlite3_free()] to avoid a memory leak. + ** ^The [sqlite3_str_finish(X)] interface may return a NULL pointer if any + ** errors were encountered during construction of the string. ^The + ** [sqlite3_str_finish(X)] interface will also return a NULL pointer if the + ** string in [sqlite3_str] object X is zero bytes long. + */ + SQLITE_API char* sqlite3_str_finish(sqlite3_str*); + + /* + ** CAPI3REF: Add Content To A Dynamic String + ** METHOD: sqlite3_str + ** + ** These interfaces add content to an sqlite3_str object previously obtained + ** from [sqlite3_str_new()]. + ** + ** ^The [sqlite3_str_appendf(X,F,...)] and + ** [sqlite3_str_vappendf(X,F,V)] interfaces uses the [built-in printf] + ** functionality of SQLite to append formatted text onto the end of + ** [sqlite3_str] object X. + ** + ** ^The [sqlite3_str_append(X,S,N)] method appends exactly N bytes from string S + ** onto the end of the [sqlite3_str] object X. N must be non-negative. + ** S must contain at least N non-zero bytes of content. To append a + ** zero-terminated string in its entirety, use the [sqlite3_str_appendall()] + ** method instead. + ** + ** ^The [sqlite3_str_appendall(X,S)] method appends the complete content of + ** zero-terminated string S onto the end of [sqlite3_str] object X. + ** + ** ^The [sqlite3_str_appendchar(X,N,C)] method appends N copies of the + ** single-byte character C onto the end of [sqlite3_str] object X. + ** ^This method can be used, for example, to add whitespace indentation. + ** + ** ^The [sqlite3_str_reset(X)] method resets the string under construction + ** inside [sqlite3_str] object X back to zero bytes in length. + ** + ** These methods do not return a result code. ^If an error occurs, that fact + ** is recorded in the [sqlite3_str] object and can be recovered by a + ** subsequent call to [sqlite3_str_errcode(X)]. + */ + SQLITE_API void sqlite3_str_appendf(sqlite3_str*, const char* zFormat, ...); + SQLITE_API void sqlite3_str_vappendf(sqlite3_str*, const char* zFormat, va_list); + SQLITE_API void sqlite3_str_append(sqlite3_str*, const char* zIn, int N); + SQLITE_API void sqlite3_str_appendall(sqlite3_str*, const char* zIn); + SQLITE_API void sqlite3_str_appendchar(sqlite3_str*, int N, char C); + SQLITE_API void sqlite3_str_reset(sqlite3_str*); + + /* + ** CAPI3REF: Status Of A Dynamic String + ** METHOD: sqlite3_str + ** + ** These interfaces return the current status of an [sqlite3_str] object. + ** + ** ^If any prior errors have occurred while constructing the dynamic string + ** in sqlite3_str X, then the [sqlite3_str_errcode(X)] method will return + ** an appropriate error code. ^The [sqlite3_str_errcode(X)] method returns + ** [SQLITE_NOMEM] following any out-of-memory error, or + ** [SQLITE_TOOBIG] if the size of the dynamic string exceeds + ** [SQLITE_MAX_LENGTH], or [SQLITE_OK] if there have been no errors. + ** + ** ^The [sqlite3_str_length(X)] method returns the current length, in bytes, + ** of the dynamic string under construction in [sqlite3_str] object X. + ** ^The length returned by [sqlite3_str_length(X)] does not include the + ** zero-termination byte. + ** + ** ^The [sqlite3_str_value(X)] method returns a pointer to the current + ** content of the dynamic string under construction in X. The value + ** returned by [sqlite3_str_value(X)] is managed by the sqlite3_str object X + ** and might be freed or altered by any subsequent method on the same + ** [sqlite3_str] object. Applications must not used the pointer returned + ** [sqlite3_str_value(X)] after any subsequent method call on the same + ** object. ^Applications may change the content of the string returned + ** by [sqlite3_str_value(X)] as long as they do not write into any bytes + ** outside the range of 0 to [sqlite3_str_length(X)] and do not read or + ** write any byte after any subsequent sqlite3_str method call. + */ + SQLITE_API int sqlite3_str_errcode(sqlite3_str*); + SQLITE_API int sqlite3_str_length(sqlite3_str*); + SQLITE_API char* sqlite3_str_value(sqlite3_str*); + + /* + ** CAPI3REF: SQLite Runtime Status + ** + ** ^These interfaces are used to retrieve runtime status information + ** about the performance of SQLite, and optionally to reset various + ** highwater marks. ^The first argument is an integer code for + ** the specific parameter to measure. ^(Recognized integer codes + ** are of the form [status parameters | SQLITE_STATUS_...].)^ + ** ^The current value of the parameter is returned into *pCurrent. + ** ^The highest recorded value is returned in *pHighwater. ^If the + ** resetFlag is true, then the highest record value is reset after + ** *pHighwater is written. ^(Some parameters do not record the highest + ** value. For those parameters + ** nothing is written into *pHighwater and the resetFlag is ignored.)^ + ** ^(Other parameters record only the highwater mark and not the current + ** value. For these latter parameters nothing is written into *pCurrent.)^ + ** + ** ^The sqlite3_status() and sqlite3_status64() routines return + ** SQLITE_OK on success and a non-zero [error code] on failure. + ** + ** If either the current value or the highwater mark is too large to + ** be represented by a 32-bit integer, then the values returned by + ** sqlite3_status() are undefined. + ** + ** See also: [sqlite3_db_status()] + */ + SQLITE_API int sqlite3_status(int op, int* pCurrent, int* pHighwater, int resetFlag); + SQLITE_API int sqlite3_status64(int op, sqlite3_int64* pCurrent, sqlite3_int64* pHighwater, int resetFlag); /* ** CAPI3REF: Status Parameters @@ -8279,48 +8214,48 @@ SQLITE_API int sqlite3_status64( ** ** New status parameters may be added from time to time. */ -#define SQLITE_STATUS_MEMORY_USED 0 -#define SQLITE_STATUS_PAGECACHE_USED 1 -#define SQLITE_STATUS_PAGECACHE_OVERFLOW 2 -#define SQLITE_STATUS_SCRATCH_USED 3 /* NOT USED */ -#define SQLITE_STATUS_SCRATCH_OVERFLOW 4 /* NOT USED */ -#define SQLITE_STATUS_MALLOC_SIZE 5 -#define SQLITE_STATUS_PARSER_STACK 6 -#define SQLITE_STATUS_PAGECACHE_SIZE 7 -#define SQLITE_STATUS_SCRATCH_SIZE 8 /* NOT USED */ -#define SQLITE_STATUS_MALLOC_COUNT 9 +#define SQLITE_STATUS_MEMORY_USED 0 +#define SQLITE_STATUS_PAGECACHE_USED 1 +#define SQLITE_STATUS_PAGECACHE_OVERFLOW 2 +#define SQLITE_STATUS_SCRATCH_USED 3 /* NOT USED */ +#define SQLITE_STATUS_SCRATCH_OVERFLOW 4 /* NOT USED */ +#define SQLITE_STATUS_MALLOC_SIZE 5 +#define SQLITE_STATUS_PARSER_STACK 6 +#define SQLITE_STATUS_PAGECACHE_SIZE 7 +#define SQLITE_STATUS_SCRATCH_SIZE 8 /* NOT USED */ +#define SQLITE_STATUS_MALLOC_COUNT 9 + + /* + ** CAPI3REF: Database Connection Status + ** METHOD: sqlite3 + ** + ** ^This interface is used to retrieve runtime status information + ** about a single [database connection]. ^The first argument is the + ** database connection object to be interrogated. ^The second argument + ** is an integer constant, taken from the set of + ** [SQLITE_DBSTATUS options], that + ** determines the parameter to interrogate. The set of + ** [SQLITE_DBSTATUS options] is likely + ** to grow in future releases of SQLite. + ** + ** ^The current value of the requested parameter is written into *pCur + ** and the highest instantaneous value is written into *pHiwtr. ^If + ** the resetFlg is true, then the highest instantaneous value is + ** reset back down to the current value. + ** + ** ^The sqlite3_db_status() routine returns SQLITE_OK on success and a + ** non-zero [error code] on failure. + ** + ** See also: [sqlite3_status()] and [sqlite3_stmt_status()]. + */ + SQLITE_API int sqlite3_db_status(sqlite3*, int op, int* pCur, int* pHiwtr, int resetFlg); /* -** CAPI3REF: Database Connection Status -** METHOD: sqlite3 +** CAPI3REF: Status Parameters for database connections +** KEYWORDS: {SQLITE_DBSTATUS options} ** -** ^This interface is used to retrieve runtime status information -** about a single [database connection]. ^The first argument is the -** database connection object to be interrogated. ^The second argument -** is an integer constant, taken from the set of -** [SQLITE_DBSTATUS options], that -** determines the parameter to interrogate. The set of -** [SQLITE_DBSTATUS options] is likely -** to grow in future releases of SQLite. -** -** ^The current value of the requested parameter is written into *pCur -** and the highest instantaneous value is written into *pHiwtr. ^If -** the resetFlg is true, then the highest instantaneous value is -** reset back down to the current value. -** -** ^The sqlite3_db_status() routine returns SQLITE_OK on success and a -** non-zero [error code] on failure. -** -** See also: [sqlite3_status()] and [sqlite3_stmt_status()]. -*/ -SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); - -/* -** CAPI3REF: Status Parameters for database connections -** KEYWORDS: {SQLITE_DBSTATUS options} -** -** These constants are the available integer "verbs" that can be passed as -** the second argument to the [sqlite3_db_status()] interface. +** These constants are the available integer "verbs" that can be passed as +** the second argument to the [sqlite3_db_status()] interface. ** ** New verbs may be added in future releases of SQLite. Existing verbs ** might be discontinued. Applications should check the return code from @@ -8426,47 +8361,46 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r ** ** */ -#define SQLITE_DBSTATUS_LOOKASIDE_USED 0 -#define SQLITE_DBSTATUS_CACHE_USED 1 -#define SQLITE_DBSTATUS_SCHEMA_USED 2 -#define SQLITE_DBSTATUS_STMT_USED 3 -#define SQLITE_DBSTATUS_LOOKASIDE_HIT 4 -#define SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE 5 -#define SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL 6 -#define SQLITE_DBSTATUS_CACHE_HIT 7 -#define SQLITE_DBSTATUS_CACHE_MISS 8 -#define SQLITE_DBSTATUS_CACHE_WRITE 9 -#define SQLITE_DBSTATUS_DEFERRED_FKS 10 -#define SQLITE_DBSTATUS_CACHE_USED_SHARED 11 -#define SQLITE_DBSTATUS_CACHE_SPILL 12 -#define SQLITE_DBSTATUS_MAX 12 /* Largest defined DBSTATUS */ - - -/* -** CAPI3REF: Prepared Statement Status -** METHOD: sqlite3_stmt -** -** ^(Each prepared statement maintains various -** [SQLITE_STMTSTATUS counters] that measure the number -** of times it has performed specific operations.)^ These counters can -** be used to monitor the performance characteristics of the prepared -** statements. For example, if the number of table steps greatly exceeds -** the number of table searches or result rows, that would tend to indicate -** that the prepared statement is using a full table scan rather than -** an index. -** -** ^(This interface is used to retrieve and reset counter values from -** a [prepared statement]. The first argument is the prepared statement -** object to be interrogated. The second argument -** is an integer code for a specific [SQLITE_STMTSTATUS counter] -** to be interrogated.)^ -** ^The current value of the requested counter is returned. -** ^If the resetFlg is true, then the counter is reset to zero after this -** interface call returns. -** -** See also: [sqlite3_status()] and [sqlite3_db_status()]. -*/ -SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); +#define SQLITE_DBSTATUS_LOOKASIDE_USED 0 +#define SQLITE_DBSTATUS_CACHE_USED 1 +#define SQLITE_DBSTATUS_SCHEMA_USED 2 +#define SQLITE_DBSTATUS_STMT_USED 3 +#define SQLITE_DBSTATUS_LOOKASIDE_HIT 4 +#define SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE 5 +#define SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL 6 +#define SQLITE_DBSTATUS_CACHE_HIT 7 +#define SQLITE_DBSTATUS_CACHE_MISS 8 +#define SQLITE_DBSTATUS_CACHE_WRITE 9 +#define SQLITE_DBSTATUS_DEFERRED_FKS 10 +#define SQLITE_DBSTATUS_CACHE_USED_SHARED 11 +#define SQLITE_DBSTATUS_CACHE_SPILL 12 +#define SQLITE_DBSTATUS_MAX 12 /* Largest defined DBSTATUS */ + + /* + ** CAPI3REF: Prepared Statement Status + ** METHOD: sqlite3_stmt + ** + ** ^(Each prepared statement maintains various + ** [SQLITE_STMTSTATUS counters] that measure the number + ** of times it has performed specific operations.)^ These counters can + ** be used to monitor the performance characteristics of the prepared + ** statements. For example, if the number of table steps greatly exceeds + ** the number of table searches or result rows, that would tend to indicate + ** that the prepared statement is using a full table scan rather than + ** an index. + ** + ** ^(This interface is used to retrieve and reset counter values from + ** a [prepared statement]. The first argument is the prepared statement + ** object to be interrogated. The second argument + ** is an integer code for a specific [SQLITE_STMTSTATUS counter] + ** to be interrogated.)^ + ** ^The current value of the requested counter is returned. + ** ^If the resetFlg is true, then the counter is reset to zero after this + ** interface call returns. + ** + ** See also: [sqlite3_status()] and [sqlite3_db_status()]. + */ + SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op, int resetFlg); /* ** CAPI3REF: Status Parameters for prepared statements @@ -8533,841 +8467,834 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); ** ** */ -#define SQLITE_STMTSTATUS_FULLSCAN_STEP 1 -#define SQLITE_STMTSTATUS_SORT 2 -#define SQLITE_STMTSTATUS_AUTOINDEX 3 -#define SQLITE_STMTSTATUS_VM_STEP 4 -#define SQLITE_STMTSTATUS_REPREPARE 5 -#define SQLITE_STMTSTATUS_RUN 6 -#define SQLITE_STMTSTATUS_FILTER_MISS 7 -#define SQLITE_STMTSTATUS_FILTER_HIT 8 -#define SQLITE_STMTSTATUS_MEMUSED 99 - -/* -** CAPI3REF: Custom Page Cache Object -** -** The sqlite3_pcache type is opaque. It is implemented by -** the pluggable module. The SQLite core has no knowledge of -** its size or internal structure and never deals with the -** sqlite3_pcache object except by holding and passing pointers -** to the object. -** -** See [sqlite3_pcache_methods2] for additional information. -*/ -typedef struct sqlite3_pcache sqlite3_pcache; - -/* -** CAPI3REF: Custom Page Cache Object -** -** The sqlite3_pcache_page object represents a single page in the -** page cache. The page cache will allocate instances of this -** object. Various methods of the page cache use pointers to instances -** of this object as parameters or as their return value. -** -** See [sqlite3_pcache_methods2] for additional information. -*/ -typedef struct sqlite3_pcache_page sqlite3_pcache_page; -struct sqlite3_pcache_page { - void *pBuf; /* The content of the page */ - void *pExtra; /* Extra information associated with the page */ -}; - -/* -** CAPI3REF: Application Defined Page Cache. -** KEYWORDS: {page cache} -** -** ^(The [sqlite3_config]([SQLITE_CONFIG_PCACHE2], ...) interface can -** register an alternative page cache implementation by passing in an -** instance of the sqlite3_pcache_methods2 structure.)^ -** In many applications, most of the heap memory allocated by -** SQLite is used for the page cache. -** By implementing a -** custom page cache using this API, an application can better control -** the amount of memory consumed by SQLite, the way in which -** that memory is allocated and released, and the policies used to -** determine exactly which parts of a database file are cached and for -** how long. -** -** The alternative page cache mechanism is an -** extreme measure that is only needed by the most demanding applications. -** The built-in page cache is recommended for most uses. -** -** ^(The contents of the sqlite3_pcache_methods2 structure are copied to an -** internal buffer by SQLite within the call to [sqlite3_config]. Hence -** the application may discard the parameter after the call to -** [sqlite3_config()] returns.)^ -** -** [[the xInit() page cache method]] -** ^(The xInit() method is called once for each effective -** call to [sqlite3_initialize()])^ -** (usually only once during the lifetime of the process). ^(The xInit() -** method is passed a copy of the sqlite3_pcache_methods2.pArg value.)^ -** The intent of the xInit() method is to set up global data structures -** required by the custom page cache implementation. -** ^(If the xInit() method is NULL, then the -** built-in default page cache is used instead of the application defined -** page cache.)^ -** -** [[the xShutdown() page cache method]] -** ^The xShutdown() method is called by [sqlite3_shutdown()]. -** It can be used to clean up -** any outstanding resources before process shutdown, if required. -** ^The xShutdown() method may be NULL. -** -** ^SQLite automatically serializes calls to the xInit method, -** so the xInit method need not be threadsafe. ^The -** xShutdown method is only called from [sqlite3_shutdown()] so it does -** not need to be threadsafe either. All other methods must be threadsafe -** in multithreaded applications. -** -** ^SQLite will never invoke xInit() more than once without an intervening -** call to xShutdown(). -** -** [[the xCreate() page cache methods]] -** ^SQLite invokes the xCreate() method to construct a new cache instance. -** SQLite will typically create one cache instance for each open database file, -** though this is not guaranteed. ^The -** first parameter, szPage, is the size in bytes of the pages that must -** be allocated by the cache. ^szPage will always a power of two. ^The -** second parameter szExtra is a number of bytes of extra storage -** associated with each page cache entry. ^The szExtra parameter will -** a number less than 250. SQLite will use the -** extra szExtra bytes on each page to store metadata about the underlying -** database page on disk. The value passed into szExtra depends -** on the SQLite version, the target platform, and how SQLite was compiled. -** ^The third argument to xCreate(), bPurgeable, is true if the cache being -** created will be used to cache database pages of a file stored on disk, or -** false if it is used for an in-memory database. The cache implementation -** does not have to do anything special based with the value of bPurgeable; -** it is purely advisory. ^On a cache where bPurgeable is false, SQLite will -** never invoke xUnpin() except to deliberately delete a page. -** ^In other words, calls to xUnpin() on a cache with bPurgeable set to -** false will always have the "discard" flag set to true. -** ^Hence, a cache created with bPurgeable false will -** never contain any unpinned pages. -** -** [[the xCachesize() page cache method]] -** ^(The xCachesize() method may be called at any time by SQLite to set the -** suggested maximum cache-size (number of pages stored by) the cache -** instance passed as the first argument. This is the value configured using -** the SQLite "[PRAGMA cache_size]" command.)^ As with the bPurgeable -** parameter, the implementation is not required to do anything with this -** value; it is advisory only. -** -** [[the xPagecount() page cache methods]] -** The xPagecount() method must return the number of pages currently -** stored in the cache, both pinned and unpinned. -** -** [[the xFetch() page cache methods]] -** The xFetch() method locates a page in the cache and returns a pointer to -** an sqlite3_pcache_page object associated with that page, or a NULL pointer. -** The pBuf element of the returned sqlite3_pcache_page object will be a -** pointer to a buffer of szPage bytes used to store the content of a -** single database page. The pExtra element of sqlite3_pcache_page will be -** a pointer to the szExtra bytes of extra storage that SQLite has requested -** for each entry in the page cache. -** -** The page to be fetched is determined by the key. ^The minimum key value -** is 1. After it has been retrieved using xFetch, the page is considered -** to be "pinned". -** -** If the requested page is already in the page cache, then the page cache -** implementation must return a pointer to the page buffer with its content -** intact. If the requested page is not already in the cache, then the -** cache implementation should use the value of the createFlag -** parameter to help it determined what action to take: -** -** -**
createFlag Behavior when page is not already in cache -**
0 Do not allocate a new page. Return NULL. -**
1 Allocate a new page if it easy and convenient to do so. -** Otherwise return NULL. -**
2 Make every effort to allocate a new page. Only return -** NULL if allocating a new page is effectively impossible. -**
-** -** ^(SQLite will normally invoke xFetch() with a createFlag of 0 or 1. SQLite -** will only use a createFlag of 2 after a prior call with a createFlag of 1 -** failed.)^ In between the xFetch() calls, SQLite may -** attempt to unpin one or more cache pages by spilling the content of -** pinned pages to disk and synching the operating system disk cache. -** -** [[the xUnpin() page cache method]] -** ^xUnpin() is called by SQLite with a pointer to a currently pinned page -** as its second argument. If the third parameter, discard, is non-zero, -** then the page must be evicted from the cache. -** ^If the discard parameter is -** zero, then the page may be discarded or retained at the discretion of -** page cache implementation. ^The page cache implementation -** may choose to evict unpinned pages at any time. -** -** The cache must not perform any reference counting. A single -** call to xUnpin() unpins the page regardless of the number of prior calls -** to xFetch(). -** -** [[the xRekey() page cache methods]] -** The xRekey() method is used to change the key value associated with the -** page passed as the second argument. If the cache -** previously contains an entry associated with newKey, it must be -** discarded. ^Any prior cache entry associated with newKey is guaranteed not -** to be pinned. -** -** When SQLite calls the xTruncate() method, the cache must discard all -** existing cache entries with page numbers (keys) greater than or equal -** to the value of the iLimit parameter passed to xTruncate(). If any -** of these pages are pinned, they are implicitly unpinned, meaning that -** they can be safely discarded. -** -** [[the xDestroy() page cache method]] -** ^The xDestroy() method is used to delete a cache allocated by xCreate(). -** All resources associated with the specified cache should be freed. ^After -** calling the xDestroy() method, SQLite considers the [sqlite3_pcache*] -** handle invalid, and will not use it with any other sqlite3_pcache_methods2 -** functions. -** -** [[the xShrink() page cache method]] -** ^SQLite invokes the xShrink() method when it wants the page cache to -** free up as much of heap memory as possible. The page cache implementation -** is not obligated to free any memory, but well-behaved implementations should -** do their best. -*/ -typedef struct sqlite3_pcache_methods2 sqlite3_pcache_methods2; -struct sqlite3_pcache_methods2 { - int iVersion; - void *pArg; - int (*xInit)(void*); - void (*xShutdown)(void*); - sqlite3_pcache *(*xCreate)(int szPage, int szExtra, int bPurgeable); - void (*xCachesize)(sqlite3_pcache*, int nCachesize); - int (*xPagecount)(sqlite3_pcache*); - sqlite3_pcache_page *(*xFetch)(sqlite3_pcache*, unsigned key, int createFlag); - void (*xUnpin)(sqlite3_pcache*, sqlite3_pcache_page*, int discard); - void (*xRekey)(sqlite3_pcache*, sqlite3_pcache_page*, - unsigned oldKey, unsigned newKey); - void (*xTruncate)(sqlite3_pcache*, unsigned iLimit); - void (*xDestroy)(sqlite3_pcache*); - void (*xShrink)(sqlite3_pcache*); -}; - -/* -** This is the obsolete pcache_methods object that has now been replaced -** by sqlite3_pcache_methods2. This object is not used by SQLite. It is -** retained in the header file for backwards compatibility only. -*/ -typedef struct sqlite3_pcache_methods sqlite3_pcache_methods; -struct sqlite3_pcache_methods { - void *pArg; - int (*xInit)(void*); - void (*xShutdown)(void*); - sqlite3_pcache *(*xCreate)(int szPage, int bPurgeable); - void (*xCachesize)(sqlite3_pcache*, int nCachesize); - int (*xPagecount)(sqlite3_pcache*); - void *(*xFetch)(sqlite3_pcache*, unsigned key, int createFlag); - void (*xUnpin)(sqlite3_pcache*, void*, int discard); - void (*xRekey)(sqlite3_pcache*, void*, unsigned oldKey, unsigned newKey); - void (*xTruncate)(sqlite3_pcache*, unsigned iLimit); - void (*xDestroy)(sqlite3_pcache*); -}; - - -/* -** CAPI3REF: Online Backup Object -** -** The sqlite3_backup object records state information about an ongoing -** online backup operation. ^The sqlite3_backup object is created by -** a call to [sqlite3_backup_init()] and is destroyed by a call to -** [sqlite3_backup_finish()]. -** -** See Also: [Using the SQLite Online Backup API] -*/ -typedef struct sqlite3_backup sqlite3_backup; - -/* -** CAPI3REF: Online Backup API. -** -** The backup API copies the content of one database into another. -** It is useful either for creating backups of databases or -** for copying in-memory databases to or from persistent files. -** -** See Also: [Using the SQLite Online Backup API] -** -** ^SQLite holds a write transaction open on the destination database file -** for the duration of the backup operation. -** ^The source database is read-locked only while it is being read; -** it is not locked continuously for the entire backup operation. -** ^Thus, the backup may be performed on a live source database without -** preventing other database connections from -** reading or writing to the source database while the backup is underway. -** -** ^(To perform a backup operation: -**
    -**
  1. sqlite3_backup_init() is called once to initialize the -** backup, -**
  2. sqlite3_backup_step() is called one or more times to transfer -** the data between the two databases, and finally -**
  3. sqlite3_backup_finish() is called to release all resources -** associated with the backup operation. -**
)^ -** There should be exactly one call to sqlite3_backup_finish() for each -** successful call to sqlite3_backup_init(). -** -** [[sqlite3_backup_init()]] sqlite3_backup_init() -** -** ^The D and N arguments to sqlite3_backup_init(D,N,S,M) are the -** [database connection] associated with the destination database -** and the database name, respectively. -** ^The database name is "main" for the main database, "temp" for the -** temporary database, or the name specified after the AS keyword in -** an [ATTACH] statement for an attached database. -** ^The S and M arguments passed to -** sqlite3_backup_init(D,N,S,M) identify the [database connection] -** and database name of the source database, respectively. -** ^The source and destination [database connections] (parameters S and D) -** must be different or else sqlite3_backup_init(D,N,S,M) will fail with -** an error. -** -** ^A call to sqlite3_backup_init() will fail, returning NULL, if -** there is already a read or read-write transaction open on the -** destination database. -** -** ^If an error occurs within sqlite3_backup_init(D,N,S,M), then NULL is -** returned and an error code and error message are stored in the -** destination [database connection] D. -** ^The error code and message for the failed call to sqlite3_backup_init() -** can be retrieved using the [sqlite3_errcode()], [sqlite3_errmsg()], and/or -** [sqlite3_errmsg16()] functions. -** ^A successful call to sqlite3_backup_init() returns a pointer to an -** [sqlite3_backup] object. -** ^The [sqlite3_backup] object may be used with the sqlite3_backup_step() and -** sqlite3_backup_finish() functions to perform the specified backup -** operation. -** -** [[sqlite3_backup_step()]] sqlite3_backup_step() -** -** ^Function sqlite3_backup_step(B,N) will copy up to N pages between -** the source and destination databases specified by [sqlite3_backup] object B. -** ^If N is negative, all remaining source pages are copied. -** ^If sqlite3_backup_step(B,N) successfully copies N pages and there -** are still more pages to be copied, then the function returns [SQLITE_OK]. -** ^If sqlite3_backup_step(B,N) successfully finishes copying all pages -** from source to destination, then it returns [SQLITE_DONE]. -** ^If an error occurs while running sqlite3_backup_step(B,N), -** then an [error code] is returned. ^As well as [SQLITE_OK] and -** [SQLITE_DONE], a call to sqlite3_backup_step() may return [SQLITE_READONLY], -** [SQLITE_NOMEM], [SQLITE_BUSY], [SQLITE_LOCKED], or an -** [SQLITE_IOERR_ACCESS | SQLITE_IOERR_XXX] extended error code. -** -** ^(The sqlite3_backup_step() might return [SQLITE_READONLY] if -**
    -**
  1. the destination database was opened read-only, or -**
  2. the destination database is using write-ahead-log journaling -** and the destination and source page sizes differ, or -**
  3. the destination database is an in-memory database and the -** destination and source page sizes differ. -**
)^ -** -** ^If sqlite3_backup_step() cannot obtain a required file-system lock, then -** the [sqlite3_busy_handler | busy-handler function] -** is invoked (if one is specified). ^If the -** busy-handler returns non-zero before the lock is available, then -** [SQLITE_BUSY] is returned to the caller. ^In this case the call to -** sqlite3_backup_step() can be retried later. ^If the source -** [database connection] -** is being used to write to the source database when sqlite3_backup_step() -** is called, then [SQLITE_LOCKED] is returned immediately. ^Again, in this -** case the call to sqlite3_backup_step() can be retried later on. ^(If -** [SQLITE_IOERR_ACCESS | SQLITE_IOERR_XXX], [SQLITE_NOMEM], or -** [SQLITE_READONLY] is returned, then -** there is no point in retrying the call to sqlite3_backup_step(). These -** errors are considered fatal.)^ The application must accept -** that the backup operation has failed and pass the backup operation handle -** to the sqlite3_backup_finish() to release associated resources. -** -** ^The first call to sqlite3_backup_step() obtains an exclusive lock -** on the destination file. ^The exclusive lock is not released until either -** sqlite3_backup_finish() is called or the backup operation is complete -** and sqlite3_backup_step() returns [SQLITE_DONE]. ^Every call to -** sqlite3_backup_step() obtains a [shared lock] on the source database that -** lasts for the duration of the sqlite3_backup_step() call. -** ^Because the source database is not locked between calls to -** sqlite3_backup_step(), the source database may be modified mid-way -** through the backup process. ^If the source database is modified by an -** external process or via a database connection other than the one being -** used by the backup operation, then the backup will be automatically -** restarted by the next call to sqlite3_backup_step(). ^If the source -** database is modified by the using the same database connection as is used -** by the backup operation, then the backup database is automatically -** updated at the same time. -** -** [[sqlite3_backup_finish()]] sqlite3_backup_finish() -** -** When sqlite3_backup_step() has returned [SQLITE_DONE], or when the -** application wishes to abandon the backup operation, the application -** should destroy the [sqlite3_backup] by passing it to sqlite3_backup_finish(). -** ^The sqlite3_backup_finish() interfaces releases all -** resources associated with the [sqlite3_backup] object. -** ^If sqlite3_backup_step() has not yet returned [SQLITE_DONE], then any -** active write-transaction on the destination database is rolled back. -** The [sqlite3_backup] object is invalid -** and may not be used following a call to sqlite3_backup_finish(). -** -** ^The value returned by sqlite3_backup_finish is [SQLITE_OK] if no -** sqlite3_backup_step() errors occurred, regardless or whether or not -** sqlite3_backup_step() completed. -** ^If an out-of-memory condition or IO error occurred during any prior -** sqlite3_backup_step() call on the same [sqlite3_backup] object, then -** sqlite3_backup_finish() returns the corresponding [error code]. -** -** ^A return of [SQLITE_BUSY] or [SQLITE_LOCKED] from sqlite3_backup_step() -** is not a permanent error and does not affect the return value of -** sqlite3_backup_finish(). -** -** [[sqlite3_backup_remaining()]] [[sqlite3_backup_pagecount()]] -** sqlite3_backup_remaining() and sqlite3_backup_pagecount() -** -** ^The sqlite3_backup_remaining() routine returns the number of pages still -** to be backed up at the conclusion of the most recent sqlite3_backup_step(). -** ^The sqlite3_backup_pagecount() routine returns the total number of pages -** in the source database at the conclusion of the most recent -** sqlite3_backup_step(). -** ^(The values returned by these functions are only updated by -** sqlite3_backup_step(). If the source database is modified in a way that -** changes the size of the source database or the number of pages remaining, -** those changes are not reflected in the output of sqlite3_backup_pagecount() -** and sqlite3_backup_remaining() until after the next -** sqlite3_backup_step().)^ -** -** Concurrent Usage of Database Handles -** -** ^The source [database connection] may be used by the application for other -** purposes while a backup operation is underway or being initialized. -** ^If SQLite is compiled and configured to support threadsafe database -** connections, then the source database connection may be used concurrently -** from within other threads. -** -** However, the application must guarantee that the destination -** [database connection] is not passed to any other API (by any thread) after -** sqlite3_backup_init() is called and before the corresponding call to -** sqlite3_backup_finish(). SQLite does not currently check to see -** if the application incorrectly accesses the destination [database connection] -** and so no error code is reported, but the operations may malfunction -** nevertheless. Use of the destination database connection while a -** backup is in progress might also also cause a mutex deadlock. -** -** If running in [shared cache mode], the application must -** guarantee that the shared cache used by the destination database -** is not accessed while the backup is running. In practice this means -** that the application must guarantee that the disk file being -** backed up to is not accessed by any connection within the process, -** not just the specific connection that was passed to sqlite3_backup_init(). -** -** The [sqlite3_backup] object itself is partially threadsafe. Multiple -** threads may safely make multiple concurrent calls to sqlite3_backup_step(). -** However, the sqlite3_backup_remaining() and sqlite3_backup_pagecount() -** APIs are not strictly speaking threadsafe. If they are invoked at the -** same time as another thread is invoking sqlite3_backup_step() it is -** possible that they return invalid values. -*/ -SQLITE_API sqlite3_backup *sqlite3_backup_init( - sqlite3 *pDest, /* Destination database handle */ - const char *zDestName, /* Destination database name */ - sqlite3 *pSource, /* Source database handle */ - const char *zSourceName /* Source database name */ -); -SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage); -SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p); -SQLITE_API int sqlite3_backup_remaining(sqlite3_backup *p); -SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p); - -/* -** CAPI3REF: Unlock Notification -** METHOD: sqlite3 -** -** ^When running in shared-cache mode, a database operation may fail with -** an [SQLITE_LOCKED] error if the required locks on the shared-cache or -** individual tables within the shared-cache cannot be obtained. See -** [SQLite Shared-Cache Mode] for a description of shared-cache locking. -** ^This API may be used to register a callback that SQLite will invoke -** when the connection currently holding the required lock relinquishes it. -** ^This API is only available if the library was compiled with the -** [SQLITE_ENABLE_UNLOCK_NOTIFY] C-preprocessor symbol defined. -** -** See Also: [Using the SQLite Unlock Notification Feature]. -** -** ^Shared-cache locks are released when a database connection concludes -** its current transaction, either by committing it or rolling it back. -** -** ^When a connection (known as the blocked connection) fails to obtain a -** shared-cache lock and SQLITE_LOCKED is returned to the caller, the -** identity of the database connection (the blocking connection) that -** has locked the required resource is stored internally. ^After an -** application receives an SQLITE_LOCKED error, it may call the -** sqlite3_unlock_notify() method with the blocked connection handle as -** the first argument to register for a callback that will be invoked -** when the blocking connections current transaction is concluded. ^The -** callback is invoked from within the [sqlite3_step] or [sqlite3_close] -** call that concludes the blocking connection's transaction. -** -** ^(If sqlite3_unlock_notify() is called in a multi-threaded application, -** there is a chance that the blocking connection will have already -** concluded its transaction by the time sqlite3_unlock_notify() is invoked. -** If this happens, then the specified callback is invoked immediately, -** from within the call to sqlite3_unlock_notify().)^ -** -** ^If the blocked connection is attempting to obtain a write-lock on a -** shared-cache table, and more than one other connection currently holds -** a read-lock on the same table, then SQLite arbitrarily selects one of -** the other connections to use as the blocking connection. -** -** ^(There may be at most one unlock-notify callback registered by a -** blocked connection. If sqlite3_unlock_notify() is called when the -** blocked connection already has a registered unlock-notify callback, -** then the new callback replaces the old.)^ ^If sqlite3_unlock_notify() is -** called with a NULL pointer as its second argument, then any existing -** unlock-notify callback is canceled. ^The blocked connections -** unlock-notify callback may also be canceled by closing the blocked -** connection using [sqlite3_close()]. -** -** The unlock-notify callback is not reentrant. If an application invokes -** any sqlite3_xxx API functions from within an unlock-notify callback, a -** crash or deadlock may be the result. -** -** ^Unless deadlock is detected (see below), sqlite3_unlock_notify() always -** returns SQLITE_OK. -** -** Callback Invocation Details -** -** When an unlock-notify callback is registered, the application provides a -** single void* pointer that is passed to the callback when it is invoked. -** However, the signature of the callback function allows SQLite to pass -** it an array of void* context pointers. The first argument passed to -** an unlock-notify callback is a pointer to an array of void* pointers, -** and the second is the number of entries in the array. -** -** When a blocking connection's transaction is concluded, there may be -** more than one blocked connection that has registered for an unlock-notify -** callback. ^If two or more such blocked connections have specified the -** same callback function, then instead of invoking the callback function -** multiple times, it is invoked once with the set of void* context pointers -** specified by the blocked connections bundled together into an array. -** This gives the application an opportunity to prioritize any actions -** related to the set of unblocked database connections. -** -** Deadlock Detection -** -** Assuming that after registering for an unlock-notify callback a -** database waits for the callback to be issued before taking any further -** action (a reasonable assumption), then using this API may cause the -** application to deadlock. For example, if connection X is waiting for -** connection Y's transaction to be concluded, and similarly connection -** Y is waiting on connection X's transaction, then neither connection -** will proceed and the system may remain deadlocked indefinitely. -** -** To avoid this scenario, the sqlite3_unlock_notify() performs deadlock -** detection. ^If a given call to sqlite3_unlock_notify() would put the -** system in a deadlocked state, then SQLITE_LOCKED is returned and no -** unlock-notify callback is registered. The system is said to be in -** a deadlocked state if connection A has registered for an unlock-notify -** callback on the conclusion of connection B's transaction, and connection -** B has itself registered for an unlock-notify callback when connection -** A's transaction is concluded. ^Indirect deadlock is also detected, so -** the system is also considered to be deadlocked if connection B has -** registered for an unlock-notify callback on the conclusion of connection -** C's transaction, where connection C is waiting on connection A. ^Any -** number of levels of indirection are allowed. -** -** The "DROP TABLE" Exception -** -** When a call to [sqlite3_step()] returns SQLITE_LOCKED, it is almost -** always appropriate to call sqlite3_unlock_notify(). There is however, -** one exception. When executing a "DROP TABLE" or "DROP INDEX" statement, -** SQLite checks if there are any currently executing SELECT statements -** that belong to the same connection. If there are, SQLITE_LOCKED is -** returned. In this case there is no "blocking connection", so invoking -** sqlite3_unlock_notify() results in the unlock-notify callback being -** invoked immediately. If the application then re-attempts the "DROP TABLE" -** or "DROP INDEX" query, an infinite loop might be the result. -** -** One way around this problem is to check the extended error code returned -** by an sqlite3_step() call. ^(If there is a blocking connection, then the -** extended error code is set to SQLITE_LOCKED_SHAREDCACHE. Otherwise, in -** the special "DROP TABLE/INDEX" case, the extended error code is just -** SQLITE_LOCKED.)^ -*/ -SQLITE_API int sqlite3_unlock_notify( - sqlite3 *pBlocked, /* Waiting connection */ - void (*xNotify)(void **apArg, int nArg), /* Callback function to invoke */ - void *pNotifyArg /* Argument to pass to xNotify */ -); - - -/* -** CAPI3REF: String Comparison -** -** ^The [sqlite3_stricmp()] and [sqlite3_strnicmp()] APIs allow applications -** and extensions to compare the contents of two buffers containing UTF-8 -** strings in a case-independent fashion, using the same definition of "case -** independence" that SQLite uses internally when comparing identifiers. -*/ -SQLITE_API int sqlite3_stricmp(const char *, const char *); -SQLITE_API int sqlite3_strnicmp(const char *, const char *, int); - -/* -** CAPI3REF: String Globbing -* -** ^The [sqlite3_strglob(P,X)] interface returns zero if and only if -** string X matches the [GLOB] pattern P. -** ^The definition of [GLOB] pattern matching used in -** [sqlite3_strglob(P,X)] is the same as for the "X GLOB P" operator in the -** SQL dialect understood by SQLite. ^The [sqlite3_strglob(P,X)] function -** is case sensitive. -** -** Note that this routine returns zero on a match and non-zero if the strings -** do not match, the same as [sqlite3_stricmp()] and [sqlite3_strnicmp()]. -** -** See also: [sqlite3_strlike()]. -*/ -SQLITE_API int sqlite3_strglob(const char *zGlob, const char *zStr); - -/* -** CAPI3REF: String LIKE Matching -* -** ^The [sqlite3_strlike(P,X,E)] interface returns zero if and only if -** string X matches the [LIKE] pattern P with escape character E. -** ^The definition of [LIKE] pattern matching used in -** [sqlite3_strlike(P,X,E)] is the same as for the "X LIKE P ESCAPE E" -** operator in the SQL dialect understood by SQLite. ^For "X LIKE P" without -** the ESCAPE clause, set the E parameter of [sqlite3_strlike(P,X,E)] to 0. -** ^As with the LIKE operator, the [sqlite3_strlike(P,X,E)] function is case -** insensitive - equivalent upper and lower case ASCII characters match -** one another. -** -** ^The [sqlite3_strlike(P,X,E)] function matches Unicode characters, though -** only ASCII characters are case folded. -** -** Note that this routine returns zero on a match and non-zero if the strings -** do not match, the same as [sqlite3_stricmp()] and [sqlite3_strnicmp()]. -** -** See also: [sqlite3_strglob()]. -*/ -SQLITE_API int sqlite3_strlike(const char *zGlob, const char *zStr, unsigned int cEsc); - -/* -** CAPI3REF: Error Logging Interface -** -** ^The [sqlite3_log()] interface writes a message into the [error log] -** established by the [SQLITE_CONFIG_LOG] option to [sqlite3_config()]. -** ^If logging is enabled, the zFormat string and subsequent arguments are -** used with [sqlite3_snprintf()] to generate the final output string. -** -** The sqlite3_log() interface is intended for use by extensions such as -** virtual tables, collating functions, and SQL functions. While there is -** nothing to prevent an application from calling sqlite3_log(), doing so -** is considered bad form. -** -** The zFormat string must not be NULL. -** -** To avoid deadlocks and other threading problems, the sqlite3_log() routine -** will not use dynamically allocated memory. The log message is stored in -** a fixed-length buffer on the stack. If the log message is longer than -** a few hundred characters, it will be truncated to the length of the -** buffer. -*/ -SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...); - -/* -** CAPI3REF: Write-Ahead Log Commit Hook -** METHOD: sqlite3 -** -** ^The [sqlite3_wal_hook()] function is used to register a callback that -** is invoked each time data is committed to a database in wal mode. -** -** ^(The callback is invoked by SQLite after the commit has taken place and -** the associated write-lock on the database released)^, so the implementation -** may read, write or [checkpoint] the database as required. -** -** ^The first parameter passed to the callback function when it is invoked -** is a copy of the third parameter passed to sqlite3_wal_hook() when -** registering the callback. ^The second is a copy of the database handle. -** ^The third parameter is the name of the database that was written to - -** either "main" or the name of an [ATTACH]-ed database. ^The fourth parameter -** is the number of pages currently in the write-ahead log file, -** including those that were just committed. -** -** The callback function should normally return [SQLITE_OK]. ^If an error -** code is returned, that error will propagate back up through the -** SQLite code base to cause the statement that provoked the callback -** to report an error, though the commit will have still occurred. If the -** callback returns [SQLITE_ROW] or [SQLITE_DONE], or if it returns a value -** that does not correspond to any valid SQLite error code, the results -** are undefined. -** -** A single database handle may have at most a single write-ahead log callback -** registered at one time. ^Calling [sqlite3_wal_hook()] replaces any -** previously registered write-ahead log callback. ^The return value is -** a copy of the third parameter from the previous call, if any, or 0. -** ^Note that the [sqlite3_wal_autocheckpoint()] interface and the -** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will -** overwrite any prior [sqlite3_wal_hook()] settings. -*/ -SQLITE_API void *sqlite3_wal_hook( - sqlite3*, - int(*)(void *,sqlite3*,const char*,int), - void* -); - -/* -** CAPI3REF: Configure an auto-checkpoint -** METHOD: sqlite3 -** -** ^The [sqlite3_wal_autocheckpoint(D,N)] is a wrapper around -** [sqlite3_wal_hook()] that causes any database on [database connection] D -** to automatically [checkpoint] -** after committing a transaction if there are N or -** more frames in the [write-ahead log] file. ^Passing zero or -** a negative value as the nFrame parameter disables automatic -** checkpoints entirely. -** -** ^The callback registered by this function replaces any existing callback -** registered using [sqlite3_wal_hook()]. ^Likewise, registering a callback -** using [sqlite3_wal_hook()] disables the automatic checkpoint mechanism -** configured by this function. -** -** ^The [wal_autocheckpoint pragma] can be used to invoke this interface -** from SQL. -** -** ^Checkpoints initiated by this mechanism are -** [sqlite3_wal_checkpoint_v2|PASSIVE]. -** -** ^Every new [database connection] defaults to having the auto-checkpoint -** enabled with a threshold of 1000 or [SQLITE_DEFAULT_WAL_AUTOCHECKPOINT] -** pages. The use of this interface -** is only necessary if the default setting is found to be suboptimal -** for a particular application. -*/ -SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N); - -/* -** CAPI3REF: Checkpoint a database -** METHOD: sqlite3 -** -** ^(The sqlite3_wal_checkpoint(D,X) is equivalent to -** [sqlite3_wal_checkpoint_v2](D,X,[SQLITE_CHECKPOINT_PASSIVE],0,0).)^ -** -** In brief, sqlite3_wal_checkpoint(D,X) causes the content in the -** [write-ahead log] for database X on [database connection] D to be -** transferred into the database file and for the write-ahead log to -** be reset. See the [checkpointing] documentation for addition -** information. -** -** This interface used to be the only way to cause a checkpoint to -** occur. But then the newer and more powerful [sqlite3_wal_checkpoint_v2()] -** interface was added. This interface is retained for backwards -** compatibility and as a convenience for applications that need to manually -** start a callback but which do not need the full power (and corresponding -** complication) of [sqlite3_wal_checkpoint_v2()]. -*/ -SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb); - -/* -** CAPI3REF: Checkpoint a database -** METHOD: sqlite3 -** -** ^(The sqlite3_wal_checkpoint_v2(D,X,M,L,C) interface runs a checkpoint -** operation on database X of [database connection] D in mode M. Status -** information is written back into integers pointed to by L and C.)^ -** ^(The M parameter must be a valid [checkpoint mode]:)^ -** -**
-**
SQLITE_CHECKPOINT_PASSIVE
-** ^Checkpoint as many frames as possible without waiting for any database -** readers or writers to finish, then sync the database file if all frames -** in the log were checkpointed. ^The [busy-handler callback] -** is never invoked in the SQLITE_CHECKPOINT_PASSIVE mode. -** ^On the other hand, passive mode might leave the checkpoint unfinished -** if there are concurrent readers or writers. -** -**
SQLITE_CHECKPOINT_FULL
-** ^This mode blocks (it invokes the -** [sqlite3_busy_handler|busy-handler callback]) until there is no -** database writer and all readers are reading from the most recent database -** snapshot. ^It then checkpoints all frames in the log file and syncs the -** database file. ^This mode blocks new database writers while it is pending, -** but new database readers are allowed to continue unimpeded. -** -**
SQLITE_CHECKPOINT_RESTART
-** ^This mode works the same way as SQLITE_CHECKPOINT_FULL with the addition -** that after checkpointing the log file it blocks (calls the -** [busy-handler callback]) -** until all readers are reading from the database file only. ^This ensures -** that the next writer will restart the log file from the beginning. -** ^Like SQLITE_CHECKPOINT_FULL, this mode blocks new -** database writer attempts while it is pending, but does not impede readers. -** -**
SQLITE_CHECKPOINT_TRUNCATE
-** ^This mode works the same way as SQLITE_CHECKPOINT_RESTART with the -** addition that it also truncates the log file to zero bytes just prior -** to a successful return. -**
-** -** ^If pnLog is not NULL, then *pnLog is set to the total number of frames in -** the log file or to -1 if the checkpoint could not run because -** of an error or because the database is not in [WAL mode]. ^If pnCkpt is not -** NULL,then *pnCkpt is set to the total number of checkpointed frames in the -** log file (including any that were already checkpointed before the function -** was called) or to -1 if the checkpoint could not run due to an error or -** because the database is not in WAL mode. ^Note that upon successful -** completion of an SQLITE_CHECKPOINT_TRUNCATE, the log file will have been -** truncated to zero bytes and so both *pnLog and *pnCkpt will be set to zero. -** -** ^All calls obtain an exclusive "checkpoint" lock on the database file. ^If -** any other process is running a checkpoint operation at the same time, the -** lock cannot be obtained and SQLITE_BUSY is returned. ^Even if there is a -** busy-handler configured, it will not be invoked in this case. -** -** ^The SQLITE_CHECKPOINT_FULL, RESTART and TRUNCATE modes also obtain the -** exclusive "writer" lock on the database file. ^If the writer lock cannot be -** obtained immediately, and a busy-handler is configured, it is invoked and -** the writer lock retried until either the busy-handler returns 0 or the lock -** is successfully obtained. ^The busy-handler is also invoked while waiting for -** database readers as described above. ^If the busy-handler returns 0 before -** the writer lock is obtained or while waiting for database readers, the -** checkpoint operation proceeds from that point in the same way as -** SQLITE_CHECKPOINT_PASSIVE - checkpointing as many frames as possible -** without blocking any further. ^SQLITE_BUSY is returned in this case. -** -** ^If parameter zDb is NULL or points to a zero length string, then the -** specified operation is attempted on all WAL databases [attached] to -** [database connection] db. In this case the -** values written to output parameters *pnLog and *pnCkpt are undefined. ^If -** an SQLITE_BUSY error is encountered when processing one or more of the -** attached WAL databases, the operation is still attempted on any remaining -** attached databases and SQLITE_BUSY is returned at the end. ^If any other -** error occurs while processing an attached database, processing is abandoned -** and the error code is returned to the caller immediately. ^If no error -** (SQLITE_BUSY or otherwise) is encountered while processing the attached -** databases, SQLITE_OK is returned. -** -** ^If database zDb is the name of an attached database that is not in WAL -** mode, SQLITE_OK is returned and both *pnLog and *pnCkpt set to -1. ^If -** zDb is not NULL (or a zero length string) and is not the name of any -** attached database, SQLITE_ERROR is returned to the caller. -** -** ^Unless it returns SQLITE_MISUSE, -** the sqlite3_wal_checkpoint_v2() interface -** sets the error information that is queried by -** [sqlite3_errcode()] and [sqlite3_errmsg()]. -** -** ^The [PRAGMA wal_checkpoint] command can be used to invoke this interface -** from SQL. -*/ -SQLITE_API int sqlite3_wal_checkpoint_v2( - sqlite3 *db, /* Database handle */ - const char *zDb, /* Name of attached database (or NULL) */ - int eMode, /* SQLITE_CHECKPOINT_* value */ - int *pnLog, /* OUT: Size of WAL log in frames */ - int *pnCkpt /* OUT: Total number of frames checkpointed */ -); +#define SQLITE_STMTSTATUS_FULLSCAN_STEP 1 +#define SQLITE_STMTSTATUS_SORT 2 +#define SQLITE_STMTSTATUS_AUTOINDEX 3 +#define SQLITE_STMTSTATUS_VM_STEP 4 +#define SQLITE_STMTSTATUS_REPREPARE 5 +#define SQLITE_STMTSTATUS_RUN 6 +#define SQLITE_STMTSTATUS_FILTER_MISS 7 +#define SQLITE_STMTSTATUS_FILTER_HIT 8 +#define SQLITE_STMTSTATUS_MEMUSED 99 + + /* + ** CAPI3REF: Custom Page Cache Object + ** + ** The sqlite3_pcache type is opaque. It is implemented by + ** the pluggable module. The SQLite core has no knowledge of + ** its size or internal structure and never deals with the + ** sqlite3_pcache object except by holding and passing pointers + ** to the object. + ** + ** See [sqlite3_pcache_methods2] for additional information. + */ + typedef struct sqlite3_pcache sqlite3_pcache; + + /* + ** CAPI3REF: Custom Page Cache Object + ** + ** The sqlite3_pcache_page object represents a single page in the + ** page cache. The page cache will allocate instances of this + ** object. Various methods of the page cache use pointers to instances + ** of this object as parameters or as their return value. + ** + ** See [sqlite3_pcache_methods2] for additional information. + */ + typedef struct sqlite3_pcache_page sqlite3_pcache_page; + struct sqlite3_pcache_page + { + void* pBuf; /* The content of the page */ + void* pExtra; /* Extra information associated with the page */ + }; + + /* + ** CAPI3REF: Application Defined Page Cache. + ** KEYWORDS: {page cache} + ** + ** ^(The [sqlite3_config]([SQLITE_CONFIG_PCACHE2], ...) interface can + ** register an alternative page cache implementation by passing in an + ** instance of the sqlite3_pcache_methods2 structure.)^ + ** In many applications, most of the heap memory allocated by + ** SQLite is used for the page cache. + ** By implementing a + ** custom page cache using this API, an application can better control + ** the amount of memory consumed by SQLite, the way in which + ** that memory is allocated and released, and the policies used to + ** determine exactly which parts of a database file are cached and for + ** how long. + ** + ** The alternative page cache mechanism is an + ** extreme measure that is only needed by the most demanding applications. + ** The built-in page cache is recommended for most uses. + ** + ** ^(The contents of the sqlite3_pcache_methods2 structure are copied to an + ** internal buffer by SQLite within the call to [sqlite3_config]. Hence + ** the application may discard the parameter after the call to + ** [sqlite3_config()] returns.)^ + ** + ** [[the xInit() page cache method]] + ** ^(The xInit() method is called once for each effective + ** call to [sqlite3_initialize()])^ + ** (usually only once during the lifetime of the process). ^(The xInit() + ** method is passed a copy of the sqlite3_pcache_methods2.pArg value.)^ + ** The intent of the xInit() method is to set up global data structures + ** required by the custom page cache implementation. + ** ^(If the xInit() method is NULL, then the + ** built-in default page cache is used instead of the application defined + ** page cache.)^ + ** + ** [[the xShutdown() page cache method]] + ** ^The xShutdown() method is called by [sqlite3_shutdown()]. + ** It can be used to clean up + ** any outstanding resources before process shutdown, if required. + ** ^The xShutdown() method may be NULL. + ** + ** ^SQLite automatically serializes calls to the xInit method, + ** so the xInit method need not be threadsafe. ^The + ** xShutdown method is only called from [sqlite3_shutdown()] so it does + ** not need to be threadsafe either. All other methods must be threadsafe + ** in multithreaded applications. + ** + ** ^SQLite will never invoke xInit() more than once without an intervening + ** call to xShutdown(). + ** + ** [[the xCreate() page cache methods]] + ** ^SQLite invokes the xCreate() method to construct a new cache instance. + ** SQLite will typically create one cache instance for each open database file, + ** though this is not guaranteed. ^The + ** first parameter, szPage, is the size in bytes of the pages that must + ** be allocated by the cache. ^szPage will always a power of two. ^The + ** second parameter szExtra is a number of bytes of extra storage + ** associated with each page cache entry. ^The szExtra parameter will + ** a number less than 250. SQLite will use the + ** extra szExtra bytes on each page to store metadata about the underlying + ** database page on disk. The value passed into szExtra depends + ** on the SQLite version, the target platform, and how SQLite was compiled. + ** ^The third argument to xCreate(), bPurgeable, is true if the cache being + ** created will be used to cache database pages of a file stored on disk, or + ** false if it is used for an in-memory database. The cache implementation + ** does not have to do anything special based with the value of bPurgeable; + ** it is purely advisory. ^On a cache where bPurgeable is false, SQLite will + ** never invoke xUnpin() except to deliberately delete a page. + ** ^In other words, calls to xUnpin() on a cache with bPurgeable set to + ** false will always have the "discard" flag set to true. + ** ^Hence, a cache created with bPurgeable false will + ** never contain any unpinned pages. + ** + ** [[the xCachesize() page cache method]] + ** ^(The xCachesize() method may be called at any time by SQLite to set the + ** suggested maximum cache-size (number of pages stored by) the cache + ** instance passed as the first argument. This is the value configured using + ** the SQLite "[PRAGMA cache_size]" command.)^ As with the bPurgeable + ** parameter, the implementation is not required to do anything with this + ** value; it is advisory only. + ** + ** [[the xPagecount() page cache methods]] + ** The xPagecount() method must return the number of pages currently + ** stored in the cache, both pinned and unpinned. + ** + ** [[the xFetch() page cache methods]] + ** The xFetch() method locates a page in the cache and returns a pointer to + ** an sqlite3_pcache_page object associated with that page, or a NULL pointer. + ** The pBuf element of the returned sqlite3_pcache_page object will be a + ** pointer to a buffer of szPage bytes used to store the content of a + ** single database page. The pExtra element of sqlite3_pcache_page will be + ** a pointer to the szExtra bytes of extra storage that SQLite has requested + ** for each entry in the page cache. + ** + ** The page to be fetched is determined by the key. ^The minimum key value + ** is 1. After it has been retrieved using xFetch, the page is considered + ** to be "pinned". + ** + ** If the requested page is already in the page cache, then the page cache + ** implementation must return a pointer to the page buffer with its content + ** intact. If the requested page is not already in the cache, then the + ** cache implementation should use the value of the createFlag + ** parameter to help it determined what action to take: + ** + ** + **
createFlag Behavior when page is not already in cache + **
0 Do not allocate a new page. Return NULL. + **
1 Allocate a new page if it easy and convenient to do so. + ** Otherwise return NULL. + **
2 Make every effort to allocate a new page. Only return + ** NULL if allocating a new page is effectively impossible. + **
+ ** + ** ^(SQLite will normally invoke xFetch() with a createFlag of 0 or 1. SQLite + ** will only use a createFlag of 2 after a prior call with a createFlag of 1 + ** failed.)^ In between the xFetch() calls, SQLite may + ** attempt to unpin one or more cache pages by spilling the content of + ** pinned pages to disk and synching the operating system disk cache. + ** + ** [[the xUnpin() page cache method]] + ** ^xUnpin() is called by SQLite with a pointer to a currently pinned page + ** as its second argument. If the third parameter, discard, is non-zero, + ** then the page must be evicted from the cache. + ** ^If the discard parameter is + ** zero, then the page may be discarded or retained at the discretion of + ** page cache implementation. ^The page cache implementation + ** may choose to evict unpinned pages at any time. + ** + ** The cache must not perform any reference counting. A single + ** call to xUnpin() unpins the page regardless of the number of prior calls + ** to xFetch(). + ** + ** [[the xRekey() page cache methods]] + ** The xRekey() method is used to change the key value associated with the + ** page passed as the second argument. If the cache + ** previously contains an entry associated with newKey, it must be + ** discarded. ^Any prior cache entry associated with newKey is guaranteed not + ** to be pinned. + ** + ** When SQLite calls the xTruncate() method, the cache must discard all + ** existing cache entries with page numbers (keys) greater than or equal + ** to the value of the iLimit parameter passed to xTruncate(). If any + ** of these pages are pinned, they are implicitly unpinned, meaning that + ** they can be safely discarded. + ** + ** [[the xDestroy() page cache method]] + ** ^The xDestroy() method is used to delete a cache allocated by xCreate(). + ** All resources associated with the specified cache should be freed. ^After + ** calling the xDestroy() method, SQLite considers the [sqlite3_pcache*] + ** handle invalid, and will not use it with any other sqlite3_pcache_methods2 + ** functions. + ** + ** [[the xShrink() page cache method]] + ** ^SQLite invokes the xShrink() method when it wants the page cache to + ** free up as much of heap memory as possible. The page cache implementation + ** is not obligated to free any memory, but well-behaved implementations should + ** do their best. + */ + typedef struct sqlite3_pcache_methods2 sqlite3_pcache_methods2; + struct sqlite3_pcache_methods2 + { + int iVersion; + void* pArg; + int (*xInit)(void*); + void (*xShutdown)(void*); + sqlite3_pcache* (*xCreate)(int szPage, int szExtra, int bPurgeable); + void (*xCachesize)(sqlite3_pcache*, int nCachesize); + int (*xPagecount)(sqlite3_pcache*); + sqlite3_pcache_page* (*xFetch)(sqlite3_pcache*, unsigned key, int createFlag); + void (*xUnpin)(sqlite3_pcache*, sqlite3_pcache_page*, int discard); + void (*xRekey)(sqlite3_pcache*, sqlite3_pcache_page*, unsigned oldKey, unsigned newKey); + void (*xTruncate)(sqlite3_pcache*, unsigned iLimit); + void (*xDestroy)(sqlite3_pcache*); + void (*xShrink)(sqlite3_pcache*); + }; + + /* + ** This is the obsolete pcache_methods object that has now been replaced + ** by sqlite3_pcache_methods2. This object is not used by SQLite. It is + ** retained in the header file for backwards compatibility only. + */ + typedef struct sqlite3_pcache_methods sqlite3_pcache_methods; + struct sqlite3_pcache_methods + { + void* pArg; + int (*xInit)(void*); + void (*xShutdown)(void*); + sqlite3_pcache* (*xCreate)(int szPage, int bPurgeable); + void (*xCachesize)(sqlite3_pcache*, int nCachesize); + int (*xPagecount)(sqlite3_pcache*); + void* (*xFetch)(sqlite3_pcache*, unsigned key, int createFlag); + void (*xUnpin)(sqlite3_pcache*, void*, int discard); + void (*xRekey)(sqlite3_pcache*, void*, unsigned oldKey, unsigned newKey); + void (*xTruncate)(sqlite3_pcache*, unsigned iLimit); + void (*xDestroy)(sqlite3_pcache*); + }; + + /* + ** CAPI3REF: Online Backup Object + ** + ** The sqlite3_backup object records state information about an ongoing + ** online backup operation. ^The sqlite3_backup object is created by + ** a call to [sqlite3_backup_init()] and is destroyed by a call to + ** [sqlite3_backup_finish()]. + ** + ** See Also: [Using the SQLite Online Backup API] + */ + typedef struct sqlite3_backup sqlite3_backup; + + /* + ** CAPI3REF: Online Backup API. + ** + ** The backup API copies the content of one database into another. + ** It is useful either for creating backups of databases or + ** for copying in-memory databases to or from persistent files. + ** + ** See Also: [Using the SQLite Online Backup API] + ** + ** ^SQLite holds a write transaction open on the destination database file + ** for the duration of the backup operation. + ** ^The source database is read-locked only while it is being read; + ** it is not locked continuously for the entire backup operation. + ** ^Thus, the backup may be performed on a live source database without + ** preventing other database connections from + ** reading or writing to the source database while the backup is underway. + ** + ** ^(To perform a backup operation: + **
    + **
  1. sqlite3_backup_init() is called once to initialize the + ** backup, + **
  2. sqlite3_backup_step() is called one or more times to transfer + ** the data between the two databases, and finally + **
  3. sqlite3_backup_finish() is called to release all resources + ** associated with the backup operation. + **
)^ + ** There should be exactly one call to sqlite3_backup_finish() for each + ** successful call to sqlite3_backup_init(). + ** + ** [[sqlite3_backup_init()]] sqlite3_backup_init() + ** + ** ^The D and N arguments to sqlite3_backup_init(D,N,S,M) are the + ** [database connection] associated with the destination database + ** and the database name, respectively. + ** ^The database name is "main" for the main database, "temp" for the + ** temporary database, or the name specified after the AS keyword in + ** an [ATTACH] statement for an attached database. + ** ^The S and M arguments passed to + ** sqlite3_backup_init(D,N,S,M) identify the [database connection] + ** and database name of the source database, respectively. + ** ^The source and destination [database connections] (parameters S and D) + ** must be different or else sqlite3_backup_init(D,N,S,M) will fail with + ** an error. + ** + ** ^A call to sqlite3_backup_init() will fail, returning NULL, if + ** there is already a read or read-write transaction open on the + ** destination database. + ** + ** ^If an error occurs within sqlite3_backup_init(D,N,S,M), then NULL is + ** returned and an error code and error message are stored in the + ** destination [database connection] D. + ** ^The error code and message for the failed call to sqlite3_backup_init() + ** can be retrieved using the [sqlite3_errcode()], [sqlite3_errmsg()], and/or + ** [sqlite3_errmsg16()] functions. + ** ^A successful call to sqlite3_backup_init() returns a pointer to an + ** [sqlite3_backup] object. + ** ^The [sqlite3_backup] object may be used with the sqlite3_backup_step() and + ** sqlite3_backup_finish() functions to perform the specified backup + ** operation. + ** + ** [[sqlite3_backup_step()]] sqlite3_backup_step() + ** + ** ^Function sqlite3_backup_step(B,N) will copy up to N pages between + ** the source and destination databases specified by [sqlite3_backup] object B. + ** ^If N is negative, all remaining source pages are copied. + ** ^If sqlite3_backup_step(B,N) successfully copies N pages and there + ** are still more pages to be copied, then the function returns [SQLITE_OK]. + ** ^If sqlite3_backup_step(B,N) successfully finishes copying all pages + ** from source to destination, then it returns [SQLITE_DONE]. + ** ^If an error occurs while running sqlite3_backup_step(B,N), + ** then an [error code] is returned. ^As well as [SQLITE_OK] and + ** [SQLITE_DONE], a call to sqlite3_backup_step() may return [SQLITE_READONLY], + ** [SQLITE_NOMEM], [SQLITE_BUSY], [SQLITE_LOCKED], or an + ** [SQLITE_IOERR_ACCESS | SQLITE_IOERR_XXX] extended error code. + ** + ** ^(The sqlite3_backup_step() might return [SQLITE_READONLY] if + **
    + **
  1. the destination database was opened read-only, or + **
  2. the destination database is using write-ahead-log journaling + ** and the destination and source page sizes differ, or + **
  3. the destination database is an in-memory database and the + ** destination and source page sizes differ. + **
)^ + ** + ** ^If sqlite3_backup_step() cannot obtain a required file-system lock, then + ** the [sqlite3_busy_handler | busy-handler function] + ** is invoked (if one is specified). ^If the + ** busy-handler returns non-zero before the lock is available, then + ** [SQLITE_BUSY] is returned to the caller. ^In this case the call to + ** sqlite3_backup_step() can be retried later. ^If the source + ** [database connection] + ** is being used to write to the source database when sqlite3_backup_step() + ** is called, then [SQLITE_LOCKED] is returned immediately. ^Again, in this + ** case the call to sqlite3_backup_step() can be retried later on. ^(If + ** [SQLITE_IOERR_ACCESS | SQLITE_IOERR_XXX], [SQLITE_NOMEM], or + ** [SQLITE_READONLY] is returned, then + ** there is no point in retrying the call to sqlite3_backup_step(). These + ** errors are considered fatal.)^ The application must accept + ** that the backup operation has failed and pass the backup operation handle + ** to the sqlite3_backup_finish() to release associated resources. + ** + ** ^The first call to sqlite3_backup_step() obtains an exclusive lock + ** on the destination file. ^The exclusive lock is not released until either + ** sqlite3_backup_finish() is called or the backup operation is complete + ** and sqlite3_backup_step() returns [SQLITE_DONE]. ^Every call to + ** sqlite3_backup_step() obtains a [shared lock] on the source database that + ** lasts for the duration of the sqlite3_backup_step() call. + ** ^Because the source database is not locked between calls to + ** sqlite3_backup_step(), the source database may be modified mid-way + ** through the backup process. ^If the source database is modified by an + ** external process or via a database connection other than the one being + ** used by the backup operation, then the backup will be automatically + ** restarted by the next call to sqlite3_backup_step(). ^If the source + ** database is modified by the using the same database connection as is used + ** by the backup operation, then the backup database is automatically + ** updated at the same time. + ** + ** [[sqlite3_backup_finish()]] sqlite3_backup_finish() + ** + ** When sqlite3_backup_step() has returned [SQLITE_DONE], or when the + ** application wishes to abandon the backup operation, the application + ** should destroy the [sqlite3_backup] by passing it to sqlite3_backup_finish(). + ** ^The sqlite3_backup_finish() interfaces releases all + ** resources associated with the [sqlite3_backup] object. + ** ^If sqlite3_backup_step() has not yet returned [SQLITE_DONE], then any + ** active write-transaction on the destination database is rolled back. + ** The [sqlite3_backup] object is invalid + ** and may not be used following a call to sqlite3_backup_finish(). + ** + ** ^The value returned by sqlite3_backup_finish is [SQLITE_OK] if no + ** sqlite3_backup_step() errors occurred, regardless or whether or not + ** sqlite3_backup_step() completed. + ** ^If an out-of-memory condition or IO error occurred during any prior + ** sqlite3_backup_step() call on the same [sqlite3_backup] object, then + ** sqlite3_backup_finish() returns the corresponding [error code]. + ** + ** ^A return of [SQLITE_BUSY] or [SQLITE_LOCKED] from sqlite3_backup_step() + ** is not a permanent error and does not affect the return value of + ** sqlite3_backup_finish(). + ** + ** [[sqlite3_backup_remaining()]] [[sqlite3_backup_pagecount()]] + ** sqlite3_backup_remaining() and sqlite3_backup_pagecount() + ** + ** ^The sqlite3_backup_remaining() routine returns the number of pages still + ** to be backed up at the conclusion of the most recent sqlite3_backup_step(). + ** ^The sqlite3_backup_pagecount() routine returns the total number of pages + ** in the source database at the conclusion of the most recent + ** sqlite3_backup_step(). + ** ^(The values returned by these functions are only updated by + ** sqlite3_backup_step(). If the source database is modified in a way that + ** changes the size of the source database or the number of pages remaining, + ** those changes are not reflected in the output of sqlite3_backup_pagecount() + ** and sqlite3_backup_remaining() until after the next + ** sqlite3_backup_step().)^ + ** + ** Concurrent Usage of Database Handles + ** + ** ^The source [database connection] may be used by the application for other + ** purposes while a backup operation is underway or being initialized. + ** ^If SQLite is compiled and configured to support threadsafe database + ** connections, then the source database connection may be used concurrently + ** from within other threads. + ** + ** However, the application must guarantee that the destination + ** [database connection] is not passed to any other API (by any thread) after + ** sqlite3_backup_init() is called and before the corresponding call to + ** sqlite3_backup_finish(). SQLite does not currently check to see + ** if the application incorrectly accesses the destination [database connection] + ** and so no error code is reported, but the operations may malfunction + ** nevertheless. Use of the destination database connection while a + ** backup is in progress might also also cause a mutex deadlock. + ** + ** If running in [shared cache mode], the application must + ** guarantee that the shared cache used by the destination database + ** is not accessed while the backup is running. In practice this means + ** that the application must guarantee that the disk file being + ** backed up to is not accessed by any connection within the process, + ** not just the specific connection that was passed to sqlite3_backup_init(). + ** + ** The [sqlite3_backup] object itself is partially threadsafe. Multiple + ** threads may safely make multiple concurrent calls to sqlite3_backup_step(). + ** However, the sqlite3_backup_remaining() and sqlite3_backup_pagecount() + ** APIs are not strictly speaking threadsafe. If they are invoked at the + ** same time as another thread is invoking sqlite3_backup_step() it is + ** possible that they return invalid values. + */ + SQLITE_API sqlite3_backup* sqlite3_backup_init(sqlite3* pDest, /* Destination database handle */ + const char* zDestName, /* Destination database name */ + sqlite3* pSource, /* Source database handle */ + const char* zSourceName /* Source database name */ + ); + SQLITE_API int sqlite3_backup_step(sqlite3_backup* p, int nPage); + SQLITE_API int sqlite3_backup_finish(sqlite3_backup* p); + SQLITE_API int sqlite3_backup_remaining(sqlite3_backup* p); + SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup* p); + + /* + ** CAPI3REF: Unlock Notification + ** METHOD: sqlite3 + ** + ** ^When running in shared-cache mode, a database operation may fail with + ** an [SQLITE_LOCKED] error if the required locks on the shared-cache or + ** individual tables within the shared-cache cannot be obtained. See + ** [SQLite Shared-Cache Mode] for a description of shared-cache locking. + ** ^This API may be used to register a callback that SQLite will invoke + ** when the connection currently holding the required lock relinquishes it. + ** ^This API is only available if the library was compiled with the + ** [SQLITE_ENABLE_UNLOCK_NOTIFY] C-preprocessor symbol defined. + ** + ** See Also: [Using the SQLite Unlock Notification Feature]. + ** + ** ^Shared-cache locks are released when a database connection concludes + ** its current transaction, either by committing it or rolling it back. + ** + ** ^When a connection (known as the blocked connection) fails to obtain a + ** shared-cache lock and SQLITE_LOCKED is returned to the caller, the + ** identity of the database connection (the blocking connection) that + ** has locked the required resource is stored internally. ^After an + ** application receives an SQLITE_LOCKED error, it may call the + ** sqlite3_unlock_notify() method with the blocked connection handle as + ** the first argument to register for a callback that will be invoked + ** when the blocking connections current transaction is concluded. ^The + ** callback is invoked from within the [sqlite3_step] or [sqlite3_close] + ** call that concludes the blocking connection's transaction. + ** + ** ^(If sqlite3_unlock_notify() is called in a multi-threaded application, + ** there is a chance that the blocking connection will have already + ** concluded its transaction by the time sqlite3_unlock_notify() is invoked. + ** If this happens, then the specified callback is invoked immediately, + ** from within the call to sqlite3_unlock_notify().)^ + ** + ** ^If the blocked connection is attempting to obtain a write-lock on a + ** shared-cache table, and more than one other connection currently holds + ** a read-lock on the same table, then SQLite arbitrarily selects one of + ** the other connections to use as the blocking connection. + ** + ** ^(There may be at most one unlock-notify callback registered by a + ** blocked connection. If sqlite3_unlock_notify() is called when the + ** blocked connection already has a registered unlock-notify callback, + ** then the new callback replaces the old.)^ ^If sqlite3_unlock_notify() is + ** called with a NULL pointer as its second argument, then any existing + ** unlock-notify callback is canceled. ^The blocked connections + ** unlock-notify callback may also be canceled by closing the blocked + ** connection using [sqlite3_close()]. + ** + ** The unlock-notify callback is not reentrant. If an application invokes + ** any sqlite3_xxx API functions from within an unlock-notify callback, a + ** crash or deadlock may be the result. + ** + ** ^Unless deadlock is detected (see below), sqlite3_unlock_notify() always + ** returns SQLITE_OK. + ** + ** Callback Invocation Details + ** + ** When an unlock-notify callback is registered, the application provides a + ** single void* pointer that is passed to the callback when it is invoked. + ** However, the signature of the callback function allows SQLite to pass + ** it an array of void* context pointers. The first argument passed to + ** an unlock-notify callback is a pointer to an array of void* pointers, + ** and the second is the number of entries in the array. + ** + ** When a blocking connection's transaction is concluded, there may be + ** more than one blocked connection that has registered for an unlock-notify + ** callback. ^If two or more such blocked connections have specified the + ** same callback function, then instead of invoking the callback function + ** multiple times, it is invoked once with the set of void* context pointers + ** specified by the blocked connections bundled together into an array. + ** This gives the application an opportunity to prioritize any actions + ** related to the set of unblocked database connections. + ** + ** Deadlock Detection + ** + ** Assuming that after registering for an unlock-notify callback a + ** database waits for the callback to be issued before taking any further + ** action (a reasonable assumption), then using this API may cause the + ** application to deadlock. For example, if connection X is waiting for + ** connection Y's transaction to be concluded, and similarly connection + ** Y is waiting on connection X's transaction, then neither connection + ** will proceed and the system may remain deadlocked indefinitely. + ** + ** To avoid this scenario, the sqlite3_unlock_notify() performs deadlock + ** detection. ^If a given call to sqlite3_unlock_notify() would put the + ** system in a deadlocked state, then SQLITE_LOCKED is returned and no + ** unlock-notify callback is registered. The system is said to be in + ** a deadlocked state if connection A has registered for an unlock-notify + ** callback on the conclusion of connection B's transaction, and connection + ** B has itself registered for an unlock-notify callback when connection + ** A's transaction is concluded. ^Indirect deadlock is also detected, so + ** the system is also considered to be deadlocked if connection B has + ** registered for an unlock-notify callback on the conclusion of connection + ** C's transaction, where connection C is waiting on connection A. ^Any + ** number of levels of indirection are allowed. + ** + ** The "DROP TABLE" Exception + ** + ** When a call to [sqlite3_step()] returns SQLITE_LOCKED, it is almost + ** always appropriate to call sqlite3_unlock_notify(). There is however, + ** one exception. When executing a "DROP TABLE" or "DROP INDEX" statement, + ** SQLite checks if there are any currently executing SELECT statements + ** that belong to the same connection. If there are, SQLITE_LOCKED is + ** returned. In this case there is no "blocking connection", so invoking + ** sqlite3_unlock_notify() results in the unlock-notify callback being + ** invoked immediately. If the application then re-attempts the "DROP TABLE" + ** or "DROP INDEX" query, an infinite loop might be the result. + ** + ** One way around this problem is to check the extended error code returned + ** by an sqlite3_step() call. ^(If there is a blocking connection, then the + ** extended error code is set to SQLITE_LOCKED_SHAREDCACHE. Otherwise, in + ** the special "DROP TABLE/INDEX" case, the extended error code is just + ** SQLITE_LOCKED.)^ + */ + SQLITE_API int sqlite3_unlock_notify(sqlite3* pBlocked, /* Waiting connection */ + void (*xNotify)(void** apArg, int nArg), /* Callback function to invoke */ + void* pNotifyArg /* Argument to pass to xNotify */ + ); + + /* + ** CAPI3REF: String Comparison + ** + ** ^The [sqlite3_stricmp()] and [sqlite3_strnicmp()] APIs allow applications + ** and extensions to compare the contents of two buffers containing UTF-8 + ** strings in a case-independent fashion, using the same definition of "case + ** independence" that SQLite uses internally when comparing identifiers. + */ + SQLITE_API int sqlite3_stricmp(const char*, const char*); + SQLITE_API int sqlite3_strnicmp(const char*, const char*, int); + + /* + ** CAPI3REF: String Globbing + * + ** ^The [sqlite3_strglob(P,X)] interface returns zero if and only if + ** string X matches the [GLOB] pattern P. + ** ^The definition of [GLOB] pattern matching used in + ** [sqlite3_strglob(P,X)] is the same as for the "X GLOB P" operator in the + ** SQL dialect understood by SQLite. ^The [sqlite3_strglob(P,X)] function + ** is case sensitive. + ** + ** Note that this routine returns zero on a match and non-zero if the strings + ** do not match, the same as [sqlite3_stricmp()] and [sqlite3_strnicmp()]. + ** + ** See also: [sqlite3_strlike()]. + */ + SQLITE_API int sqlite3_strglob(const char* zGlob, const char* zStr); + + /* + ** CAPI3REF: String LIKE Matching + * + ** ^The [sqlite3_strlike(P,X,E)] interface returns zero if and only if + ** string X matches the [LIKE] pattern P with escape character E. + ** ^The definition of [LIKE] pattern matching used in + ** [sqlite3_strlike(P,X,E)] is the same as for the "X LIKE P ESCAPE E" + ** operator in the SQL dialect understood by SQLite. ^For "X LIKE P" without + ** the ESCAPE clause, set the E parameter of [sqlite3_strlike(P,X,E)] to 0. + ** ^As with the LIKE operator, the [sqlite3_strlike(P,X,E)] function is case + ** insensitive - equivalent upper and lower case ASCII characters match + ** one another. + ** + ** ^The [sqlite3_strlike(P,X,E)] function matches Unicode characters, though + ** only ASCII characters are case folded. + ** + ** Note that this routine returns zero on a match and non-zero if the strings + ** do not match, the same as [sqlite3_stricmp()] and [sqlite3_strnicmp()]. + ** + ** See also: [sqlite3_strglob()]. + */ + SQLITE_API int sqlite3_strlike(const char* zGlob, const char* zStr, unsigned int cEsc); + + /* + ** CAPI3REF: Error Logging Interface + ** + ** ^The [sqlite3_log()] interface writes a message into the [error log] + ** established by the [SQLITE_CONFIG_LOG] option to [sqlite3_config()]. + ** ^If logging is enabled, the zFormat string and subsequent arguments are + ** used with [sqlite3_snprintf()] to generate the final output string. + ** + ** The sqlite3_log() interface is intended for use by extensions such as + ** virtual tables, collating functions, and SQL functions. While there is + ** nothing to prevent an application from calling sqlite3_log(), doing so + ** is considered bad form. + ** + ** The zFormat string must not be NULL. + ** + ** To avoid deadlocks and other threading problems, the sqlite3_log() routine + ** will not use dynamically allocated memory. The log message is stored in + ** a fixed-length buffer on the stack. If the log message is longer than + ** a few hundred characters, it will be truncated to the length of the + ** buffer. + */ + SQLITE_API void sqlite3_log(int iErrCode, const char* zFormat, ...); + + /* + ** CAPI3REF: Write-Ahead Log Commit Hook + ** METHOD: sqlite3 + ** + ** ^The [sqlite3_wal_hook()] function is used to register a callback that + ** is invoked each time data is committed to a database in wal mode. + ** + ** ^(The callback is invoked by SQLite after the commit has taken place and + ** the associated write-lock on the database released)^, so the implementation + ** may read, write or [checkpoint] the database as required. + ** + ** ^The first parameter passed to the callback function when it is invoked + ** is a copy of the third parameter passed to sqlite3_wal_hook() when + ** registering the callback. ^The second is a copy of the database handle. + ** ^The third parameter is the name of the database that was written to - + ** either "main" or the name of an [ATTACH]-ed database. ^The fourth parameter + ** is the number of pages currently in the write-ahead log file, + ** including those that were just committed. + ** + ** The callback function should normally return [SQLITE_OK]. ^If an error + ** code is returned, that error will propagate back up through the + ** SQLite code base to cause the statement that provoked the callback + ** to report an error, though the commit will have still occurred. If the + ** callback returns [SQLITE_ROW] or [SQLITE_DONE], or if it returns a value + ** that does not correspond to any valid SQLite error code, the results + ** are undefined. + ** + ** A single database handle may have at most a single write-ahead log callback + ** registered at one time. ^Calling [sqlite3_wal_hook()] replaces any + ** previously registered write-ahead log callback. ^The return value is + ** a copy of the third parameter from the previous call, if any, or 0. + ** ^Note that the [sqlite3_wal_autocheckpoint()] interface and the + ** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will + ** overwrite any prior [sqlite3_wal_hook()] settings. + */ + SQLITE_API void* sqlite3_wal_hook(sqlite3*, int (*)(void*, sqlite3*, const char*, int), void*); + + /* + ** CAPI3REF: Configure an auto-checkpoint + ** METHOD: sqlite3 + ** + ** ^The [sqlite3_wal_autocheckpoint(D,N)] is a wrapper around + ** [sqlite3_wal_hook()] that causes any database on [database connection] D + ** to automatically [checkpoint] + ** after committing a transaction if there are N or + ** more frames in the [write-ahead log] file. ^Passing zero or + ** a negative value as the nFrame parameter disables automatic + ** checkpoints entirely. + ** + ** ^The callback registered by this function replaces any existing callback + ** registered using [sqlite3_wal_hook()]. ^Likewise, registering a callback + ** using [sqlite3_wal_hook()] disables the automatic checkpoint mechanism + ** configured by this function. + ** + ** ^The [wal_autocheckpoint pragma] can be used to invoke this interface + ** from SQL. + ** + ** ^Checkpoints initiated by this mechanism are + ** [sqlite3_wal_checkpoint_v2|PASSIVE]. + ** + ** ^Every new [database connection] defaults to having the auto-checkpoint + ** enabled with a threshold of 1000 or [SQLITE_DEFAULT_WAL_AUTOCHECKPOINT] + ** pages. The use of this interface + ** is only necessary if the default setting is found to be suboptimal + ** for a particular application. + */ + SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3* db, int N); + + /* + ** CAPI3REF: Checkpoint a database + ** METHOD: sqlite3 + ** + ** ^(The sqlite3_wal_checkpoint(D,X) is equivalent to + ** [sqlite3_wal_checkpoint_v2](D,X,[SQLITE_CHECKPOINT_PASSIVE],0,0).)^ + ** + ** In brief, sqlite3_wal_checkpoint(D,X) causes the content in the + ** [write-ahead log] for database X on [database connection] D to be + ** transferred into the database file and for the write-ahead log to + ** be reset. See the [checkpointing] documentation for addition + ** information. + ** + ** This interface used to be the only way to cause a checkpoint to + ** occur. But then the newer and more powerful [sqlite3_wal_checkpoint_v2()] + ** interface was added. This interface is retained for backwards + ** compatibility and as a convenience for applications that need to manually + ** start a callback but which do not need the full power (and corresponding + ** complication) of [sqlite3_wal_checkpoint_v2()]. + */ + SQLITE_API int sqlite3_wal_checkpoint(sqlite3* db, const char* zDb); + + /* + ** CAPI3REF: Checkpoint a database + ** METHOD: sqlite3 + ** + ** ^(The sqlite3_wal_checkpoint_v2(D,X,M,L,C) interface runs a checkpoint + ** operation on database X of [database connection] D in mode M. Status + ** information is written back into integers pointed to by L and C.)^ + ** ^(The M parameter must be a valid [checkpoint mode]:)^ + ** + **
+ **
SQLITE_CHECKPOINT_PASSIVE
+ ** ^Checkpoint as many frames as possible without waiting for any database + ** readers or writers to finish, then sync the database file if all frames + ** in the log were checkpointed. ^The [busy-handler callback] + ** is never invoked in the SQLITE_CHECKPOINT_PASSIVE mode. + ** ^On the other hand, passive mode might leave the checkpoint unfinished + ** if there are concurrent readers or writers. + ** + **
SQLITE_CHECKPOINT_FULL
+ ** ^This mode blocks (it invokes the + ** [sqlite3_busy_handler|busy-handler callback]) until there is no + ** database writer and all readers are reading from the most recent database + ** snapshot. ^It then checkpoints all frames in the log file and syncs the + ** database file. ^This mode blocks new database writers while it is pending, + ** but new database readers are allowed to continue unimpeded. + ** + **
SQLITE_CHECKPOINT_RESTART
+ ** ^This mode works the same way as SQLITE_CHECKPOINT_FULL with the addition + ** that after checkpointing the log file it blocks (calls the + ** [busy-handler callback]) + ** until all readers are reading from the database file only. ^This ensures + ** that the next writer will restart the log file from the beginning. + ** ^Like SQLITE_CHECKPOINT_FULL, this mode blocks new + ** database writer attempts while it is pending, but does not impede readers. + ** + **
SQLITE_CHECKPOINT_TRUNCATE
+ ** ^This mode works the same way as SQLITE_CHECKPOINT_RESTART with the + ** addition that it also truncates the log file to zero bytes just prior + ** to a successful return. + **
+ ** + ** ^If pnLog is not NULL, then *pnLog is set to the total number of frames in + ** the log file or to -1 if the checkpoint could not run because + ** of an error or because the database is not in [WAL mode]. ^If pnCkpt is not + ** NULL,then *pnCkpt is set to the total number of checkpointed frames in the + ** log file (including any that were already checkpointed before the function + ** was called) or to -1 if the checkpoint could not run due to an error or + ** because the database is not in WAL mode. ^Note that upon successful + ** completion of an SQLITE_CHECKPOINT_TRUNCATE, the log file will have been + ** truncated to zero bytes and so both *pnLog and *pnCkpt will be set to zero. + ** + ** ^All calls obtain an exclusive "checkpoint" lock on the database file. ^If + ** any other process is running a checkpoint operation at the same time, the + ** lock cannot be obtained and SQLITE_BUSY is returned. ^Even if there is a + ** busy-handler configured, it will not be invoked in this case. + ** + ** ^The SQLITE_CHECKPOINT_FULL, RESTART and TRUNCATE modes also obtain the + ** exclusive "writer" lock on the database file. ^If the writer lock cannot be + ** obtained immediately, and a busy-handler is configured, it is invoked and + ** the writer lock retried until either the busy-handler returns 0 or the lock + ** is successfully obtained. ^The busy-handler is also invoked while waiting for + ** database readers as described above. ^If the busy-handler returns 0 before + ** the writer lock is obtained or while waiting for database readers, the + ** checkpoint operation proceeds from that point in the same way as + ** SQLITE_CHECKPOINT_PASSIVE - checkpointing as many frames as possible + ** without blocking any further. ^SQLITE_BUSY is returned in this case. + ** + ** ^If parameter zDb is NULL or points to a zero length string, then the + ** specified operation is attempted on all WAL databases [attached] to + ** [database connection] db. In this case the + ** values written to output parameters *pnLog and *pnCkpt are undefined. ^If + ** an SQLITE_BUSY error is encountered when processing one or more of the + ** attached WAL databases, the operation is still attempted on any remaining + ** attached databases and SQLITE_BUSY is returned at the end. ^If any other + ** error occurs while processing an attached database, processing is abandoned + ** and the error code is returned to the caller immediately. ^If no error + ** (SQLITE_BUSY or otherwise) is encountered while processing the attached + ** databases, SQLITE_OK is returned. + ** + ** ^If database zDb is the name of an attached database that is not in WAL + ** mode, SQLITE_OK is returned and both *pnLog and *pnCkpt set to -1. ^If + ** zDb is not NULL (or a zero length string) and is not the name of any + ** attached database, SQLITE_ERROR is returned to the caller. + ** + ** ^Unless it returns SQLITE_MISUSE, + ** the sqlite3_wal_checkpoint_v2() interface + ** sets the error information that is queried by + ** [sqlite3_errcode()] and [sqlite3_errmsg()]. + ** + ** ^The [PRAGMA wal_checkpoint] command can be used to invoke this interface + ** from SQL. + */ + SQLITE_API int sqlite3_wal_checkpoint_v2(sqlite3* db, /* Database handle */ + const char* zDb, /* Name of attached database (or NULL) */ + int eMode, /* SQLITE_CHECKPOINT_* value */ + int* pnLog, /* OUT: Size of WAL log in frames */ + int* pnCkpt /* OUT: Total number of frames checkpointed */ + ); /* ** CAPI3REF: Checkpoint Mode Values @@ -9378,30 +9305,30 @@ SQLITE_API int sqlite3_wal_checkpoint_v2( ** See the [sqlite3_wal_checkpoint_v2()] documentation for details on the ** meaning of each of these checkpoint modes. */ -#define SQLITE_CHECKPOINT_PASSIVE 0 /* Do as much as possible w/o blocking */ -#define SQLITE_CHECKPOINT_FULL 1 /* Wait for writers, then checkpoint */ -#define SQLITE_CHECKPOINT_RESTART 2 /* Like FULL but wait for for readers */ -#define SQLITE_CHECKPOINT_TRUNCATE 3 /* Like RESTART but also truncate WAL */ - -/* -** CAPI3REF: Virtual Table Interface Configuration -** -** This function may be called by either the [xConnect] or [xCreate] method -** of a [virtual table] implementation to configure -** various facets of the virtual table interface. -** -** If this interface is invoked outside the context of an xConnect or -** xCreate virtual table method then the behavior is undefined. -** -** In the call sqlite3_vtab_config(D,C,...) the D parameter is the -** [database connection] in which the virtual table is being created and -** which is passed in as the first argument to the [xConnect] or [xCreate] -** method that is invoking sqlite3_vtab_config(). The C parameter is one -** of the [virtual table configuration options]. The presence and meaning -** of parameters after C depend on which [virtual table configuration option] -** is used. -*/ -SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); +#define SQLITE_CHECKPOINT_PASSIVE 0 /* Do as much as possible w/o blocking */ +#define SQLITE_CHECKPOINT_FULL 1 /* Wait for writers, then checkpoint */ +#define SQLITE_CHECKPOINT_RESTART 2 /* Like FULL but wait for for readers */ +#define SQLITE_CHECKPOINT_TRUNCATE 3 /* Like RESTART but also truncate WAL */ + + /* + ** CAPI3REF: Virtual Table Interface Configuration + ** + ** This function may be called by either the [xConnect] or [xCreate] method + ** of a [virtual table] implementation to configure + ** various facets of the virtual table interface. + ** + ** If this interface is invoked outside the context of an xConnect or + ** xCreate virtual table method then the behavior is undefined. + ** + ** In the call sqlite3_vtab_config(D,C,...) the D parameter is the + ** [database connection] in which the virtual table is being created and + ** which is passed in as the first argument to the [xConnect] or [xCreate] + ** method that is invoking sqlite3_vtab_config(). The C parameter is one + ** of the [virtual table configuration options]. The presence and meaning + ** of parameters after C depend on which [virtual table configuration option] + ** is used. + */ + SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); /* ** CAPI3REF: Virtual Table Configuration Options @@ -9466,311 +9393,311 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); ** */ #define SQLITE_VTAB_CONSTRAINT_SUPPORT 1 -#define SQLITE_VTAB_INNOCUOUS 2 -#define SQLITE_VTAB_DIRECTONLY 3 - -/* -** CAPI3REF: Determine The Virtual Table Conflict Policy -** -** This function may only be called from within a call to the [xUpdate] method -** of a [virtual table] implementation for an INSERT or UPDATE operation. ^The -** value returned is one of [SQLITE_ROLLBACK], [SQLITE_IGNORE], [SQLITE_FAIL], -** [SQLITE_ABORT], or [SQLITE_REPLACE], according to the [ON CONFLICT] mode -** of the SQL statement that triggered the call to the [xUpdate] method of the -** [virtual table]. -*/ -SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *); - -/* -** CAPI3REF: Determine If Virtual Table Column Access Is For UPDATE -** -** If the sqlite3_vtab_nochange(X) routine is called within the [xColumn] -** method of a [virtual table], then it might return true if the -** column is being fetched as part of an UPDATE operation during which the -** column value will not change. The virtual table implementation can use -** this hint as permission to substitute a return value that is less -** expensive to compute and that the corresponding -** [xUpdate] method understands as a "no-change" value. -** -** If the [xColumn] method calls sqlite3_vtab_nochange() and finds that -** the column is not changed by the UPDATE statement, then the xColumn -** method can optionally return without setting a result, without calling -** any of the [sqlite3_result_int|sqlite3_result_xxxxx() interfaces]. -** In that case, [sqlite3_value_nochange(X)] will return true for the -** same column in the [xUpdate] method. -** -** The sqlite3_vtab_nochange() routine is an optimization. Virtual table -** implementations should continue to give a correct answer even if the -** sqlite3_vtab_nochange() interface were to always return false. In the -** current implementation, the sqlite3_vtab_nochange() interface does always -** returns false for the enhanced [UPDATE FROM] statement. -*/ -SQLITE_API int sqlite3_vtab_nochange(sqlite3_context*); - -/* -** CAPI3REF: Determine The Collation For a Virtual Table Constraint -** METHOD: sqlite3_index_info -** -** This function may only be called from within a call to the [xBestIndex] -** method of a [virtual table]. This function returns a pointer to a string -** that is the name of the appropriate collation sequence to use for text -** comparisons on the constraint identified by its arguments. -** -** The first argument must be the pointer to the [sqlite3_index_info] object -** that is the first parameter to the xBestIndex() method. The second argument -** must be an index into the aConstraint[] array belonging to the -** sqlite3_index_info structure passed to xBestIndex. -** -** Important: -** The first parameter must be the same pointer that is passed into the -** xBestMethod() method. The first parameter may not be a pointer to a -** different [sqlite3_index_info] object, even an exact copy. -** -** The return value is computed as follows: -** -**
    -**
  1. If the constraint comes from a WHERE clause expression that contains -** a [COLLATE operator], then the name of the collation specified by -** that COLLATE operator is returned. -**

  2. If there is no COLLATE operator, but the column that is the subject -** of the constraint specifies an alternative collating sequence via -** a [COLLATE clause] on the column definition within the CREATE TABLE -** statement that was passed into [sqlite3_declare_vtab()], then the -** name of that alternative collating sequence is returned. -**

  3. Otherwise, "BINARY" is returned. -**

-*/ -SQLITE_API SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int); - -/* -** CAPI3REF: Determine if a virtual table query is DISTINCT -** METHOD: sqlite3_index_info -** -** This API may only be used from within an [xBestIndex|xBestIndex method] -** of a [virtual table] implementation. The result of calling this -** interface from outside of xBestIndex() is undefined and probably harmful. -** -** ^The sqlite3_vtab_distinct() interface returns an integer that is -** either 0, 1, or 2. The integer returned by sqlite3_vtab_distinct() -** gives the virtual table additional information about how the query -** planner wants the output to be ordered. As long as the virtual table -** can meet the ordering requirements of the query planner, it may set -** the "orderByConsumed" flag. -** -**
  1. -** ^If the sqlite3_vtab_distinct() interface returns 0, that means -** that the query planner needs the virtual table to return all rows in the -** sort order defined by the "nOrderBy" and "aOrderBy" fields of the -** [sqlite3_index_info] object. This is the default expectation. If the -** virtual table outputs all rows in sorted order, then it is always safe for -** the xBestIndex method to set the "orderByConsumed" flag, regardless of -** the return value from sqlite3_vtab_distinct(). -**

  2. -** ^(If the sqlite3_vtab_distinct() interface returns 1, that means -** that the query planner does not need the rows to be returned in sorted order -** as long as all rows with the same values in all columns identified by the -** "aOrderBy" field are adjacent.)^ This mode is used when the query planner -** is doing a GROUP BY. -**

  3. -** ^(If the sqlite3_vtab_distinct() interface returns 2, that means -** that the query planner does not need the rows returned in any particular -** order, as long as rows with the same values in all "aOrderBy" columns -** are adjacent.)^ ^(Furthermore, only a single row for each particular -** combination of values in the columns identified by the "aOrderBy" field -** needs to be returned.)^ ^It is always ok for two or more rows with the same -** values in all "aOrderBy" columns to be returned, as long as all such rows -** are adjacent. ^The virtual table may, if it chooses, omit extra rows -** that have the same value for all columns identified by "aOrderBy". -** ^However omitting the extra rows is optional. -** This mode is used for a DISTINCT query. -**

-** -** ^For the purposes of comparing virtual table output values to see if the -** values are same value for sorting purposes, two NULL values are considered -** to be the same. In other words, the comparison operator is "IS" -** (or "IS NOT DISTINCT FROM") and not "==". -** -** If a virtual table implementation is unable to meet the requirements -** specified above, then it must not set the "orderByConsumed" flag in the -** [sqlite3_index_info] object or an incorrect answer may result. -** -** ^A virtual table implementation is always free to return rows in any order -** it wants, as long as the "orderByConsumed" flag is not set. ^When the -** the "orderByConsumed" flag is unset, the query planner will add extra -** [bytecode] to ensure that the final results returned by the SQL query are -** ordered correctly. The use of the "orderByConsumed" flag and the -** sqlite3_vtab_distinct() interface is merely an optimization. ^Careful -** use of the sqlite3_vtab_distinct() interface and the "orderByConsumed" -** flag might help queries against a virtual table to run faster. Being -** overly aggressive and setting the "orderByConsumed" flag when it is not -** valid to do so, on the other hand, might cause SQLite to return incorrect -** results. -*/ -SQLITE_API int sqlite3_vtab_distinct(sqlite3_index_info*); - -/* -** CAPI3REF: Identify and handle IN constraints in xBestIndex -** -** This interface may only be used from within an -** [xBestIndex|xBestIndex() method] of a [virtual table] implementation. -** The result of invoking this interface from any other context is -** undefined and probably harmful. -** -** ^(A constraint on a virtual table of the form -** "[IN operator|column IN (...)]" is -** communicated to the xBestIndex method as a -** [SQLITE_INDEX_CONSTRAINT_EQ] constraint.)^ If xBestIndex wants to use -** this constraint, it must set the corresponding -** aConstraintUsage[].argvIndex to a postive integer. ^(Then, under -** the usual mode of handling IN operators, SQLite generates [bytecode] -** that invokes the [xFilter|xFilter() method] once for each value -** on the right-hand side of the IN operator.)^ Thus the virtual table -** only sees a single value from the right-hand side of the IN operator -** at a time. -** -** In some cases, however, it would be advantageous for the virtual -** table to see all values on the right-hand of the IN operator all at -** once. The sqlite3_vtab_in() interfaces facilitates this in two ways: -** -**
    -**
  1. -** ^A call to sqlite3_vtab_in(P,N,-1) will return true (non-zero) -** if and only if the [sqlite3_index_info|P->aConstraint][N] constraint -** is an [IN operator] that can be processed all at once. ^In other words, -** sqlite3_vtab_in() with -1 in the third argument is a mechanism -** by which the virtual table can ask SQLite if all-at-once processing -** of the IN operator is even possible. -** -**

  2. -** ^A call to sqlite3_vtab_in(P,N,F) with F==1 or F==0 indicates -** to SQLite that the virtual table does or does not want to process -** the IN operator all-at-once, respectively. ^Thus when the third -** parameter (F) is non-negative, this interface is the mechanism by -** which the virtual table tells SQLite how it wants to process the -** IN operator. -**

-** -** ^The sqlite3_vtab_in(P,N,F) interface can be invoked multiple times -** within the same xBestIndex method call. ^For any given P,N pair, -** the return value from sqlite3_vtab_in(P,N,F) will always be the same -** within the same xBestIndex call. ^If the interface returns true -** (non-zero), that means that the constraint is an IN operator -** that can be processed all-at-once. ^If the constraint is not an IN -** operator or cannot be processed all-at-once, then the interface returns -** false. -** -** ^(All-at-once processing of the IN operator is selected if both of the -** following conditions are met: -** -**
    -**
  1. The P->aConstraintUsage[N].argvIndex value is set to a positive -** integer. This is how the virtual table tells SQLite that it wants to -** use the N-th constraint. -** -**

  2. The last call to sqlite3_vtab_in(P,N,F) for which F was -** non-negative had F>=1. -**

)^ -** -** ^If either or both of the conditions above are false, then SQLite uses -** the traditional one-at-a-time processing strategy for the IN constraint. -** ^If both conditions are true, then the argvIndex-th parameter to the -** xFilter method will be an [sqlite3_value] that appears to be NULL, -** but which can be passed to [sqlite3_vtab_in_first()] and -** [sqlite3_vtab_in_next()] to find all values on the right-hand side -** of the IN constraint. -*/ -SQLITE_API int sqlite3_vtab_in(sqlite3_index_info*, int iCons, int bHandle); - -/* -** CAPI3REF: Find all elements on the right-hand side of an IN constraint. -** -** These interfaces are only useful from within the -** [xFilter|xFilter() method] of a [virtual table] implementation. -** The result of invoking these interfaces from any other context -** is undefined and probably harmful. -** -** The X parameter in a call to sqlite3_vtab_in_first(X,P) or -** sqlite3_vtab_in_next(X,P) must be one of the parameters to the -** xFilter method which invokes these routines, and specifically -** a parameter that was previously selected for all-at-once IN constraint -** processing use the [sqlite3_vtab_in()] interface in the -** [xBestIndex|xBestIndex method]. ^(If the X parameter is not -** an xFilter argument that was selected for all-at-once IN constraint -** processing, then these routines return [SQLITE_MISUSE])^ or perhaps -** exhibit some other undefined or harmful behavior. -** -** ^(Use these routines to access all values on the right-hand side -** of the IN constraint using code like the following: -** -**
-**    for(rc=sqlite3_vtab_in_first(pList, &pVal);
-**        rc==SQLITE_OK && pVal
-**        rc=sqlite3_vtab_in_next(pList, &pVal)
-**    ){
-**      // do something with pVal
-**    }
-**    if( rc!=SQLITE_OK ){
-**      // an error has occurred
-**    }
-** 
)^ -** -** ^On success, the sqlite3_vtab_in_first(X,P) and sqlite3_vtab_in_next(X,P) -** routines return SQLITE_OK and set *P to point to the first or next value -** on the RHS of the IN constraint. ^If there are no more values on the -** right hand side of the IN constraint, then *P is set to NULL and these -** routines return [SQLITE_DONE]. ^The return value might be -** some other value, such as SQLITE_NOMEM, in the event of a malfunction. -** -** The *ppOut values returned by these routines are only valid until the -** next call to either of these routines or until the end of the xFilter -** method from which these routines were called. If the virtual table -** implementation needs to retain the *ppOut values for longer, it must make -** copies. The *ppOut values are [protected sqlite3_value|protected]. -*/ -SQLITE_API int sqlite3_vtab_in_first(sqlite3_value *pVal, sqlite3_value **ppOut); -SQLITE_API int sqlite3_vtab_in_next(sqlite3_value *pVal, sqlite3_value **ppOut); - -/* -** CAPI3REF: Constraint values in xBestIndex() -** METHOD: sqlite3_index_info -** -** This API may only be used from within the [xBestIndex|xBestIndex method] -** of a [virtual table] implementation. The result of calling this interface -** from outside of an xBestIndex method are undefined and probably harmful. -** -** ^When the sqlite3_vtab_rhs_value(P,J,V) interface is invoked from within -** the [xBestIndex] method of a [virtual table] implementation, with P being -** a copy of the [sqlite3_index_info] object pointer passed into xBestIndex and -** J being a 0-based index into P->aConstraint[], then this routine -** attempts to set *V to the value of the right-hand operand of -** that constraint if the right-hand operand is known. ^If the -** right-hand operand is not known, then *V is set to a NULL pointer. -** ^The sqlite3_vtab_rhs_value(P,J,V) interface returns SQLITE_OK if -** and only if *V is set to a value. ^The sqlite3_vtab_rhs_value(P,J,V) -** inteface returns SQLITE_NOTFOUND if the right-hand side of the J-th -** constraint is not available. ^The sqlite3_vtab_rhs_value() interface -** can return an result code other than SQLITE_OK or SQLITE_NOTFOUND if -** something goes wrong. -** -** The sqlite3_vtab_rhs_value() interface is usually only successful if -** the right-hand operand of a constraint is a literal value in the original -** SQL statement. If the right-hand operand is an expression or a reference -** to some other column or a [host parameter], then sqlite3_vtab_rhs_value() -** will probably return [SQLITE_NOTFOUND]. -** -** ^(Some constraints, such as [SQLITE_INDEX_CONSTRAINT_ISNULL] and -** [SQLITE_INDEX_CONSTRAINT_ISNOTNULL], have no right-hand operand. For such -** constraints, sqlite3_vtab_rhs_value() always returns SQLITE_NOTFOUND.)^ -** -** ^The [sqlite3_value] object returned in *V is a protected sqlite3_value -** and remains valid for the duration of the xBestIndex method call. -** ^When xBestIndex returns, the sqlite3_value object returned by -** sqlite3_vtab_rhs_value() is automatically deallocated. -** -** The "_rhs_" in the name of this routine is an appreviation for -** "Right-Hand Side". -*/ -SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value **ppVal); +#define SQLITE_VTAB_INNOCUOUS 2 +#define SQLITE_VTAB_DIRECTONLY 3 + + /* + ** CAPI3REF: Determine The Virtual Table Conflict Policy + ** + ** This function may only be called from within a call to the [xUpdate] method + ** of a [virtual table] implementation for an INSERT or UPDATE operation. ^The + ** value returned is one of [SQLITE_ROLLBACK], [SQLITE_IGNORE], [SQLITE_FAIL], + ** [SQLITE_ABORT], or [SQLITE_REPLACE], according to the [ON CONFLICT] mode + ** of the SQL statement that triggered the call to the [xUpdate] method of the + ** [virtual table]. + */ + SQLITE_API int sqlite3_vtab_on_conflict(sqlite3*); + + /* + ** CAPI3REF: Determine If Virtual Table Column Access Is For UPDATE + ** + ** If the sqlite3_vtab_nochange(X) routine is called within the [xColumn] + ** method of a [virtual table], then it might return true if the + ** column is being fetched as part of an UPDATE operation during which the + ** column value will not change. The virtual table implementation can use + ** this hint as permission to substitute a return value that is less + ** expensive to compute and that the corresponding + ** [xUpdate] method understands as a "no-change" value. + ** + ** If the [xColumn] method calls sqlite3_vtab_nochange() and finds that + ** the column is not changed by the UPDATE statement, then the xColumn + ** method can optionally return without setting a result, without calling + ** any of the [sqlite3_result_int|sqlite3_result_xxxxx() interfaces]. + ** In that case, [sqlite3_value_nochange(X)] will return true for the + ** same column in the [xUpdate] method. + ** + ** The sqlite3_vtab_nochange() routine is an optimization. Virtual table + ** implementations should continue to give a correct answer even if the + ** sqlite3_vtab_nochange() interface were to always return false. In the + ** current implementation, the sqlite3_vtab_nochange() interface does always + ** returns false for the enhanced [UPDATE FROM] statement. + */ + SQLITE_API int sqlite3_vtab_nochange(sqlite3_context*); + + /* + ** CAPI3REF: Determine The Collation For a Virtual Table Constraint + ** METHOD: sqlite3_index_info + ** + ** This function may only be called from within a call to the [xBestIndex] + ** method of a [virtual table]. This function returns a pointer to a string + ** that is the name of the appropriate collation sequence to use for text + ** comparisons on the constraint identified by its arguments. + ** + ** The first argument must be the pointer to the [sqlite3_index_info] object + ** that is the first parameter to the xBestIndex() method. The second argument + ** must be an index into the aConstraint[] array belonging to the + ** sqlite3_index_info structure passed to xBestIndex. + ** + ** Important: + ** The first parameter must be the same pointer that is passed into the + ** xBestMethod() method. The first parameter may not be a pointer to a + ** different [sqlite3_index_info] object, even an exact copy. + ** + ** The return value is computed as follows: + ** + **
    + **
  1. If the constraint comes from a WHERE clause expression that contains + ** a [COLLATE operator], then the name of the collation specified by + ** that COLLATE operator is returned. + **

  2. If there is no COLLATE operator, but the column that is the subject + ** of the constraint specifies an alternative collating sequence via + ** a [COLLATE clause] on the column definition within the CREATE TABLE + ** statement that was passed into [sqlite3_declare_vtab()], then the + ** name of that alternative collating sequence is returned. + **

  3. Otherwise, "BINARY" is returned. + **

+ */ + SQLITE_API SQLITE_EXPERIMENTAL const char* sqlite3_vtab_collation(sqlite3_index_info*, int); + + /* + ** CAPI3REF: Determine if a virtual table query is DISTINCT + ** METHOD: sqlite3_index_info + ** + ** This API may only be used from within an [xBestIndex|xBestIndex method] + ** of a [virtual table] implementation. The result of calling this + ** interface from outside of xBestIndex() is undefined and probably harmful. + ** + ** ^The sqlite3_vtab_distinct() interface returns an integer that is + ** either 0, 1, or 2. The integer returned by sqlite3_vtab_distinct() + ** gives the virtual table additional information about how the query + ** planner wants the output to be ordered. As long as the virtual table + ** can meet the ordering requirements of the query planner, it may set + ** the "orderByConsumed" flag. + ** + **
  1. + ** ^If the sqlite3_vtab_distinct() interface returns 0, that means + ** that the query planner needs the virtual table to return all rows in the + ** sort order defined by the "nOrderBy" and "aOrderBy" fields of the + ** [sqlite3_index_info] object. This is the default expectation. If the + ** virtual table outputs all rows in sorted order, then it is always safe for + ** the xBestIndex method to set the "orderByConsumed" flag, regardless of + ** the return value from sqlite3_vtab_distinct(). + **

  2. + ** ^(If the sqlite3_vtab_distinct() interface returns 1, that means + ** that the query planner does not need the rows to be returned in sorted order + ** as long as all rows with the same values in all columns identified by the + ** "aOrderBy" field are adjacent.)^ This mode is used when the query planner + ** is doing a GROUP BY. + **

  3. + ** ^(If the sqlite3_vtab_distinct() interface returns 2, that means + ** that the query planner does not need the rows returned in any particular + ** order, as long as rows with the same values in all "aOrderBy" columns + ** are adjacent.)^ ^(Furthermore, only a single row for each particular + ** combination of values in the columns identified by the "aOrderBy" field + ** needs to be returned.)^ ^It is always ok for two or more rows with the same + ** values in all "aOrderBy" columns to be returned, as long as all such rows + ** are adjacent. ^The virtual table may, if it chooses, omit extra rows + ** that have the same value for all columns identified by "aOrderBy". + ** ^However omitting the extra rows is optional. + ** This mode is used for a DISTINCT query. + **

+ ** + ** ^For the purposes of comparing virtual table output values to see if the + ** values are same value for sorting purposes, two NULL values are considered + ** to be the same. In other words, the comparison operator is "IS" + ** (or "IS NOT DISTINCT FROM") and not "==". + ** + ** If a virtual table implementation is unable to meet the requirements + ** specified above, then it must not set the "orderByConsumed" flag in the + ** [sqlite3_index_info] object or an incorrect answer may result. + ** + ** ^A virtual table implementation is always free to return rows in any order + ** it wants, as long as the "orderByConsumed" flag is not set. ^When the + ** the "orderByConsumed" flag is unset, the query planner will add extra + ** [bytecode] to ensure that the final results returned by the SQL query are + ** ordered correctly. The use of the "orderByConsumed" flag and the + ** sqlite3_vtab_distinct() interface is merely an optimization. ^Careful + ** use of the sqlite3_vtab_distinct() interface and the "orderByConsumed" + ** flag might help queries against a virtual table to run faster. Being + ** overly aggressive and setting the "orderByConsumed" flag when it is not + ** valid to do so, on the other hand, might cause SQLite to return incorrect + ** results. + */ + SQLITE_API int sqlite3_vtab_distinct(sqlite3_index_info*); + + /* + ** CAPI3REF: Identify and handle IN constraints in xBestIndex + ** + ** This interface may only be used from within an + ** [xBestIndex|xBestIndex() method] of a [virtual table] implementation. + ** The result of invoking this interface from any other context is + ** undefined and probably harmful. + ** + ** ^(A constraint on a virtual table of the form + ** "[IN operator|column IN (...)]" is + ** communicated to the xBestIndex method as a + ** [SQLITE_INDEX_CONSTRAINT_EQ] constraint.)^ If xBestIndex wants to use + ** this constraint, it must set the corresponding + ** aConstraintUsage[].argvIndex to a postive integer. ^(Then, under + ** the usual mode of handling IN operators, SQLite generates [bytecode] + ** that invokes the [xFilter|xFilter() method] once for each value + ** on the right-hand side of the IN operator.)^ Thus the virtual table + ** only sees a single value from the right-hand side of the IN operator + ** at a time. + ** + ** In some cases, however, it would be advantageous for the virtual + ** table to see all values on the right-hand of the IN operator all at + ** once. The sqlite3_vtab_in() interfaces facilitates this in two ways: + ** + **
    + **
  1. + ** ^A call to sqlite3_vtab_in(P,N,-1) will return true (non-zero) + ** if and only if the [sqlite3_index_info|P->aConstraint][N] constraint + ** is an [IN operator] that can be processed all at once. ^In other words, + ** sqlite3_vtab_in() with -1 in the third argument is a mechanism + ** by which the virtual table can ask SQLite if all-at-once processing + ** of the IN operator is even possible. + ** + **

  2. + ** ^A call to sqlite3_vtab_in(P,N,F) with F==1 or F==0 indicates + ** to SQLite that the virtual table does or does not want to process + ** the IN operator all-at-once, respectively. ^Thus when the third + ** parameter (F) is non-negative, this interface is the mechanism by + ** which the virtual table tells SQLite how it wants to process the + ** IN operator. + **

+ ** + ** ^The sqlite3_vtab_in(P,N,F) interface can be invoked multiple times + ** within the same xBestIndex method call. ^For any given P,N pair, + ** the return value from sqlite3_vtab_in(P,N,F) will always be the same + ** within the same xBestIndex call. ^If the interface returns true + ** (non-zero), that means that the constraint is an IN operator + ** that can be processed all-at-once. ^If the constraint is not an IN + ** operator or cannot be processed all-at-once, then the interface returns + ** false. + ** + ** ^(All-at-once processing of the IN operator is selected if both of the + ** following conditions are met: + ** + **
    + **
  1. The P->aConstraintUsage[N].argvIndex value is set to a positive + ** integer. This is how the virtual table tells SQLite that it wants to + ** use the N-th constraint. + ** + **

  2. The last call to sqlite3_vtab_in(P,N,F) for which F was + ** non-negative had F>=1. + **

)^ + ** + ** ^If either or both of the conditions above are false, then SQLite uses + ** the traditional one-at-a-time processing strategy for the IN constraint. + ** ^If both conditions are true, then the argvIndex-th parameter to the + ** xFilter method will be an [sqlite3_value] that appears to be NULL, + ** but which can be passed to [sqlite3_vtab_in_first()] and + ** [sqlite3_vtab_in_next()] to find all values on the right-hand side + ** of the IN constraint. + */ + SQLITE_API int sqlite3_vtab_in(sqlite3_index_info*, int iCons, int bHandle); + + /* + ** CAPI3REF: Find all elements on the right-hand side of an IN constraint. + ** + ** These interfaces are only useful from within the + ** [xFilter|xFilter() method] of a [virtual table] implementation. + ** The result of invoking these interfaces from any other context + ** is undefined and probably harmful. + ** + ** The X parameter in a call to sqlite3_vtab_in_first(X,P) or + ** sqlite3_vtab_in_next(X,P) must be one of the parameters to the + ** xFilter method which invokes these routines, and specifically + ** a parameter that was previously selected for all-at-once IN constraint + ** processing use the [sqlite3_vtab_in()] interface in the + ** [xBestIndex|xBestIndex method]. ^(If the X parameter is not + ** an xFilter argument that was selected for all-at-once IN constraint + ** processing, then these routines return [SQLITE_MISUSE])^ or perhaps + ** exhibit some other undefined or harmful behavior. + ** + ** ^(Use these routines to access all values on the right-hand side + ** of the IN constraint using code like the following: + ** + **
+    **    for(rc=sqlite3_vtab_in_first(pList, &pVal);
+    **        rc==SQLITE_OK && pVal
+    **        rc=sqlite3_vtab_in_next(pList, &pVal)
+    **    ){
+    **      // do something with pVal
+    **    }
+    **    if( rc!=SQLITE_OK ){
+    **      // an error has occurred
+    **    }
+    ** 
)^ + ** + ** ^On success, the sqlite3_vtab_in_first(X,P) and sqlite3_vtab_in_next(X,P) + ** routines return SQLITE_OK and set *P to point to the first or next value + ** on the RHS of the IN constraint. ^If there are no more values on the + ** right hand side of the IN constraint, then *P is set to NULL and these + ** routines return [SQLITE_DONE]. ^The return value might be + ** some other value, such as SQLITE_NOMEM, in the event of a malfunction. + ** + ** The *ppOut values returned by these routines are only valid until the + ** next call to either of these routines or until the end of the xFilter + ** method from which these routines were called. If the virtual table + ** implementation needs to retain the *ppOut values for longer, it must make + ** copies. The *ppOut values are [protected sqlite3_value|protected]. + */ + SQLITE_API int sqlite3_vtab_in_first(sqlite3_value* pVal, sqlite3_value** ppOut); + SQLITE_API int sqlite3_vtab_in_next(sqlite3_value* pVal, sqlite3_value** ppOut); + + /* + ** CAPI3REF: Constraint values in xBestIndex() + ** METHOD: sqlite3_index_info + ** + ** This API may only be used from within the [xBestIndex|xBestIndex method] + ** of a [virtual table] implementation. The result of calling this interface + ** from outside of an xBestIndex method are undefined and probably harmful. + ** + ** ^When the sqlite3_vtab_rhs_value(P,J,V) interface is invoked from within + ** the [xBestIndex] method of a [virtual table] implementation, with P being + ** a copy of the [sqlite3_index_info] object pointer passed into xBestIndex and + ** J being a 0-based index into P->aConstraint[], then this routine + ** attempts to set *V to the value of the right-hand operand of + ** that constraint if the right-hand operand is known. ^If the + ** right-hand operand is not known, then *V is set to a NULL pointer. + ** ^The sqlite3_vtab_rhs_value(P,J,V) interface returns SQLITE_OK if + ** and only if *V is set to a value. ^The sqlite3_vtab_rhs_value(P,J,V) + ** inteface returns SQLITE_NOTFOUND if the right-hand side of the J-th + ** constraint is not available. ^The sqlite3_vtab_rhs_value() interface + ** can return an result code other than SQLITE_OK or SQLITE_NOTFOUND if + ** something goes wrong. + ** + ** The sqlite3_vtab_rhs_value() interface is usually only successful if + ** the right-hand operand of a constraint is a literal value in the original + ** SQL statement. If the right-hand operand is an expression or a reference + ** to some other column or a [host parameter], then sqlite3_vtab_rhs_value() + ** will probably return [SQLITE_NOTFOUND]. + ** + ** ^(Some constraints, such as [SQLITE_INDEX_CONSTRAINT_ISNULL] and + ** [SQLITE_INDEX_CONSTRAINT_ISNOTNULL], have no right-hand operand. For such + ** constraints, sqlite3_vtab_rhs_value() always returns SQLITE_NOTFOUND.)^ + ** + ** ^The [sqlite3_value] object returned in *V is a protected sqlite3_value + ** and remains valid for the duration of the xBestIndex method call. + ** ^When xBestIndex returns, the sqlite3_value object returned by + ** sqlite3_vtab_rhs_value() is automatically deallocated. + ** + ** The "_rhs_" in the name of this routine is an appreviation for + ** "Right-Hand Side". + */ + SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value** ppVal); /* ** CAPI3REF: Conflict resolution modes @@ -9786,9 +9713,9 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value ** */ #define SQLITE_ROLLBACK 1 /* #define SQLITE_IGNORE 2 // Also used by sqlite3_authorizer() callback */ -#define SQLITE_FAIL 3 +#define SQLITE_FAIL 3 /* #define SQLITE_ABORT 4 // Also an error code */ -#define SQLITE_REPLACE 5 +#define SQLITE_REPLACE 5 /* ** CAPI3REF: Prepared Statement Scan Status Opcodes @@ -9837,94 +9764,93 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value ** ** of an [EXPLAIN QUERY PLAN] query. ** */ -#define SQLITE_SCANSTAT_NLOOP 0 -#define SQLITE_SCANSTAT_NVISIT 1 -#define SQLITE_SCANSTAT_EST 2 -#define SQLITE_SCANSTAT_NAME 3 -#define SQLITE_SCANSTAT_EXPLAIN 4 +#define SQLITE_SCANSTAT_NLOOP 0 +#define SQLITE_SCANSTAT_NVISIT 1 +#define SQLITE_SCANSTAT_EST 2 +#define SQLITE_SCANSTAT_NAME 3 +#define SQLITE_SCANSTAT_EXPLAIN 4 #define SQLITE_SCANSTAT_SELECTID 5 -/* -** CAPI3REF: Prepared Statement Scan Status -** METHOD: sqlite3_stmt -** -** This interface returns information about the predicted and measured -** performance for pStmt. Advanced applications can use this -** interface to compare the predicted and the measured performance and -** issue warnings and/or rerun [ANALYZE] if discrepancies are found. -** -** Since this interface is expected to be rarely used, it is only -** available if SQLite is compiled using the [SQLITE_ENABLE_STMT_SCANSTATUS] -** compile-time option. -** -** The "iScanStatusOp" parameter determines which status information to return. -** The "iScanStatusOp" must be one of the [scanstatus options] or the behavior -** of this interface is undefined. -** ^The requested measurement is written into a variable pointed to by -** the "pOut" parameter. -** Parameter "idx" identifies the specific loop to retrieve statistics for. -** Loops are numbered starting from zero. ^If idx is out of range - less than -** zero or greater than or equal to the total number of loops used to implement -** the statement - a non-zero value is returned and the variable that pOut -** points to is unchanged. -** -** ^Statistics might not be available for all loops in all statements. ^In cases -** where there exist loops with no available statistics, this function behaves -** as if the loop did not exist - it returns non-zero and leave the variable -** that pOut points to unchanged. -** -** See also: [sqlite3_stmt_scanstatus_reset()] -*/ -SQLITE_API int sqlite3_stmt_scanstatus( - sqlite3_stmt *pStmt, /* Prepared statement for which info desired */ - int idx, /* Index of loop to report on */ - int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */ - void *pOut /* Result written here */ -); - -/* -** CAPI3REF: Zero Scan-Status Counters -** METHOD: sqlite3_stmt -** -** ^Zero all [sqlite3_stmt_scanstatus()] related event counters. -** -** This API is only available if the library is built with pre-processor -** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined. -*/ -SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*); - -/* -** CAPI3REF: Flush caches to disk mid-transaction -** METHOD: sqlite3 -** -** ^If a write-transaction is open on [database connection] D when the -** [sqlite3_db_cacheflush(D)] interface invoked, any dirty -** pages in the pager-cache that are not currently in use are written out -** to disk. A dirty page may be in use if a database cursor created by an -** active SQL statement is reading from it, or if it is page 1 of a database -** file (page 1 is always "in use"). ^The [sqlite3_db_cacheflush(D)] -** interface flushes caches for all schemas - "main", "temp", and -** any [attached] databases. -** -** ^If this function needs to obtain extra database locks before dirty pages -** can be flushed to disk, it does so. ^If those locks cannot be obtained -** immediately and there is a busy-handler callback configured, it is invoked -** in the usual manner. ^If the required lock still cannot be obtained, then -** the database is skipped and an attempt made to flush any dirty pages -** belonging to the next (if any) database. ^If any databases are skipped -** because locks cannot be obtained, but no other error occurs, this -** function returns SQLITE_BUSY. -** -** ^If any other error occurs while flushing dirty pages to disk (for -** example an IO error or out-of-memory condition), then processing is -** abandoned and an SQLite [error code] is returned to the caller immediately. -** -** ^Otherwise, if no error occurs, [sqlite3_db_cacheflush()] returns SQLITE_OK. -** -** ^This function does not set the database handle error code or message -** returned by the [sqlite3_errcode()] and [sqlite3_errmsg()] functions. -*/ -SQLITE_API int sqlite3_db_cacheflush(sqlite3*); + /* + ** CAPI3REF: Prepared Statement Scan Status + ** METHOD: sqlite3_stmt + ** + ** This interface returns information about the predicted and measured + ** performance for pStmt. Advanced applications can use this + ** interface to compare the predicted and the measured performance and + ** issue warnings and/or rerun [ANALYZE] if discrepancies are found. + ** + ** Since this interface is expected to be rarely used, it is only + ** available if SQLite is compiled using the [SQLITE_ENABLE_STMT_SCANSTATUS] + ** compile-time option. + ** + ** The "iScanStatusOp" parameter determines which status information to return. + ** The "iScanStatusOp" must be one of the [scanstatus options] or the behavior + ** of this interface is undefined. + ** ^The requested measurement is written into a variable pointed to by + ** the "pOut" parameter. + ** Parameter "idx" identifies the specific loop to retrieve statistics for. + ** Loops are numbered starting from zero. ^If idx is out of range - less than + ** zero or greater than or equal to the total number of loops used to implement + ** the statement - a non-zero value is returned and the variable that pOut + ** points to is unchanged. + ** + ** ^Statistics might not be available for all loops in all statements. ^In cases + ** where there exist loops with no available statistics, this function behaves + ** as if the loop did not exist - it returns non-zero and leave the variable + ** that pOut points to unchanged. + ** + ** See also: [sqlite3_stmt_scanstatus_reset()] + */ + SQLITE_API int sqlite3_stmt_scanstatus(sqlite3_stmt* pStmt, /* Prepared statement for which info desired */ + int idx, /* Index of loop to report on */ + int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */ + void* pOut /* Result written here */ + ); + + /* + ** CAPI3REF: Zero Scan-Status Counters + ** METHOD: sqlite3_stmt + ** + ** ^Zero all [sqlite3_stmt_scanstatus()] related event counters. + ** + ** This API is only available if the library is built with pre-processor + ** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined. + */ + SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*); + + /* + ** CAPI3REF: Flush caches to disk mid-transaction + ** METHOD: sqlite3 + ** + ** ^If a write-transaction is open on [database connection] D when the + ** [sqlite3_db_cacheflush(D)] interface invoked, any dirty + ** pages in the pager-cache that are not currently in use are written out + ** to disk. A dirty page may be in use if a database cursor created by an + ** active SQL statement is reading from it, or if it is page 1 of a database + ** file (page 1 is always "in use"). ^The [sqlite3_db_cacheflush(D)] + ** interface flushes caches for all schemas - "main", "temp", and + ** any [attached] databases. + ** + ** ^If this function needs to obtain extra database locks before dirty pages + ** can be flushed to disk, it does so. ^If those locks cannot be obtained + ** immediately and there is a busy-handler callback configured, it is invoked + ** in the usual manner. ^If the required lock still cannot be obtained, then + ** the database is skipped and an attempt made to flush any dirty pages + ** belonging to the next (if any) database. ^If any databases are skipped + ** because locks cannot be obtained, but no other error occurs, this + ** function returns SQLITE_BUSY. + ** + ** ^If any other error occurs while flushing dirty pages to disk (for + ** example an IO error or out-of-memory condition), then processing is + ** abandoned and an SQLite [error code] is returned to the caller immediately. + ** + ** ^Otherwise, if no error occurs, [sqlite3_db_cacheflush()] returns SQLITE_OK. + ** + ** ^This function does not set the database handle error code or message + ** returned by the [sqlite3_errcode()] and [sqlite3_errmsg()] functions. + */ + SQLITE_API int sqlite3_db_cacheflush(sqlite3*); /* ** CAPI3REF: The pre-update hook. @@ -9999,1731 +9925,1689 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*); ** undefined. This must only be used within SQLITE_INSERT and SQLITE_UPDATE ** preupdate callbacks; if it is used by an SQLITE_DELETE callback then the ** behavior is undefined. The [sqlite3_value] that P points to -** will be destroyed when the preupdate callback returns. -** -** ^The [sqlite3_preupdate_depth(D)] interface returns 0 if the preupdate -** callback was invoked as a result of a direct insert, update, or delete -** operation; or 1 for inserts, updates, or deletes invoked by top-level -** triggers; or 2 for changes resulting from triggers called by top-level -** triggers; and so forth. -** -** When the [sqlite3_blob_write()] API is used to update a blob column, -** the pre-update hook is invoked with SQLITE_DELETE. This is because the -** in this case the new values are not available. In this case, when a -** callback made with op==SQLITE_DELETE is actuall a write using the -** sqlite3_blob_write() API, the [sqlite3_preupdate_blobwrite()] returns -** the index of the column being written. In other cases, where the -** pre-update hook is being invoked for some other reason, including a -** regular DELETE, sqlite3_preupdate_blobwrite() returns -1. -** -** See also: [sqlite3_update_hook()] -*/ -#if defined(SQLITE_ENABLE_PREUPDATE_HOOK) -SQLITE_API void *sqlite3_preupdate_hook( - sqlite3 *db, - void(*xPreUpdate)( - void *pCtx, /* Copy of third arg to preupdate_hook() */ - sqlite3 *db, /* Database handle */ - int op, /* SQLITE_UPDATE, DELETE or INSERT */ - char const *zDb, /* Database name */ - char const *zName, /* Table name */ - sqlite3_int64 iKey1, /* Rowid of row about to be deleted/updated */ - sqlite3_int64 iKey2 /* New rowid value (for a rowid UPDATE) */ - ), - void* -); -SQLITE_API int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **); -SQLITE_API int sqlite3_preupdate_count(sqlite3 *); -SQLITE_API int sqlite3_preupdate_depth(sqlite3 *); -SQLITE_API int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **); -SQLITE_API int sqlite3_preupdate_blobwrite(sqlite3 *); -#endif - -/* -** CAPI3REF: Low-level system error code -** METHOD: sqlite3 -** -** ^Attempt to return the underlying operating system error code or error -** number that caused the most recent I/O error or failure to open a file. -** The return value is OS-dependent. For example, on unix systems, after -** [sqlite3_open_v2()] returns [SQLITE_CANTOPEN], this interface could be -** called to get back the underlying "errno" that caused the problem, such -** as ENOSPC, EAUTH, EISDIR, and so forth. -*/ -SQLITE_API int sqlite3_system_errno(sqlite3*); - -/* -** CAPI3REF: Database Snapshot -** KEYWORDS: {snapshot} {sqlite3_snapshot} -** -** An instance of the snapshot object records the state of a [WAL mode] -** database for some specific point in history. -** -** In [WAL mode], multiple [database connections] that are open on the -** same database file can each be reading a different historical version -** of the database file. When a [database connection] begins a read -** transaction, that connection sees an unchanging copy of the database -** as it existed for the point in time when the transaction first started. -** Subsequent changes to the database from other connections are not seen -** by the reader until a new read transaction is started. -** -** The sqlite3_snapshot object records state information about an historical -** version of the database file so that it is possible to later open a new read -** transaction that sees that historical version of the database rather than -** the most recent version. -*/ -typedef struct sqlite3_snapshot { - unsigned char hidden[48]; -} sqlite3_snapshot; - -/* -** CAPI3REF: Record A Database Snapshot -** CONSTRUCTOR: sqlite3_snapshot -** -** ^The [sqlite3_snapshot_get(D,S,P)] interface attempts to make a -** new [sqlite3_snapshot] object that records the current state of -** schema S in database connection D. ^On success, the -** [sqlite3_snapshot_get(D,S,P)] interface writes a pointer to the newly -** created [sqlite3_snapshot] object into *P and returns SQLITE_OK. -** If there is not already a read-transaction open on schema S when -** this function is called, one is opened automatically. -** -** The following must be true for this function to succeed. If any of -** the following statements are false when sqlite3_snapshot_get() is -** called, SQLITE_ERROR is returned. The final value of *P is undefined -** in this case. -** -**
    -**
  • The database handle must not be in [autocommit mode]. -** -**
  • Schema S of [database connection] D must be a [WAL mode] database. -** -**
  • There must not be a write transaction open on schema S of database -** connection D. -** -**
  • One or more transactions must have been written to the current wal -** file since it was created on disk (by any connection). This means -** that a snapshot cannot be taken on a wal mode database with no wal -** file immediately after it is first opened. At least one transaction -** must be written to it first. -**
-** -** This function may also return SQLITE_NOMEM. If it is called with the -** database handle in autocommit mode but fails for some other reason, -** whether or not a read transaction is opened on schema S is undefined. -** -** The [sqlite3_snapshot] object returned from a successful call to -** [sqlite3_snapshot_get()] must be freed using [sqlite3_snapshot_free()] -** to avoid a memory leak. -** -** The [sqlite3_snapshot_get()] interface is only available when the -** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used. -*/ -SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get( - sqlite3 *db, - const char *zSchema, - sqlite3_snapshot **ppSnapshot -); - -/* -** CAPI3REF: Start a read transaction on an historical snapshot -** METHOD: sqlite3_snapshot -** -** ^The [sqlite3_snapshot_open(D,S,P)] interface either starts a new read -** transaction or upgrades an existing one for schema S of -** [database connection] D such that the read transaction refers to -** historical [snapshot] P, rather than the most recent change to the -** database. ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK -** on success or an appropriate [error code] if it fails. -** -** ^In order to succeed, the database connection must not be in -** [autocommit mode] when [sqlite3_snapshot_open(D,S,P)] is called. If there -** is already a read transaction open on schema S, then the database handle -** must have no active statements (SELECT statements that have been passed -** to sqlite3_step() but not sqlite3_reset() or sqlite3_finalize()). -** SQLITE_ERROR is returned if either of these conditions is violated, or -** if schema S does not exist, or if the snapshot object is invalid. -** -** ^A call to sqlite3_snapshot_open() will fail to open if the specified -** snapshot has been overwritten by a [checkpoint]. In this case -** SQLITE_ERROR_SNAPSHOT is returned. -** -** If there is already a read transaction open when this function is -** invoked, then the same read transaction remains open (on the same -** database snapshot) if SQLITE_ERROR, SQLITE_BUSY or SQLITE_ERROR_SNAPSHOT -** is returned. If another error code - for example SQLITE_PROTOCOL or an -** SQLITE_IOERR error code - is returned, then the final state of the -** read transaction is undefined. If SQLITE_OK is returned, then the -** read transaction is now open on database snapshot P. -** -** ^(A call to [sqlite3_snapshot_open(D,S,P)] will fail if the -** database connection D does not know that the database file for -** schema S is in [WAL mode]. A database connection might not know -** that the database file is in [WAL mode] if there has been no prior -** I/O on that database connection, or if the database entered [WAL mode] -** after the most recent I/O on the database connection.)^ -** (Hint: Run "[PRAGMA application_id]" against a newly opened -** database connection in order to make it ready to use snapshots.) -** -** The [sqlite3_snapshot_open()] interface is only available when the -** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used. -*/ -SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open( - sqlite3 *db, - const char *zSchema, - sqlite3_snapshot *pSnapshot -); - -/* -** CAPI3REF: Destroy a snapshot -** DESTRUCTOR: sqlite3_snapshot -** -** ^The [sqlite3_snapshot_free(P)] interface destroys [sqlite3_snapshot] P. -** The application must eventually free every [sqlite3_snapshot] object -** using this routine to avoid a memory leak. -** -** The [sqlite3_snapshot_free()] interface is only available when the -** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used. -*/ -SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*); - -/* -** CAPI3REF: Compare the ages of two snapshot handles. -** METHOD: sqlite3_snapshot -** -** The sqlite3_snapshot_cmp(P1, P2) interface is used to compare the ages -** of two valid snapshot handles. -** -** If the two snapshot handles are not associated with the same database -** file, the result of the comparison is undefined. -** -** Additionally, the result of the comparison is only valid if both of the -** snapshot handles were obtained by calling sqlite3_snapshot_get() since the -** last time the wal file was deleted. The wal file is deleted when the -** database is changed back to rollback mode or when the number of database -** clients drops to zero. If either snapshot handle was obtained before the -** wal file was last deleted, the value returned by this function -** is undefined. -** -** Otherwise, this API returns a negative value if P1 refers to an older -** snapshot than P2, zero if the two handles refer to the same database -** snapshot, and a positive value if P1 is a newer snapshot than P2. -** -** This interface is only available if SQLite is compiled with the -** [SQLITE_ENABLE_SNAPSHOT] option. -*/ -SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp( - sqlite3_snapshot *p1, - sqlite3_snapshot *p2 -); - -/* -** CAPI3REF: Recover snapshots from a wal file -** METHOD: sqlite3_snapshot -** -** If a [WAL file] remains on disk after all database connections close -** (either through the use of the [SQLITE_FCNTL_PERSIST_WAL] [file control] -** or because the last process to have the database opened exited without -** calling [sqlite3_close()]) and a new connection is subsequently opened -** on that database and [WAL file], the [sqlite3_snapshot_open()] interface -** will only be able to open the last transaction added to the WAL file -** even though the WAL file contains other valid transactions. -** -** This function attempts to scan the WAL file associated with database zDb -** of database handle db and make all valid snapshots available to -** sqlite3_snapshot_open(). It is an error if there is already a read -** transaction open on the database, or if the database is not a WAL mode -** database. -** -** SQLITE_OK is returned if successful, or an SQLite error code otherwise. -** -** This interface is only available if SQLite is compiled with the -** [SQLITE_ENABLE_SNAPSHOT] option. -*/ -SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb); - -/* -** CAPI3REF: Serialize a database -** -** The sqlite3_serialize(D,S,P,F) interface returns a pointer to memory -** that is a serialization of the S database on [database connection] D. -** If P is not a NULL pointer, then the size of the database in bytes -** is written into *P. -** -** For an ordinary on-disk database file, the serialization is just a -** copy of the disk file. For an in-memory database or a "TEMP" database, -** the serialization is the same sequence of bytes which would be written -** to disk if that database where backed up to disk. -** -** The usual case is that sqlite3_serialize() copies the serialization of -** the database into memory obtained from [sqlite3_malloc64()] and returns -** a pointer to that memory. The caller is responsible for freeing the -** returned value to avoid a memory leak. However, if the F argument -** contains the SQLITE_SERIALIZE_NOCOPY bit, then no memory allocations -** are made, and the sqlite3_serialize() function will return a pointer -** to the contiguous memory representation of the database that SQLite -** is currently using for that database, or NULL if the no such contiguous -** memory representation of the database exists. A contiguous memory -** representation of the database will usually only exist if there has -** been a prior call to [sqlite3_deserialize(D,S,...)] with the same -** values of D and S. -** The size of the database is written into *P even if the -** SQLITE_SERIALIZE_NOCOPY bit is set but no contiguous copy -** of the database exists. -** -** A call to sqlite3_serialize(D,S,P,F) might return NULL even if the -** SQLITE_SERIALIZE_NOCOPY bit is omitted from argument F if a memory -** allocation error occurs. -** -** This interface is omitted if SQLite is compiled with the -** [SQLITE_OMIT_DESERIALIZE] option. -*/ -SQLITE_API unsigned char *sqlite3_serialize( - sqlite3 *db, /* The database connection */ - const char *zSchema, /* Which DB to serialize. ex: "main", "temp", ... */ - sqlite3_int64 *piSize, /* Write size of the DB here, if not NULL */ - unsigned int mFlags /* Zero or more SQLITE_SERIALIZE_* flags */ -); - -/* -** CAPI3REF: Flags for sqlite3_serialize -** -** Zero or more of the following constants can be OR-ed together for -** the F argument to [sqlite3_serialize(D,S,P,F)]. -** -** SQLITE_SERIALIZE_NOCOPY means that [sqlite3_serialize()] will return -** a pointer to contiguous in-memory database that it is currently using, -** without making a copy of the database. If SQLite is not currently using -** a contiguous in-memory database, then this option causes -** [sqlite3_serialize()] to return a NULL pointer. SQLite will only be -** using a contiguous in-memory database if it has been initialized by a -** prior call to [sqlite3_deserialize()]. -*/ -#define SQLITE_SERIALIZE_NOCOPY 0x001 /* Do no memory allocations */ - -/* -** CAPI3REF: Deserialize a database -** -** The sqlite3_deserialize(D,S,P,N,M,F) interface causes the -** [database connection] D to disconnect from database S and then -** reopen S as an in-memory database based on the serialization contained -** in P. The serialized database P is N bytes in size. M is the size of -** the buffer P, which might be larger than N. If M is larger than N, and -** the SQLITE_DESERIALIZE_READONLY bit is not set in F, then SQLite is -** permitted to add content to the in-memory database as long as the total -** size does not exceed M bytes. -** -** If the SQLITE_DESERIALIZE_FREEONCLOSE bit is set in F, then SQLite will -** invoke sqlite3_free() on the serialization buffer when the database -** connection closes. If the SQLITE_DESERIALIZE_RESIZEABLE bit is set, then -** SQLite will try to increase the buffer size using sqlite3_realloc64() -** if writes on the database cause it to grow larger than M bytes. -** -** The sqlite3_deserialize() interface will fail with SQLITE_BUSY if the -** database is currently in a read transaction or is involved in a backup -** operation. -** -** It is not possible to deserialized into the TEMP database. If the -** S argument to sqlite3_deserialize(D,S,P,N,M,F) is "temp" then the -** function returns SQLITE_ERROR. -** -** If sqlite3_deserialize(D,S,P,N,M,F) fails for any reason and if the -** SQLITE_DESERIALIZE_FREEONCLOSE bit is set in argument F, then -** [sqlite3_free()] is invoked on argument P prior to returning. -** -** This interface is omitted if SQLite is compiled with the -** [SQLITE_OMIT_DESERIALIZE] option. -*/ -SQLITE_API int sqlite3_deserialize( - sqlite3 *db, /* The database connection */ - const char *zSchema, /* Which DB to reopen with the deserialization */ - unsigned char *pData, /* The serialized database content */ - sqlite3_int64 szDb, /* Number bytes in the deserialization */ - sqlite3_int64 szBuf, /* Total size of buffer pData[] */ - unsigned mFlags /* Zero or more SQLITE_DESERIALIZE_* flags */ -); - -/* -** CAPI3REF: Flags for sqlite3_deserialize() -** -** The following are allowed values for 6th argument (the F argument) to -** the [sqlite3_deserialize(D,S,P,N,M,F)] interface. -** -** The SQLITE_DESERIALIZE_FREEONCLOSE means that the database serialization -** in the P argument is held in memory obtained from [sqlite3_malloc64()] -** and that SQLite should take ownership of this memory and automatically -** free it when it has finished using it. Without this flag, the caller -** is responsible for freeing any dynamically allocated memory. -** -** The SQLITE_DESERIALIZE_RESIZEABLE flag means that SQLite is allowed to -** grow the size of the database using calls to [sqlite3_realloc64()]. This -** flag should only be used if SQLITE_DESERIALIZE_FREEONCLOSE is also used. -** Without this flag, the deserialized database cannot increase in size beyond -** the number of bytes specified by the M parameter. -** -** The SQLITE_DESERIALIZE_READONLY flag means that the deserialized database -** should be treated as read-only. -*/ -#define SQLITE_DESERIALIZE_FREEONCLOSE 1 /* Call sqlite3_free() on close */ -#define SQLITE_DESERIALIZE_RESIZEABLE 2 /* Resize using sqlite3_realloc64() */ -#define SQLITE_DESERIALIZE_READONLY 4 /* Database is read-only */ - -/* -** Undo the hack that converts floating point types to integer for -** builds on processors without floating point support. -*/ -#ifdef SQLITE_OMIT_FLOATING_POINT -# undef double -#endif - -#ifdef __cplusplus -} /* End of the 'extern "C"' block */ -#endif -#endif /* SQLITE3_H */ - -/******** Begin file sqlite3rtree.h *********/ -/* -** 2010 August 30 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -*/ - -#ifndef _SQLITE3RTREE_H_ -#define _SQLITE3RTREE_H_ - - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct sqlite3_rtree_geometry sqlite3_rtree_geometry; -typedef struct sqlite3_rtree_query_info sqlite3_rtree_query_info; - -/* The double-precision datatype used by RTree depends on the -** SQLITE_RTREE_INT_ONLY compile-time option. -*/ -#ifdef SQLITE_RTREE_INT_ONLY - typedef sqlite3_int64 sqlite3_rtree_dbl; -#else - typedef double sqlite3_rtree_dbl; -#endif - -/* -** Register a geometry callback named zGeom that can be used as part of an -** R-Tree geometry query as follows: -** -** SELECT ... FROM WHERE MATCH $zGeom(... params ...) -*/ -SQLITE_API int sqlite3_rtree_geometry_callback( - sqlite3 *db, - const char *zGeom, - int (*xGeom)(sqlite3_rtree_geometry*, int, sqlite3_rtree_dbl*,int*), - void *pContext -); - - -/* -** A pointer to a structure of the following type is passed as the first -** argument to callbacks registered using rtree_geometry_callback(). -*/ -struct sqlite3_rtree_geometry { - void *pContext; /* Copy of pContext passed to s_r_g_c() */ - int nParam; /* Size of array aParam[] */ - sqlite3_rtree_dbl *aParam; /* Parameters passed to SQL geom function */ - void *pUser; /* Callback implementation user data */ - void (*xDelUser)(void *); /* Called by SQLite to clean up pUser */ -}; - -/* -** Register a 2nd-generation geometry callback named zScore that can be -** used as part of an R-Tree geometry query as follows: -** -** SELECT ... FROM WHERE MATCH $zQueryFunc(... params ...) -*/ -SQLITE_API int sqlite3_rtree_query_callback( - sqlite3 *db, - const char *zQueryFunc, - int (*xQueryFunc)(sqlite3_rtree_query_info*), - void *pContext, - void (*xDestructor)(void*) -); - - -/* -** A pointer to a structure of the following type is passed as the -** argument to scored geometry callback registered using -** sqlite3_rtree_query_callback(). -** -** Note that the first 5 fields of this structure are identical to -** sqlite3_rtree_geometry. This structure is a subclass of -** sqlite3_rtree_geometry. -*/ -struct sqlite3_rtree_query_info { - void *pContext; /* pContext from when function registered */ - int nParam; /* Number of function parameters */ - sqlite3_rtree_dbl *aParam; /* value of function parameters */ - void *pUser; /* callback can use this, if desired */ - void (*xDelUser)(void*); /* function to free pUser */ - sqlite3_rtree_dbl *aCoord; /* Coordinates of node or entry to check */ - unsigned int *anQueue; /* Number of pending entries in the queue */ - int nCoord; /* Number of coordinates */ - int iLevel; /* Level of current node or entry */ - int mxLevel; /* The largest iLevel value in the tree */ - sqlite3_int64 iRowid; /* Rowid for current entry */ - sqlite3_rtree_dbl rParentScore; /* Score of parent node */ - int eParentWithin; /* Visibility of parent node */ - int eWithin; /* OUT: Visibility */ - sqlite3_rtree_dbl rScore; /* OUT: Write the score here */ - /* The following fields are only available in 3.8.11 and later */ - sqlite3_value **apSqlParam; /* Original SQL values of parameters */ -}; - -/* -** Allowed values for sqlite3_rtree_query.eWithin and .eParentWithin. -*/ -#define NOT_WITHIN 0 /* Object completely outside of query region */ -#define PARTLY_WITHIN 1 /* Object partially overlaps query region */ -#define FULLY_WITHIN 2 /* Object fully contained within query region */ - - -#ifdef __cplusplus -} /* end of the 'extern "C"' block */ -#endif - -#endif /* ifndef _SQLITE3RTREE_H_ */ - -/******** End of sqlite3rtree.h *********/ -/******** Begin file sqlite3session.h *********/ - -#if !defined(__SQLITESESSION_H_) && defined(SQLITE_ENABLE_SESSION) -#define __SQLITESESSION_H_ 1 - -/* -** Make sure we can call this stuff from C++. -*/ -#ifdef __cplusplus -extern "C" { -#endif - - -/* -** CAPI3REF: Session Object Handle -** -** An instance of this object is a [session] that can be used to -** record changes to a database. -*/ -typedef struct sqlite3_session sqlite3_session; - -/* -** CAPI3REF: Changeset Iterator Handle -** -** An instance of this object acts as a cursor for iterating -** over the elements of a [changeset] or [patchset]. -*/ -typedef struct sqlite3_changeset_iter sqlite3_changeset_iter; - -/* -** CAPI3REF: Create A New Session Object -** CONSTRUCTOR: sqlite3_session -** -** Create a new session object attached to database handle db. If successful, -** a pointer to the new object is written to *ppSession and SQLITE_OK is -** returned. If an error occurs, *ppSession is set to NULL and an SQLite -** error code (e.g. SQLITE_NOMEM) is returned. -** -** It is possible to create multiple session objects attached to a single -** database handle. -** -** Session objects created using this function should be deleted using the -** [sqlite3session_delete()] function before the database handle that they -** are attached to is itself closed. If the database handle is closed before -** the session object is deleted, then the results of calling any session -** module function, including [sqlite3session_delete()] on the session object -** are undefined. -** -** Because the session module uses the [sqlite3_preupdate_hook()] API, it -** is not possible for an application to register a pre-update hook on a -** database handle that has one or more session objects attached. Nor is -** it possible to create a session object attached to a database handle for -** which a pre-update hook is already defined. The results of attempting -** either of these things are undefined. -** -** The session object will be used to create changesets for tables in -** database zDb, where zDb is either "main", or "temp", or the name of an -** attached database. It is not an error if database zDb is not attached -** to the database when the session object is created. -*/ -SQLITE_API int sqlite3session_create( - sqlite3 *db, /* Database handle */ - const char *zDb, /* Name of db (e.g. "main") */ - sqlite3_session **ppSession /* OUT: New session object */ -); - -/* -** CAPI3REF: Delete A Session Object -** DESTRUCTOR: sqlite3_session -** -** Delete a session object previously allocated using -** [sqlite3session_create()]. Once a session object has been deleted, the -** results of attempting to use pSession with any other session module -** function are undefined. -** -** Session objects must be deleted before the database handle to which they -** are attached is closed. Refer to the documentation for -** [sqlite3session_create()] for details. -*/ -SQLITE_API void sqlite3session_delete(sqlite3_session *pSession); - -/* -** CAPIREF: Conigure a Session Object -** METHOD: sqlite3_session -** -** This method is used to configure a session object after it has been -** created. At present the only valid value for the second parameter is -** [SQLITE_SESSION_OBJCONFIG_SIZE]. -** -** Arguments for sqlite3session_object_config() -** -** The following values may passed as the the 4th parameter to -** sqlite3session_object_config(). -** -**
SQLITE_SESSION_OBJCONFIG_SIZE
-** This option is used to set, clear or query the flag that enables -** the [sqlite3session_changeset_size()] API. Because it imposes some -** computational overhead, this API is disabled by default. Argument -** pArg must point to a value of type (int). If the value is initially -** 0, then the sqlite3session_changeset_size() API is disabled. If it -** is greater than 0, then the same API is enabled. Or, if the initial -** value is less than zero, no change is made. In all cases the (int) -** variable is set to 1 if the sqlite3session_changeset_size() API is -** enabled following the current call, or 0 otherwise. -** -** It is an error (SQLITE_MISUSE) to attempt to modify this setting after -** the first table has been attached to the session object. -*/ -SQLITE_API int sqlite3session_object_config(sqlite3_session*, int op, void *pArg); - -/* -*/ -#define SQLITE_SESSION_OBJCONFIG_SIZE 1 - -/* -** CAPI3REF: Enable Or Disable A Session Object -** METHOD: sqlite3_session -** -** Enable or disable the recording of changes by a session object. When -** enabled, a session object records changes made to the database. When -** disabled - it does not. A newly created session object is enabled. -** Refer to the documentation for [sqlite3session_changeset()] for further -** details regarding how enabling and disabling a session object affects -** the eventual changesets. -** -** Passing zero to this function disables the session. Passing a value -** greater than zero enables it. Passing a value less than zero is a -** no-op, and may be used to query the current state of the session. -** -** The return value indicates the final state of the session object: 0 if -** the session is disabled, or 1 if it is enabled. -*/ -SQLITE_API int sqlite3session_enable(sqlite3_session *pSession, int bEnable); - -/* -** CAPI3REF: Set Or Clear the Indirect Change Flag -** METHOD: sqlite3_session -** -** Each change recorded by a session object is marked as either direct or -** indirect. A change is marked as indirect if either: -** -**
    -**
  • The session object "indirect" flag is set when the change is -** made, or -**
  • The change is made by an SQL trigger or foreign key action -** instead of directly as a result of a users SQL statement. -**
-** -** If a single row is affected by more than one operation within a session, -** then the change is considered indirect if all operations meet the criteria -** for an indirect change above, or direct otherwise. -** -** This function is used to set, clear or query the session object indirect -** flag. If the second argument passed to this function is zero, then the -** indirect flag is cleared. If it is greater than zero, the indirect flag -** is set. Passing a value less than zero does not modify the current value -** of the indirect flag, and may be used to query the current state of the -** indirect flag for the specified session object. -** -** The return value indicates the final state of the indirect flag: 0 if -** it is clear, or 1 if it is set. -*/ -SQLITE_API int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect); - -/* -** CAPI3REF: Attach A Table To A Session Object -** METHOD: sqlite3_session -** -** If argument zTab is not NULL, then it is the name of a table to attach -** to the session object passed as the first argument. All subsequent changes -** made to the table while the session object is enabled will be recorded. See -** documentation for [sqlite3session_changeset()] for further details. -** -** Or, if argument zTab is NULL, then changes are recorded for all tables -** in the database. If additional tables are added to the database (by -** executing "CREATE TABLE" statements) after this call is made, changes for -** the new tables are also recorded. -** -** Changes can only be recorded for tables that have a PRIMARY KEY explicitly -** defined as part of their CREATE TABLE statement. It does not matter if the -** PRIMARY KEY is an "INTEGER PRIMARY KEY" (rowid alias) or not. The PRIMARY -** KEY may consist of a single column, or may be a composite key. -** -** It is not an error if the named table does not exist in the database. Nor -** is it an error if the named table does not have a PRIMARY KEY. However, -** no changes will be recorded in either of these scenarios. -** -** Changes are not recorded for individual rows that have NULL values stored -** in one or more of their PRIMARY KEY columns. -** -** SQLITE_OK is returned if the call completes without error. Or, if an error -** occurs, an SQLite error code (e.g. SQLITE_NOMEM) is returned. -** -**

Special sqlite_stat1 Handling

-** -** As of SQLite version 3.22.0, the "sqlite_stat1" table is an exception to -** some of the rules above. In SQLite, the schema of sqlite_stat1 is: -**
-**        CREATE TABLE sqlite_stat1(tbl,idx,stat)
-**  
-** -** Even though sqlite_stat1 does not have a PRIMARY KEY, changes are -** recorded for it as if the PRIMARY KEY is (tbl,idx). Additionally, changes -** are recorded for rows for which (idx IS NULL) is true. However, for such -** rows a zero-length blob (SQL value X'') is stored in the changeset or -** patchset instead of a NULL value. This allows such changesets to be -** manipulated by legacy implementations of sqlite3changeset_invert(), -** concat() and similar. -** -** The sqlite3changeset_apply() function automatically converts the -** zero-length blob back to a NULL value when updating the sqlite_stat1 -** table. However, if the application calls sqlite3changeset_new(), -** sqlite3changeset_old() or sqlite3changeset_conflict on a changeset -** iterator directly (including on a changeset iterator passed to a -** conflict-handler callback) then the X'' value is returned. The application -** must translate X'' to NULL itself if required. -** -** Legacy (older than 3.22.0) versions of the sessions module cannot capture -** changes made to the sqlite_stat1 table. Legacy versions of the -** sqlite3changeset_apply() function silently ignore any modifications to the -** sqlite_stat1 table that are part of a changeset or patchset. -*/ -SQLITE_API int sqlite3session_attach( - sqlite3_session *pSession, /* Session object */ - const char *zTab /* Table name */ -); - -/* -** CAPI3REF: Set a table filter on a Session Object. -** METHOD: sqlite3_session -** -** The second argument (xFilter) is the "filter callback". For changes to rows -** in tables that are not attached to the Session object, the filter is called -** to determine whether changes to the table's rows should be tracked or not. -** If xFilter returns 0, changes are not tracked. Note that once a table is -** attached, xFilter will not be called again. -*/ -SQLITE_API void sqlite3session_table_filter( - sqlite3_session *pSession, /* Session object */ - int(*xFilter)( - void *pCtx, /* Copy of third arg to _filter_table() */ - const char *zTab /* Table name */ - ), - void *pCtx /* First argument passed to xFilter */ -); - -/* -** CAPI3REF: Generate A Changeset From A Session Object -** METHOD: sqlite3_session -** -** Obtain a changeset containing changes to the tables attached to the -** session object passed as the first argument. If successful, -** set *ppChangeset to point to a buffer containing the changeset -** and *pnChangeset to the size of the changeset in bytes before returning -** SQLITE_OK. If an error occurs, set both *ppChangeset and *pnChangeset to -** zero and return an SQLite error code. -** -** A changeset consists of zero or more INSERT, UPDATE and/or DELETE changes, -** each representing a change to a single row of an attached table. An INSERT -** change contains the values of each field of a new database row. A DELETE -** contains the original values of each field of a deleted database row. An -** UPDATE change contains the original values of each field of an updated -** database row along with the updated values for each updated non-primary-key -** column. It is not possible for an UPDATE change to represent a change that -** modifies the values of primary key columns. If such a change is made, it -** is represented in a changeset as a DELETE followed by an INSERT. -** -** Changes are not recorded for rows that have NULL values stored in one or -** more of their PRIMARY KEY columns. If such a row is inserted or deleted, -** no corresponding change is present in the changesets returned by this -** function. If an existing row with one or more NULL values stored in -** PRIMARY KEY columns is updated so that all PRIMARY KEY columns are non-NULL, -** only an INSERT is appears in the changeset. Similarly, if an existing row -** with non-NULL PRIMARY KEY values is updated so that one or more of its -** PRIMARY KEY columns are set to NULL, the resulting changeset contains a -** DELETE change only. -** -** The contents of a changeset may be traversed using an iterator created -** using the [sqlite3changeset_start()] API. A changeset may be applied to -** a database with a compatible schema using the [sqlite3changeset_apply()] -** API. -** -** Within a changeset generated by this function, all changes related to a -** single table are grouped together. In other words, when iterating through -** a changeset or when applying a changeset to a database, all changes related -** to a single table are processed before moving on to the next table. Tables -** are sorted in the same order in which they were attached (or auto-attached) -** to the sqlite3_session object. The order in which the changes related to -** a single table are stored is undefined. -** -** Following a successful call to this function, it is the responsibility of -** the caller to eventually free the buffer that *ppChangeset points to using -** [sqlite3_free()]. -** -**

Changeset Generation

-** -** Once a table has been attached to a session object, the session object -** records the primary key values of all new rows inserted into the table. -** It also records the original primary key and other column values of any -** deleted or updated rows. For each unique primary key value, data is only -** recorded once - the first time a row with said primary key is inserted, -** updated or deleted in the lifetime of the session. -** -** There is one exception to the previous paragraph: when a row is inserted, -** updated or deleted, if one or more of its primary key columns contain a -** NULL value, no record of the change is made. -** -** The session object therefore accumulates two types of records - those -** that consist of primary key values only (created when the user inserts -** a new record) and those that consist of the primary key values and the -** original values of other table columns (created when the users deletes -** or updates a record). -** -** When this function is called, the requested changeset is created using -** both the accumulated records and the current contents of the database -** file. Specifically: -** -**
    -**
  • For each record generated by an insert, the database is queried -** for a row with a matching primary key. If one is found, an INSERT -** change is added to the changeset. If no such row is found, no change -** is added to the changeset. -** -**
  • For each record generated by an update or delete, the database is -** queried for a row with a matching primary key. If such a row is -** found and one or more of the non-primary key fields have been -** modified from their original values, an UPDATE change is added to -** the changeset. Or, if no such row is found in the table, a DELETE -** change is added to the changeset. If there is a row with a matching -** primary key in the database, but all fields contain their original -** values, no change is added to the changeset. -**
-** -** This means, amongst other things, that if a row is inserted and then later -** deleted while a session object is active, neither the insert nor the delete -** will be present in the changeset. Or if a row is deleted and then later a -** row with the same primary key values inserted while a session object is -** active, the resulting changeset will contain an UPDATE change instead of -** a DELETE and an INSERT. -** -** When a session object is disabled (see the [sqlite3session_enable()] API), -** it does not accumulate records when rows are inserted, updated or deleted. -** This may appear to have some counter-intuitive effects if a single row -** is written to more than once during a session. For example, if a row -** is inserted while a session object is enabled, then later deleted while -** the same session object is disabled, no INSERT record will appear in the -** changeset, even though the delete took place while the session was disabled. -** Or, if one field of a row is updated while a session is disabled, and -** another field of the same row is updated while the session is enabled, the -** resulting changeset will contain an UPDATE change that updates both fields. -*/ -SQLITE_API int sqlite3session_changeset( - sqlite3_session *pSession, /* Session object */ - int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */ - void **ppChangeset /* OUT: Buffer containing changeset */ -); - -/* -** CAPI3REF: Return An Upper-limit For The Size Of The Changeset -** METHOD: sqlite3_session -** -** By default, this function always returns 0. For it to return -** a useful result, the sqlite3_session object must have been configured -** to enable this API using sqlite3session_object_config() with the -** SQLITE_SESSION_OBJCONFIG_SIZE verb. -** -** When enabled, this function returns an upper limit, in bytes, for the size -** of the changeset that might be produced if sqlite3session_changeset() were -** called. The final changeset size might be equal to or smaller than the -** size in bytes returned by this function. -*/ -SQLITE_API sqlite3_int64 sqlite3session_changeset_size(sqlite3_session *pSession); - -/* -** CAPI3REF: Load The Difference Between Tables Into A Session -** METHOD: sqlite3_session -** -** If it is not already attached to the session object passed as the first -** argument, this function attaches table zTbl in the same manner as the -** [sqlite3session_attach()] function. If zTbl does not exist, or if it -** does not have a primary key, this function is a no-op (but does not return -** an error). -** -** Argument zFromDb must be the name of a database ("main", "temp" etc.) -** attached to the same database handle as the session object that contains -** a table compatible with the table attached to the session by this function. -** A table is considered compatible if it: -** -**
    -**
  • Has the same name, -**
  • Has the same set of columns declared in the same order, and -**
  • Has the same PRIMARY KEY definition. -**
-** -** If the tables are not compatible, SQLITE_SCHEMA is returned. If the tables -** are compatible but do not have any PRIMARY KEY columns, it is not an error -** but no changes are added to the session object. As with other session -** APIs, tables without PRIMARY KEYs are simply ignored. -** -** This function adds a set of changes to the session object that could be -** used to update the table in database zFrom (call this the "from-table") -** so that its content is the same as the table attached to the session -** object (call this the "to-table"). Specifically: -** -**
    -**
  • For each row (primary key) that exists in the to-table but not in -** the from-table, an INSERT record is added to the session object. -** -**
  • For each row (primary key) that exists in the to-table but not in -** the from-table, a DELETE record is added to the session object. -** -**
  • For each row (primary key) that exists in both tables, but features -** different non-PK values in each, an UPDATE record is added to the -** session. -**
+** will be destroyed when the preupdate callback returns. ** -** To clarify, if this function is called and then a changeset constructed -** using [sqlite3session_changeset()], then after applying that changeset to -** database zFrom the contents of the two compatible tables would be -** identical. +** ^The [sqlite3_preupdate_depth(D)] interface returns 0 if the preupdate +** callback was invoked as a result of a direct insert, update, or delete +** operation; or 1 for inserts, updates, or deletes invoked by top-level +** triggers; or 2 for changes resulting from triggers called by top-level +** triggers; and so forth. ** -** It an error if database zFrom does not exist or does not contain the -** required compatible table. +** When the [sqlite3_blob_write()] API is used to update a blob column, +** the pre-update hook is invoked with SQLITE_DELETE. This is because the +** in this case the new values are not available. In this case, when a +** callback made with op==SQLITE_DELETE is actuall a write using the +** sqlite3_blob_write() API, the [sqlite3_preupdate_blobwrite()] returns +** the index of the column being written. In other cases, where the +** pre-update hook is being invoked for some other reason, including a +** regular DELETE, sqlite3_preupdate_blobwrite() returns -1. ** -** If the operation is successful, SQLITE_OK is returned. Otherwise, an SQLite -** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg -** may be set to point to a buffer containing an English language error -** message. It is the responsibility of the caller to free this buffer using -** sqlite3_free(). +** See also: [sqlite3_update_hook()] */ -SQLITE_API int sqlite3session_diff( - sqlite3_session *pSession, - const char *zFromDb, - const char *zTbl, - char **pzErrMsg -); +#if defined(SQLITE_ENABLE_PREUPDATE_HOOK) + SQLITE_API void* + sqlite3_preupdate_hook(sqlite3* db, + void (*xPreUpdate)(void* pCtx, /* Copy of third arg to preupdate_hook() */ + sqlite3* db, /* Database handle */ + int op, /* SQLITE_UPDATE, DELETE or INSERT */ + char const* zDb, /* Database name */ + char const* zName, /* Table name */ + sqlite3_int64 iKey1, /* Rowid of row about to be deleted/updated */ + sqlite3_int64 iKey2 /* New rowid value (for a rowid UPDATE) */ + ), + void*); + SQLITE_API int sqlite3_preupdate_old(sqlite3*, int, sqlite3_value**); + SQLITE_API int sqlite3_preupdate_count(sqlite3*); + SQLITE_API int sqlite3_preupdate_depth(sqlite3*); + SQLITE_API int sqlite3_preupdate_new(sqlite3*, int, sqlite3_value**); + SQLITE_API int sqlite3_preupdate_blobwrite(sqlite3*); +#endif + /* + ** CAPI3REF: Low-level system error code + ** METHOD: sqlite3 + ** + ** ^Attempt to return the underlying operating system error code or error + ** number that caused the most recent I/O error or failure to open a file. + ** The return value is OS-dependent. For example, on unix systems, after + ** [sqlite3_open_v2()] returns [SQLITE_CANTOPEN], this interface could be + ** called to get back the underlying "errno" that caused the problem, such + ** as ENOSPC, EAUTH, EISDIR, and so forth. + */ + SQLITE_API int sqlite3_system_errno(sqlite3*); + + /* + ** CAPI3REF: Database Snapshot + ** KEYWORDS: {snapshot} {sqlite3_snapshot} + ** + ** An instance of the snapshot object records the state of a [WAL mode] + ** database for some specific point in history. + ** + ** In [WAL mode], multiple [database connections] that are open on the + ** same database file can each be reading a different historical version + ** of the database file. When a [database connection] begins a read + ** transaction, that connection sees an unchanging copy of the database + ** as it existed for the point in time when the transaction first started. + ** Subsequent changes to the database from other connections are not seen + ** by the reader until a new read transaction is started. + ** + ** The sqlite3_snapshot object records state information about an historical + ** version of the database file so that it is possible to later open a new read + ** transaction that sees that historical version of the database rather than + ** the most recent version. + */ + typedef struct sqlite3_snapshot + { + unsigned char hidden[48]; + } sqlite3_snapshot; + + /* + ** CAPI3REF: Record A Database Snapshot + ** CONSTRUCTOR: sqlite3_snapshot + ** + ** ^The [sqlite3_snapshot_get(D,S,P)] interface attempts to make a + ** new [sqlite3_snapshot] object that records the current state of + ** schema S in database connection D. ^On success, the + ** [sqlite3_snapshot_get(D,S,P)] interface writes a pointer to the newly + ** created [sqlite3_snapshot] object into *P and returns SQLITE_OK. + ** If there is not already a read-transaction open on schema S when + ** this function is called, one is opened automatically. + ** + ** The following must be true for this function to succeed. If any of + ** the following statements are false when sqlite3_snapshot_get() is + ** called, SQLITE_ERROR is returned. The final value of *P is undefined + ** in this case. + ** + **
    + **
  • The database handle must not be in [autocommit mode]. + ** + **
  • Schema S of [database connection] D must be a [WAL mode] database. + ** + **
  • There must not be a write transaction open on schema S of database + ** connection D. + ** + **
  • One or more transactions must have been written to the current wal + ** file since it was created on disk (by any connection). This means + ** that a snapshot cannot be taken on a wal mode database with no wal + ** file immediately after it is first opened. At least one transaction + ** must be written to it first. + **
+ ** + ** This function may also return SQLITE_NOMEM. If it is called with the + ** database handle in autocommit mode but fails for some other reason, + ** whether or not a read transaction is opened on schema S is undefined. + ** + ** The [sqlite3_snapshot] object returned from a successful call to + ** [sqlite3_snapshot_get()] must be freed using [sqlite3_snapshot_free()] + ** to avoid a memory leak. + ** + ** The [sqlite3_snapshot_get()] interface is only available when the + ** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used. + */ + SQLITE_API SQLITE_EXPERIMENTAL int + sqlite3_snapshot_get(sqlite3* db, const char* zSchema, sqlite3_snapshot** ppSnapshot); + + /* + ** CAPI3REF: Start a read transaction on an historical snapshot + ** METHOD: sqlite3_snapshot + ** + ** ^The [sqlite3_snapshot_open(D,S,P)] interface either starts a new read + ** transaction or upgrades an existing one for schema S of + ** [database connection] D such that the read transaction refers to + ** historical [snapshot] P, rather than the most recent change to the + ** database. ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK + ** on success or an appropriate [error code] if it fails. + ** + ** ^In order to succeed, the database connection must not be in + ** [autocommit mode] when [sqlite3_snapshot_open(D,S,P)] is called. If there + ** is already a read transaction open on schema S, then the database handle + ** must have no active statements (SELECT statements that have been passed + ** to sqlite3_step() but not sqlite3_reset() or sqlite3_finalize()). + ** SQLITE_ERROR is returned if either of these conditions is violated, or + ** if schema S does not exist, or if the snapshot object is invalid. + ** + ** ^A call to sqlite3_snapshot_open() will fail to open if the specified + ** snapshot has been overwritten by a [checkpoint]. In this case + ** SQLITE_ERROR_SNAPSHOT is returned. + ** + ** If there is already a read transaction open when this function is + ** invoked, then the same read transaction remains open (on the same + ** database snapshot) if SQLITE_ERROR, SQLITE_BUSY or SQLITE_ERROR_SNAPSHOT + ** is returned. If another error code - for example SQLITE_PROTOCOL or an + ** SQLITE_IOERR error code - is returned, then the final state of the + ** read transaction is undefined. If SQLITE_OK is returned, then the + ** read transaction is now open on database snapshot P. + ** + ** ^(A call to [sqlite3_snapshot_open(D,S,P)] will fail if the + ** database connection D does not know that the database file for + ** schema S is in [WAL mode]. A database connection might not know + ** that the database file is in [WAL mode] if there has been no prior + ** I/O on that database connection, or if the database entered [WAL mode] + ** after the most recent I/O on the database connection.)^ + ** (Hint: Run "[PRAGMA application_id]" against a newly opened + ** database connection in order to make it ready to use snapshots.) + ** + ** The [sqlite3_snapshot_open()] interface is only available when the + ** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used. + */ + SQLITE_API SQLITE_EXPERIMENTAL int + sqlite3_snapshot_open(sqlite3* db, const char* zSchema, sqlite3_snapshot* pSnapshot); + + /* + ** CAPI3REF: Destroy a snapshot + ** DESTRUCTOR: sqlite3_snapshot + ** + ** ^The [sqlite3_snapshot_free(P)] interface destroys [sqlite3_snapshot] P. + ** The application must eventually free every [sqlite3_snapshot] object + ** using this routine to avoid a memory leak. + ** + ** The [sqlite3_snapshot_free()] interface is only available when the + ** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used. + */ + SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*); + + /* + ** CAPI3REF: Compare the ages of two snapshot handles. + ** METHOD: sqlite3_snapshot + ** + ** The sqlite3_snapshot_cmp(P1, P2) interface is used to compare the ages + ** of two valid snapshot handles. + ** + ** If the two snapshot handles are not associated with the same database + ** file, the result of the comparison is undefined. + ** + ** Additionally, the result of the comparison is only valid if both of the + ** snapshot handles were obtained by calling sqlite3_snapshot_get() since the + ** last time the wal file was deleted. The wal file is deleted when the + ** database is changed back to rollback mode or when the number of database + ** clients drops to zero. If either snapshot handle was obtained before the + ** wal file was last deleted, the value returned by this function + ** is undefined. + ** + ** Otherwise, this API returns a negative value if P1 refers to an older + ** snapshot than P2, zero if the two handles refer to the same database + ** snapshot, and a positive value if P1 is a newer snapshot than P2. + ** + ** This interface is only available if SQLite is compiled with the + ** [SQLITE_ENABLE_SNAPSHOT] option. + */ + SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp(sqlite3_snapshot* p1, sqlite3_snapshot* p2); + + /* + ** CAPI3REF: Recover snapshots from a wal file + ** METHOD: sqlite3_snapshot + ** + ** If a [WAL file] remains on disk after all database connections close + ** (either through the use of the [SQLITE_FCNTL_PERSIST_WAL] [file control] + ** or because the last process to have the database opened exited without + ** calling [sqlite3_close()]) and a new connection is subsequently opened + ** on that database and [WAL file], the [sqlite3_snapshot_open()] interface + ** will only be able to open the last transaction added to the WAL file + ** even though the WAL file contains other valid transactions. + ** + ** This function attempts to scan the WAL file associated with database zDb + ** of database handle db and make all valid snapshots available to + ** sqlite3_snapshot_open(). It is an error if there is already a read + ** transaction open on the database, or if the database is not a WAL mode + ** database. + ** + ** SQLITE_OK is returned if successful, or an SQLite error code otherwise. + ** + ** This interface is only available if SQLite is compiled with the + ** [SQLITE_ENABLE_SNAPSHOT] option. + */ + SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3* db, const char* zDb); + + /* + ** CAPI3REF: Serialize a database + ** + ** The sqlite3_serialize(D,S,P,F) interface returns a pointer to memory + ** that is a serialization of the S database on [database connection] D. + ** If P is not a NULL pointer, then the size of the database in bytes + ** is written into *P. + ** + ** For an ordinary on-disk database file, the serialization is just a + ** copy of the disk file. For an in-memory database or a "TEMP" database, + ** the serialization is the same sequence of bytes which would be written + ** to disk if that database where backed up to disk. + ** + ** The usual case is that sqlite3_serialize() copies the serialization of + ** the database into memory obtained from [sqlite3_malloc64()] and returns + ** a pointer to that memory. The caller is responsible for freeing the + ** returned value to avoid a memory leak. However, if the F argument + ** contains the SQLITE_SERIALIZE_NOCOPY bit, then no memory allocations + ** are made, and the sqlite3_serialize() function will return a pointer + ** to the contiguous memory representation of the database that SQLite + ** is currently using for that database, or NULL if the no such contiguous + ** memory representation of the database exists. A contiguous memory + ** representation of the database will usually only exist if there has + ** been a prior call to [sqlite3_deserialize(D,S,...)] with the same + ** values of D and S. + ** The size of the database is written into *P even if the + ** SQLITE_SERIALIZE_NOCOPY bit is set but no contiguous copy + ** of the database exists. + ** + ** A call to sqlite3_serialize(D,S,P,F) might return NULL even if the + ** SQLITE_SERIALIZE_NOCOPY bit is omitted from argument F if a memory + ** allocation error occurs. + ** + ** This interface is omitted if SQLite is compiled with the + ** [SQLITE_OMIT_DESERIALIZE] option. + */ + SQLITE_API unsigned char* sqlite3_serialize(sqlite3* db, /* The database connection */ + const char* zSchema, /* Which DB to serialize. ex: "main", "temp", ... + */ + sqlite3_int64* piSize, /* Write size of the DB here, if not NULL */ + unsigned int mFlags /* Zero or more SQLITE_SERIALIZE_* flags */ + ); /* -** CAPI3REF: Generate A Patchset From A Session Object -** METHOD: sqlite3_session -** -** The differences between a patchset and a changeset are that: -** -**
    -**
  • DELETE records consist of the primary key fields only. The -** original values of other fields are omitted. -**
  • The original values of any modified fields are omitted from -** UPDATE records. -**
+** CAPI3REF: Flags for sqlite3_serialize ** -** A patchset blob may be used with up to date versions of all -** sqlite3changeset_xxx API functions except for sqlite3changeset_invert(), -** which returns SQLITE_CORRUPT if it is passed a patchset. Similarly, -** attempting to use a patchset blob with old versions of the -** sqlite3changeset_xxx APIs also provokes an SQLITE_CORRUPT error. -** -** Because the non-primary key "old.*" fields are omitted, no -** SQLITE_CHANGESET_DATA conflicts can be detected or reported if a patchset -** is passed to the sqlite3changeset_apply() API. Other conflict types work -** in the same way as for changesets. -** -** Changes within a patchset are ordered in the same way as for changesets -** generated by the sqlite3session_changeset() function (i.e. all changes for -** a single table are grouped together, tables appear in the order in which -** they were attached to the session object). -*/ -SQLITE_API int sqlite3session_patchset( - sqlite3_session *pSession, /* Session object */ - int *pnPatchset, /* OUT: Size of buffer at *ppPatchset */ - void **ppPatchset /* OUT: Buffer containing patchset */ -); - -/* -** CAPI3REF: Test if a changeset has recorded any changes. -** -** Return non-zero if no changes to attached tables have been recorded by -** the session object passed as the first argument. Otherwise, if one or -** more changes have been recorded, return zero. -** -** Even if this function returns zero, it is possible that calling -** [sqlite3session_changeset()] on the session handle may still return a -** changeset that contains no changes. This can happen when a row in -** an attached table is modified and then later on the original values -** are restored. However, if this function returns non-zero, then it is -** guaranteed that a call to sqlite3session_changeset() will return a -** changeset containing zero changes. -*/ -SQLITE_API int sqlite3session_isempty(sqlite3_session *pSession); - -/* -** CAPI3REF: Query for the amount of heap memory used by a session object. +** Zero or more of the following constants can be OR-ed together for +** the F argument to [sqlite3_serialize(D,S,P,F)]. ** -** This API returns the total amount of heap memory in bytes currently -** used by the session object passed as the only argument. +** SQLITE_SERIALIZE_NOCOPY means that [sqlite3_serialize()] will return +** a pointer to contiguous in-memory database that it is currently using, +** without making a copy of the database. If SQLite is not currently using +** a contiguous in-memory database, then this option causes +** [sqlite3_serialize()] to return a NULL pointer. SQLite will only be +** using a contiguous in-memory database if it has been initialized by a +** prior call to [sqlite3_deserialize()]. */ -SQLITE_API sqlite3_int64 sqlite3session_memory_used(sqlite3_session *pSession); +#define SQLITE_SERIALIZE_NOCOPY 0x001 /* Do no memory allocations */ + + /* + ** CAPI3REF: Deserialize a database + ** + ** The sqlite3_deserialize(D,S,P,N,M,F) interface causes the + ** [database connection] D to disconnect from database S and then + ** reopen S as an in-memory database based on the serialization contained + ** in P. The serialized database P is N bytes in size. M is the size of + ** the buffer P, which might be larger than N. If M is larger than N, and + ** the SQLITE_DESERIALIZE_READONLY bit is not set in F, then SQLite is + ** permitted to add content to the in-memory database as long as the total + ** size does not exceed M bytes. + ** + ** If the SQLITE_DESERIALIZE_FREEONCLOSE bit is set in F, then SQLite will + ** invoke sqlite3_free() on the serialization buffer when the database + ** connection closes. If the SQLITE_DESERIALIZE_RESIZEABLE bit is set, then + ** SQLite will try to increase the buffer size using sqlite3_realloc64() + ** if writes on the database cause it to grow larger than M bytes. + ** + ** The sqlite3_deserialize() interface will fail with SQLITE_BUSY if the + ** database is currently in a read transaction or is involved in a backup + ** operation. + ** + ** It is not possible to deserialized into the TEMP database. If the + ** S argument to sqlite3_deserialize(D,S,P,N,M,F) is "temp" then the + ** function returns SQLITE_ERROR. + ** + ** If sqlite3_deserialize(D,S,P,N,M,F) fails for any reason and if the + ** SQLITE_DESERIALIZE_FREEONCLOSE bit is set in argument F, then + ** [sqlite3_free()] is invoked on argument P prior to returning. + ** + ** This interface is omitted if SQLite is compiled with the + ** [SQLITE_OMIT_DESERIALIZE] option. + */ + SQLITE_API int sqlite3_deserialize(sqlite3* db, /* The database connection */ + const char* zSchema, /* Which DB to reopen with the deserialization */ + unsigned char* pData, /* The serialized database content */ + sqlite3_int64 szDb, /* Number bytes in the deserialization */ + sqlite3_int64 szBuf, /* Total size of buffer pData[] */ + unsigned mFlags /* Zero or more SQLITE_DESERIALIZE_* flags */ + ); /* -** CAPI3REF: Create An Iterator To Traverse A Changeset -** CONSTRUCTOR: sqlite3_changeset_iter -** -** Create an iterator used to iterate through the contents of a changeset. -** If successful, *pp is set to point to the iterator handle and SQLITE_OK -** is returned. Otherwise, if an error occurs, *pp is set to zero and an -** SQLite error code is returned. -** -** The following functions can be used to advance and query a changeset -** iterator created by this function: +** CAPI3REF: Flags for sqlite3_deserialize() ** -**
    -**
  • [sqlite3changeset_next()] -**
  • [sqlite3changeset_op()] -**
  • [sqlite3changeset_new()] -**
  • [sqlite3changeset_old()] -**
+** The following are allowed values for 6th argument (the F argument) to +** the [sqlite3_deserialize(D,S,P,N,M,F)] interface. ** -** It is the responsibility of the caller to eventually destroy the iterator -** by passing it to [sqlite3changeset_finalize()]. The buffer containing the -** changeset (pChangeset) must remain valid until after the iterator is -** destroyed. -** -** Assuming the changeset blob was created by one of the -** [sqlite3session_changeset()], [sqlite3changeset_concat()] or -** [sqlite3changeset_invert()] functions, all changes within the changeset -** that apply to a single table are grouped together. This means that when -** an application iterates through a changeset using an iterator created by -** this function, all changes that relate to a single table are visited -** consecutively. There is no chance that the iterator will visit a change -** the applies to table X, then one for table Y, and then later on visit -** another change for table X. -** -** The behavior of sqlite3changeset_start_v2() and its streaming equivalent -** may be modified by passing a combination of -** [SQLITE_CHANGESETSTART_INVERT | supported flags] as the 4th parameter. -** -** Note that the sqlite3changeset_start_v2() API is still experimental -** and therefore subject to change. -*/ -SQLITE_API int sqlite3changeset_start( - sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */ - int nChangeset, /* Size of changeset blob in bytes */ - void *pChangeset /* Pointer to blob containing changeset */ -); -SQLITE_API int sqlite3changeset_start_v2( - sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */ - int nChangeset, /* Size of changeset blob in bytes */ - void *pChangeset, /* Pointer to blob containing changeset */ - int flags /* SESSION_CHANGESETSTART_* flags */ -); - -/* -** CAPI3REF: Flags for sqlite3changeset_start_v2 +** The SQLITE_DESERIALIZE_FREEONCLOSE means that the database serialization +** in the P argument is held in memory obtained from [sqlite3_malloc64()] +** and that SQLite should take ownership of this memory and automatically +** free it when it has finished using it. Without this flag, the caller +** is responsible for freeing any dynamically allocated memory. ** -** The following flags may passed via the 4th parameter to -** [sqlite3changeset_start_v2] and [sqlite3changeset_start_v2_strm]: +** The SQLITE_DESERIALIZE_RESIZEABLE flag means that SQLite is allowed to +** grow the size of the database using calls to [sqlite3_realloc64()]. This +** flag should only be used if SQLITE_DESERIALIZE_FREEONCLOSE is also used. +** Without this flag, the deserialized database cannot increase in size beyond +** the number of bytes specified by the M parameter. ** -**
SQLITE_CHANGESETAPPLY_INVERT
-** Invert the changeset while iterating through it. This is equivalent to -** inverting a changeset using sqlite3changeset_invert() before applying it. -** It is an error to specify this flag with a patchset. +** The SQLITE_DESERIALIZE_READONLY flag means that the deserialized database +** should be treated as read-only. */ -#define SQLITE_CHANGESETSTART_INVERT 0x0002 - +#define SQLITE_DESERIALIZE_FREEONCLOSE 1 /* Call sqlite3_free() on close */ +#define SQLITE_DESERIALIZE_RESIZEABLE 2 /* Resize using sqlite3_realloc64() */ +#define SQLITE_DESERIALIZE_READONLY 4 /* Database is read-only */ /* -** CAPI3REF: Advance A Changeset Iterator -** METHOD: sqlite3_changeset_iter -** -** This function may only be used with iterators created by the function -** [sqlite3changeset_start()]. If it is called on an iterator passed to -** a conflict-handler callback by [sqlite3changeset_apply()], SQLITE_MISUSE -** is returned and the call has no effect. -** -** Immediately after an iterator is created by sqlite3changeset_start(), it -** does not point to any change in the changeset. Assuming the changeset -** is not empty, the first call to this function advances the iterator to -** point to the first change in the changeset. Each subsequent call advances -** the iterator to point to the next change in the changeset (if any). If -** no error occurs and the iterator points to a valid change after a call -** to sqlite3changeset_next() has advanced it, SQLITE_ROW is returned. -** Otherwise, if all changes in the changeset have already been visited, -** SQLITE_DONE is returned. -** -** If an error occurs, an SQLite error code is returned. Possible error -** codes include SQLITE_CORRUPT (if the changeset buffer is corrupt) or -** SQLITE_NOMEM. +** Undo the hack that converts floating point types to integer for +** builds on processors without floating point support. */ -SQLITE_API int sqlite3changeset_next(sqlite3_changeset_iter *pIter); +#ifdef SQLITE_OMIT_FLOATING_POINT +#undef double +#endif -/* -** CAPI3REF: Obtain The Current Operation From A Changeset Iterator -** METHOD: sqlite3_changeset_iter -** -** The pIter argument passed to this function may either be an iterator -** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator -** created by [sqlite3changeset_start()]. In the latter case, the most recent -** call to [sqlite3changeset_next()] must have returned [SQLITE_ROW]. If this -** is not the case, this function returns [SQLITE_MISUSE]. -** -** Arguments pOp, pnCol and pzTab may not be NULL. Upon return, three -** outputs are set through these pointers: -** -** *pOp is set to one of [SQLITE_INSERT], [SQLITE_DELETE] or [SQLITE_UPDATE], -** depending on the type of change that the iterator currently points to; -** -** *pnCol is set to the number of columns in the table affected by the change; and -** -** *pzTab is set to point to a nul-terminated utf-8 encoded string containing -** the name of the table affected by the current change. The buffer remains -** valid until either sqlite3changeset_next() is called on the iterator -** or until the conflict-handler function returns. -** -** If pbIndirect is not NULL, then *pbIndirect is set to true (1) if the change -** is an indirect change, or false (0) otherwise. See the documentation for -** [sqlite3session_indirect()] for a description of direct and indirect -** changes. -** -** If no error occurs, SQLITE_OK is returned. If an error does occur, an -** SQLite error code is returned. The values of the output variables may not -** be trusted in this case. -*/ -SQLITE_API int sqlite3changeset_op( - sqlite3_changeset_iter *pIter, /* Iterator object */ - const char **pzTab, /* OUT: Pointer to table name */ - int *pnCol, /* OUT: Number of columns in table */ - int *pOp, /* OUT: SQLITE_INSERT, DELETE or UPDATE */ - int *pbIndirect /* OUT: True for an 'indirect' change */ -); +#ifdef __cplusplus +} /* End of the 'extern "C"' block */ +#endif +#endif /* SQLITE3_H */ +/******** Begin file sqlite3rtree.h *********/ /* -** CAPI3REF: Obtain The Primary Key Definition Of A Table -** METHOD: sqlite3_changeset_iter -** -** For each modified table, a changeset includes the following: -** -**
    -**
  • The number of columns in the table, and -**
  • Which of those columns make up the tables PRIMARY KEY. -**
+** 2010 August 30 ** -** This function is used to find which columns comprise the PRIMARY KEY of -** the table modified by the change that iterator pIter currently points to. -** If successful, *pabPK is set to point to an array of nCol entries, where -** nCol is the number of columns in the table. Elements of *pabPK are set to -** 0x01 if the corresponding column is part of the tables primary key, or -** 0x00 if it is not. +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: ** -** If argument pnCol is not NULL, then *pnCol is set to the number of columns -** in the table. +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. ** -** If this function is called when the iterator does not point to a valid -** entry, SQLITE_MISUSE is returned and the output variables zeroed. Otherwise, -** SQLITE_OK is returned and the output variables populated as described -** above. +************************************************************************* */ -SQLITE_API int sqlite3changeset_pk( - sqlite3_changeset_iter *pIter, /* Iterator object */ - unsigned char **pabPK, /* OUT: Array of boolean - true for PK cols */ - int *pnCol /* OUT: Number of entries in output array */ -); -/* -** CAPI3REF: Obtain old.* Values From A Changeset Iterator -** METHOD: sqlite3_changeset_iter -** -** The pIter argument passed to this function may either be an iterator -** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator -** created by [sqlite3changeset_start()]. In the latter case, the most recent -** call to [sqlite3changeset_next()] must have returned SQLITE_ROW. -** Furthermore, it may only be called if the type of change that the iterator -** currently points to is either [SQLITE_DELETE] or [SQLITE_UPDATE]. Otherwise, -** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL. -** -** Argument iVal must be greater than or equal to 0, and less than the number -** of columns in the table affected by the current change. Otherwise, -** [SQLITE_RANGE] is returned and *ppValue is set to NULL. -** -** If successful, this function sets *ppValue to point to a protected -** sqlite3_value object containing the iVal'th value from the vector of -** original row values stored as part of the UPDATE or DELETE change and -** returns SQLITE_OK. The name of the function comes from the fact that this -** is similar to the "old.*" columns available to update or delete triggers. -** -** If some other error occurs (e.g. an OOM condition), an SQLite error code -** is returned and *ppValue is set to NULL. -*/ -SQLITE_API int sqlite3changeset_old( - sqlite3_changeset_iter *pIter, /* Changeset iterator */ - int iVal, /* Column number */ - sqlite3_value **ppValue /* OUT: Old value (or NULL pointer) */ -); +#ifndef _SQLITE3RTREE_H_ +#define _SQLITE3RTREE_H_ -/* -** CAPI3REF: Obtain new.* Values From A Changeset Iterator -** METHOD: sqlite3_changeset_iter -** -** The pIter argument passed to this function may either be an iterator -** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator -** created by [sqlite3changeset_start()]. In the latter case, the most recent -** call to [sqlite3changeset_next()] must have returned SQLITE_ROW. -** Furthermore, it may only be called if the type of change that the iterator -** currently points to is either [SQLITE_UPDATE] or [SQLITE_INSERT]. Otherwise, -** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL. -** -** Argument iVal must be greater than or equal to 0, and less than the number -** of columns in the table affected by the current change. Otherwise, -** [SQLITE_RANGE] is returned and *ppValue is set to NULL. -** -** If successful, this function sets *ppValue to point to a protected -** sqlite3_value object containing the iVal'th value from the vector of -** new row values stored as part of the UPDATE or INSERT change and -** returns SQLITE_OK. If the change is an UPDATE and does not include -** a new value for the requested column, *ppValue is set to NULL and -** SQLITE_OK returned. The name of the function comes from the fact that -** this is similar to the "new.*" columns available to update or delete -** triggers. -** -** If some other error occurs (e.g. an OOM condition), an SQLite error code -** is returned and *ppValue is set to NULL. -*/ -SQLITE_API int sqlite3changeset_new( - sqlite3_changeset_iter *pIter, /* Changeset iterator */ - int iVal, /* Column number */ - sqlite3_value **ppValue /* OUT: New value (or NULL pointer) */ -); +#ifdef __cplusplus +extern "C" +{ +#endif -/* -** CAPI3REF: Obtain Conflicting Row Values From A Changeset Iterator -** METHOD: sqlite3_changeset_iter -** -** This function should only be used with iterator objects passed to a -** conflict-handler callback by [sqlite3changeset_apply()] with either -** [SQLITE_CHANGESET_DATA] or [SQLITE_CHANGESET_CONFLICT]. If this function -** is called on any other iterator, [SQLITE_MISUSE] is returned and *ppValue -** is set to NULL. -** -** Argument iVal must be greater than or equal to 0, and less than the number -** of columns in the table affected by the current change. Otherwise, -** [SQLITE_RANGE] is returned and *ppValue is set to NULL. -** -** If successful, this function sets *ppValue to point to a protected -** sqlite3_value object containing the iVal'th value from the -** "conflicting row" associated with the current conflict-handler callback -** and returns SQLITE_OK. -** -** If some other error occurs (e.g. an OOM condition), an SQLite error code -** is returned and *ppValue is set to NULL. -*/ -SQLITE_API int sqlite3changeset_conflict( - sqlite3_changeset_iter *pIter, /* Changeset iterator */ - int iVal, /* Column number */ - sqlite3_value **ppValue /* OUT: Value from conflicting row */ -); + typedef struct sqlite3_rtree_geometry sqlite3_rtree_geometry; + typedef struct sqlite3_rtree_query_info sqlite3_rtree_query_info; -/* -** CAPI3REF: Determine The Number Of Foreign Key Constraint Violations -** METHOD: sqlite3_changeset_iter -** -** This function may only be called with an iterator passed to an -** SQLITE_CHANGESET_FOREIGN_KEY conflict handler callback. In this case -** it sets the output variable to the total number of known foreign key -** violations in the destination database and returns SQLITE_OK. -** -** In all other cases this function returns SQLITE_MISUSE. +/* The double-precision datatype used by RTree depends on the +** SQLITE_RTREE_INT_ONLY compile-time option. */ -SQLITE_API int sqlite3changeset_fk_conflicts( - sqlite3_changeset_iter *pIter, /* Changeset iterator */ - int *pnOut /* OUT: Number of FK violations */ -); - +#ifdef SQLITE_RTREE_INT_ONLY + typedef sqlite3_int64 sqlite3_rtree_dbl; +#else +typedef double sqlite3_rtree_dbl; +#endif -/* -** CAPI3REF: Finalize A Changeset Iterator -** METHOD: sqlite3_changeset_iter -** -** This function is used to finalize an iterator allocated with -** [sqlite3changeset_start()]. -** -** This function should only be called on iterators created using the -** [sqlite3changeset_start()] function. If an application calls this -** function with an iterator passed to a conflict-handler by -** [sqlite3changeset_apply()], [SQLITE_MISUSE] is immediately returned and the -** call has no effect. -** -** If an error was encountered within a call to an sqlite3changeset_xxx() -** function (for example an [SQLITE_CORRUPT] in [sqlite3changeset_next()] or an -** [SQLITE_NOMEM] in [sqlite3changeset_new()]) then an error code corresponding -** to that error is returned by this function. Otherwise, SQLITE_OK is -** returned. This is to allow the following pattern (pseudo-code): -** -**
-**   sqlite3changeset_start();
-**   while( SQLITE_ROW==sqlite3changeset_next() ){
-**     // Do something with change.
-**   }
-**   rc = sqlite3changeset_finalize();
-**   if( rc!=SQLITE_OK ){
-**     // An error has occurred
-**   }
-** 
-*/ -SQLITE_API int sqlite3changeset_finalize(sqlite3_changeset_iter *pIter); + /* + ** Register a geometry callback named zGeom that can be used as part of an + ** R-Tree geometry query as follows: + ** + ** SELECT ... FROM WHERE MATCH $zGeom(... params ...) + */ + SQLITE_API int sqlite3_rtree_geometry_callback(sqlite3* db, + const char* zGeom, + int (*xGeom)(sqlite3_rtree_geometry*, int, sqlite3_rtree_dbl*, int*), + void* pContext); + + /* + ** A pointer to a structure of the following type is passed as the first + ** argument to callbacks registered using rtree_geometry_callback(). + */ + struct sqlite3_rtree_geometry + { + void* pContext; /* Copy of pContext passed to s_r_g_c() */ + int nParam; /* Size of array aParam[] */ + sqlite3_rtree_dbl* aParam; /* Parameters passed to SQL geom function */ + void* pUser; /* Callback implementation user data */ + void (*xDelUser)(void*); /* Called by SQLite to clean up pUser */ + }; + + /* + ** Register a 2nd-generation geometry callback named zScore that can be + ** used as part of an R-Tree geometry query as follows: + ** + ** SELECT ... FROM WHERE MATCH $zQueryFunc(... params ...) + */ + SQLITE_API int sqlite3_rtree_query_callback(sqlite3* db, + const char* zQueryFunc, + int (*xQueryFunc)(sqlite3_rtree_query_info*), + void* pContext, + void (*xDestructor)(void*)); + + /* + ** A pointer to a structure of the following type is passed as the + ** argument to scored geometry callback registered using + ** sqlite3_rtree_query_callback(). + ** + ** Note that the first 5 fields of this structure are identical to + ** sqlite3_rtree_geometry. This structure is a subclass of + ** sqlite3_rtree_geometry. + */ + struct sqlite3_rtree_query_info + { + void* pContext; /* pContext from when function registered */ + int nParam; /* Number of function parameters */ + sqlite3_rtree_dbl* aParam; /* value of function parameters */ + void* pUser; /* callback can use this, if desired */ + void (*xDelUser)(void*); /* function to free pUser */ + sqlite3_rtree_dbl* aCoord; /* Coordinates of node or entry to check */ + unsigned int* anQueue; /* Number of pending entries in the queue */ + int nCoord; /* Number of coordinates */ + int iLevel; /* Level of current node or entry */ + int mxLevel; /* The largest iLevel value in the tree */ + sqlite3_int64 iRowid; /* Rowid for current entry */ + sqlite3_rtree_dbl rParentScore; /* Score of parent node */ + int eParentWithin; /* Visibility of parent node */ + int eWithin; /* OUT: Visibility */ + sqlite3_rtree_dbl rScore; /* OUT: Write the score here */ + /* The following fields are only available in 3.8.11 and later */ + sqlite3_value** apSqlParam; /* Original SQL values of parameters */ + }; /* -** CAPI3REF: Invert A Changeset -** -** This function is used to "invert" a changeset object. Applying an inverted -** changeset to a database reverses the effects of applying the uninverted -** changeset. Specifically: -** -**
    -**
  • Each DELETE change is changed to an INSERT, and -**
  • Each INSERT change is changed to a DELETE, and -**
  • For each UPDATE change, the old.* and new.* values are exchanged. -**
-** -** This function does not change the order in which changes appear within -** the changeset. It merely reverses the sense of each individual change. -** -** If successful, a pointer to a buffer containing the inverted changeset -** is stored in *ppOut, the size of the same buffer is stored in *pnOut, and -** SQLITE_OK is returned. If an error occurs, both *pnOut and *ppOut are -** zeroed and an SQLite error code returned. -** -** It is the responsibility of the caller to eventually call sqlite3_free() -** on the *ppOut pointer to free the buffer allocation following a successful -** call to this function. -** -** WARNING/TODO: This function currently assumes that the input is a valid -** changeset. If it is not, the results are undefined. +** Allowed values for sqlite3_rtree_query.eWithin and .eParentWithin. */ -SQLITE_API int sqlite3changeset_invert( - int nIn, const void *pIn, /* Input changeset */ - int *pnOut, void **ppOut /* OUT: Inverse of input */ -); +#define NOT_WITHIN 0 /* Object completely outside of query region */ +#define PARTLY_WITHIN 1 /* Object partially overlaps query region */ +#define FULLY_WITHIN 2 /* Object fully contained within query region */ -/* -** CAPI3REF: Concatenate Two Changeset Objects -** -** This function is used to concatenate two changesets, A and B, into a -** single changeset. The result is a changeset equivalent to applying -** changeset A followed by changeset B. -** -** This function combines the two input changesets using an -** sqlite3_changegroup object. Calling it produces similar results as the -** following code fragment: -** -**
-**   sqlite3_changegroup *pGrp;
-**   rc = sqlite3_changegroup_new(&pGrp);
-**   if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nA, pA);
-**   if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nB, pB);
-**   if( rc==SQLITE_OK ){
-**     rc = sqlite3changegroup_output(pGrp, pnOut, ppOut);
-**   }else{
-**     *ppOut = 0;
-**     *pnOut = 0;
-**   }
-** 
-** -** Refer to the sqlite3_changegroup documentation below for details. -*/ -SQLITE_API int sqlite3changeset_concat( - int nA, /* Number of bytes in buffer pA */ - void *pA, /* Pointer to buffer containing changeset A */ - int nB, /* Number of bytes in buffer pB */ - void *pB, /* Pointer to buffer containing changeset B */ - int *pnOut, /* OUT: Number of bytes in output changeset */ - void **ppOut /* OUT: Buffer containing output changeset */ -); +#ifdef __cplusplus +} /* end of the 'extern "C"' block */ +#endif +#endif /* ifndef _SQLITE3RTREE_H_ */ -/* -** CAPI3REF: Changegroup Handle -** -** A changegroup is an object used to combine two or more -** [changesets] or [patchsets] -*/ -typedef struct sqlite3_changegroup sqlite3_changegroup; +/******** End of sqlite3rtree.h *********/ +/******** Begin file sqlite3session.h *********/ -/* -** CAPI3REF: Create A New Changegroup Object -** CONSTRUCTOR: sqlite3_changegroup -** -** An sqlite3_changegroup object is used to combine two or more changesets -** (or patchsets) into a single changeset (or patchset). A single changegroup -** object may combine changesets or patchsets, but not both. The output is -** always in the same format as the input. -** -** If successful, this function returns SQLITE_OK and populates (*pp) with -** a pointer to a new sqlite3_changegroup object before returning. The caller -** should eventually free the returned object using a call to -** sqlite3changegroup_delete(). If an error occurs, an SQLite error code -** (i.e. SQLITE_NOMEM) is returned and *pp is set to NULL. -** -** The usual usage pattern for an sqlite3_changegroup object is as follows: -** -**
    -**
  • It is created using a call to sqlite3changegroup_new(). -** -**
  • Zero or more changesets (or patchsets) are added to the object -** by calling sqlite3changegroup_add(). -** -**
  • The result of combining all input changesets together is obtained -** by the application via a call to sqlite3changegroup_output(). -** -**
  • The object is deleted using a call to sqlite3changegroup_delete(). -**
-** -** Any number of calls to add() and output() may be made between the calls to -** new() and delete(), and in any order. -** -** As well as the regular sqlite3changegroup_add() and -** sqlite3changegroup_output() functions, also available are the streaming -** versions sqlite3changegroup_add_strm() and sqlite3changegroup_output_strm(). -*/ -SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp); +#if !defined(__SQLITESESSION_H_) && defined(SQLITE_ENABLE_SESSION) +#define __SQLITESESSION_H_ 1 /* -** CAPI3REF: Add A Changeset To A Changegroup -** METHOD: sqlite3_changegroup -** -** Add all changes within the changeset (or patchset) in buffer pData (size -** nData bytes) to the changegroup. -** -** If the buffer contains a patchset, then all prior calls to this function -** on the same changegroup object must also have specified patchsets. Or, if -** the buffer contains a changeset, so must have the earlier calls to this -** function. Otherwise, SQLITE_ERROR is returned and no changes are added -** to the changegroup. -** -** Rows within the changeset and changegroup are identified by the values in -** their PRIMARY KEY columns. A change in the changeset is considered to -** apply to the same row as a change already present in the changegroup if -** the two rows have the same primary key. -** -** Changes to rows that do not already appear in the changegroup are -** simply copied into it. Or, if both the new changeset and the changegroup -** contain changes that apply to a single row, the final contents of the -** changegroup depends on the type of each change, as follows: -** -** -** -** -**
Existing Change New Change Output Change -**
INSERT INSERT -** The new change is ignored. This case does not occur if the new -** changeset was recorded immediately after the changesets already -** added to the changegroup. -**
INSERT UPDATE -** The INSERT change remains in the changegroup. The values in the -** INSERT change are modified as if the row was inserted by the -** existing change and then updated according to the new change. -**
INSERT DELETE -** The existing INSERT is removed from the changegroup. The DELETE is -** not added. -**
UPDATE INSERT -** The new change is ignored. This case does not occur if the new -** changeset was recorded immediately after the changesets already -** added to the changegroup. -**
UPDATE UPDATE -** The existing UPDATE remains within the changegroup. It is amended -** so that the accompanying values are as if the row was updated once -** by the existing change and then again by the new change. -**
UPDATE DELETE -** The existing UPDATE is replaced by the new DELETE within the -** changegroup. -**
DELETE INSERT -** If one or more of the column values in the row inserted by the -** new change differ from those in the row deleted by the existing -** change, the existing DELETE is replaced by an UPDATE within the -** changegroup. Otherwise, if the inserted row is exactly the same -** as the deleted row, the existing DELETE is simply discarded. -**
DELETE UPDATE -** The new change is ignored. This case does not occur if the new -** changeset was recorded immediately after the changesets already -** added to the changegroup. -**
DELETE DELETE -** The new change is ignored. This case does not occur if the new -** changeset was recorded immediately after the changesets already -** added to the changegroup. -**
-** -** If the new changeset contains changes to a table that is already present -** in the changegroup, then the number of columns and the position of the -** primary key columns for the table must be consistent. If this is not the -** case, this function fails with SQLITE_SCHEMA. If the input changeset -** appears to be corrupt and the corruption is detected, SQLITE_CORRUPT is -** returned. Or, if an out-of-memory condition occurs during processing, this -** function returns SQLITE_NOMEM. In all cases, if an error occurs the state -** of the final contents of the changegroup is undefined. -** -** If no error occurs, SQLITE_OK is returned. +** Make sure we can call this stuff from C++. */ -SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData); +#ifdef __cplusplus +extern "C" +{ +#endif -/* -** CAPI3REF: Obtain A Composite Changeset From A Changegroup -** METHOD: sqlite3_changegroup -** -** Obtain a buffer containing a changeset (or patchset) representing the -** current contents of the changegroup. If the inputs to the changegroup -** were themselves changesets, the output is a changeset. Or, if the -** inputs were patchsets, the output is also a patchset. -** -** As with the output of the sqlite3session_changeset() and -** sqlite3session_patchset() functions, all changes related to a single -** table are grouped together in the output of this function. Tables appear -** in the same order as for the very first changeset added to the changegroup. -** If the second or subsequent changesets added to the changegroup contain -** changes for tables that do not appear in the first changeset, they are -** appended onto the end of the output changeset, again in the order in -** which they are first encountered. -** -** If an error occurs, an SQLite error code is returned and the output -** variables (*pnData) and (*ppData) are set to 0. Otherwise, SQLITE_OK -** is returned and the output variables are set to the size of and a -** pointer to the output buffer, respectively. In this case it is the -** responsibility of the caller to eventually free the buffer using a -** call to sqlite3_free(). -*/ -SQLITE_API int sqlite3changegroup_output( - sqlite3_changegroup*, - int *pnData, /* OUT: Size of output buffer in bytes */ - void **ppData /* OUT: Pointer to output buffer */ -); + /* + ** CAPI3REF: Session Object Handle + ** + ** An instance of this object is a [session] that can be used to + ** record changes to a database. + */ + typedef struct sqlite3_session sqlite3_session; + + /* + ** CAPI3REF: Changeset Iterator Handle + ** + ** An instance of this object acts as a cursor for iterating + ** over the elements of a [changeset] or [patchset]. + */ + typedef struct sqlite3_changeset_iter sqlite3_changeset_iter; + + /* + ** CAPI3REF: Create A New Session Object + ** CONSTRUCTOR: sqlite3_session + ** + ** Create a new session object attached to database handle db. If successful, + ** a pointer to the new object is written to *ppSession and SQLITE_OK is + ** returned. If an error occurs, *ppSession is set to NULL and an SQLite + ** error code (e.g. SQLITE_NOMEM) is returned. + ** + ** It is possible to create multiple session objects attached to a single + ** database handle. + ** + ** Session objects created using this function should be deleted using the + ** [sqlite3session_delete()] function before the database handle that they + ** are attached to is itself closed. If the database handle is closed before + ** the session object is deleted, then the results of calling any session + ** module function, including [sqlite3session_delete()] on the session object + ** are undefined. + ** + ** Because the session module uses the [sqlite3_preupdate_hook()] API, it + ** is not possible for an application to register a pre-update hook on a + ** database handle that has one or more session objects attached. Nor is + ** it possible to create a session object attached to a database handle for + ** which a pre-update hook is already defined. The results of attempting + ** either of these things are undefined. + ** + ** The session object will be used to create changesets for tables in + ** database zDb, where zDb is either "main", or "temp", or the name of an + ** attached database. It is not an error if database zDb is not attached + ** to the database when the session object is created. + */ + SQLITE_API int sqlite3session_create(sqlite3* db, /* Database handle */ + const char* zDb, /* Name of db (e.g. "main") */ + sqlite3_session** ppSession /* OUT: New session object */ + ); + + /* + ** CAPI3REF: Delete A Session Object + ** DESTRUCTOR: sqlite3_session + ** + ** Delete a session object previously allocated using + ** [sqlite3session_create()]. Once a session object has been deleted, the + ** results of attempting to use pSession with any other session module + ** function are undefined. + ** + ** Session objects must be deleted before the database handle to which they + ** are attached is closed. Refer to the documentation for + ** [sqlite3session_create()] for details. + */ + SQLITE_API void sqlite3session_delete(sqlite3_session* pSession); + + /* + ** CAPIREF: Conigure a Session Object + ** METHOD: sqlite3_session + ** + ** This method is used to configure a session object after it has been + ** created. At present the only valid value for the second parameter is + ** [SQLITE_SESSION_OBJCONFIG_SIZE]. + ** + ** Arguments for sqlite3session_object_config() + ** + ** The following values may passed as the the 4th parameter to + ** sqlite3session_object_config(). + ** + **
SQLITE_SESSION_OBJCONFIG_SIZE
+ ** This option is used to set, clear or query the flag that enables + ** the [sqlite3session_changeset_size()] API. Because it imposes some + ** computational overhead, this API is disabled by default. Argument + ** pArg must point to a value of type (int). If the value is initially + ** 0, then the sqlite3session_changeset_size() API is disabled. If it + ** is greater than 0, then the same API is enabled. Or, if the initial + ** value is less than zero, no change is made. In all cases the (int) + ** variable is set to 1 if the sqlite3session_changeset_size() API is + ** enabled following the current call, or 0 otherwise. + ** + ** It is an error (SQLITE_MISUSE) to attempt to modify this setting after + ** the first table has been attached to the session object. + */ + SQLITE_API int sqlite3session_object_config(sqlite3_session*, int op, void* pArg); + +/* + */ +#define SQLITE_SESSION_OBJCONFIG_SIZE 1 -/* -** CAPI3REF: Delete A Changegroup Object -** DESTRUCTOR: sqlite3_changegroup -*/ -SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*); + /* + ** CAPI3REF: Enable Or Disable A Session Object + ** METHOD: sqlite3_session + ** + ** Enable or disable the recording of changes by a session object. When + ** enabled, a session object records changes made to the database. When + ** disabled - it does not. A newly created session object is enabled. + ** Refer to the documentation for [sqlite3session_changeset()] for further + ** details regarding how enabling and disabling a session object affects + ** the eventual changesets. + ** + ** Passing zero to this function disables the session. Passing a value + ** greater than zero enables it. Passing a value less than zero is a + ** no-op, and may be used to query the current state of the session. + ** + ** The return value indicates the final state of the session object: 0 if + ** the session is disabled, or 1 if it is enabled. + */ + SQLITE_API int sqlite3session_enable(sqlite3_session* pSession, int bEnable); + + /* + ** CAPI3REF: Set Or Clear the Indirect Change Flag + ** METHOD: sqlite3_session + ** + ** Each change recorded by a session object is marked as either direct or + ** indirect. A change is marked as indirect if either: + ** + **
    + **
  • The session object "indirect" flag is set when the change is + ** made, or + **
  • The change is made by an SQL trigger or foreign key action + ** instead of directly as a result of a users SQL statement. + **
+ ** + ** If a single row is affected by more than one operation within a session, + ** then the change is considered indirect if all operations meet the criteria + ** for an indirect change above, or direct otherwise. + ** + ** This function is used to set, clear or query the session object indirect + ** flag. If the second argument passed to this function is zero, then the + ** indirect flag is cleared. If it is greater than zero, the indirect flag + ** is set. Passing a value less than zero does not modify the current value + ** of the indirect flag, and may be used to query the current state of the + ** indirect flag for the specified session object. + ** + ** The return value indicates the final state of the indirect flag: 0 if + ** it is clear, or 1 if it is set. + */ + SQLITE_API int sqlite3session_indirect(sqlite3_session* pSession, int bIndirect); + + /* + ** CAPI3REF: Attach A Table To A Session Object + ** METHOD: sqlite3_session + ** + ** If argument zTab is not NULL, then it is the name of a table to attach + ** to the session object passed as the first argument. All subsequent changes + ** made to the table while the session object is enabled will be recorded. See + ** documentation for [sqlite3session_changeset()] for further details. + ** + ** Or, if argument zTab is NULL, then changes are recorded for all tables + ** in the database. If additional tables are added to the database (by + ** executing "CREATE TABLE" statements) after this call is made, changes for + ** the new tables are also recorded. + ** + ** Changes can only be recorded for tables that have a PRIMARY KEY explicitly + ** defined as part of their CREATE TABLE statement. It does not matter if the + ** PRIMARY KEY is an "INTEGER PRIMARY KEY" (rowid alias) or not. The PRIMARY + ** KEY may consist of a single column, or may be a composite key. + ** + ** It is not an error if the named table does not exist in the database. Nor + ** is it an error if the named table does not have a PRIMARY KEY. However, + ** no changes will be recorded in either of these scenarios. + ** + ** Changes are not recorded for individual rows that have NULL values stored + ** in one or more of their PRIMARY KEY columns. + ** + ** SQLITE_OK is returned if the call completes without error. Or, if an error + ** occurs, an SQLite error code (e.g. SQLITE_NOMEM) is returned. + ** + **

Special sqlite_stat1 Handling

+ ** + ** As of SQLite version 3.22.0, the "sqlite_stat1" table is an exception to + ** some of the rules above. In SQLite, the schema of sqlite_stat1 is: + **
+    **        CREATE TABLE sqlite_stat1(tbl,idx,stat)
+    **  
+ ** + ** Even though sqlite_stat1 does not have a PRIMARY KEY, changes are + ** recorded for it as if the PRIMARY KEY is (tbl,idx). Additionally, changes + ** are recorded for rows for which (idx IS NULL) is true. However, for such + ** rows a zero-length blob (SQL value X'') is stored in the changeset or + ** patchset instead of a NULL value. This allows such changesets to be + ** manipulated by legacy implementations of sqlite3changeset_invert(), + ** concat() and similar. + ** + ** The sqlite3changeset_apply() function automatically converts the + ** zero-length blob back to a NULL value when updating the sqlite_stat1 + ** table. However, if the application calls sqlite3changeset_new(), + ** sqlite3changeset_old() or sqlite3changeset_conflict on a changeset + ** iterator directly (including on a changeset iterator passed to a + ** conflict-handler callback) then the X'' value is returned. The application + ** must translate X'' to NULL itself if required. + ** + ** Legacy (older than 3.22.0) versions of the sessions module cannot capture + ** changes made to the sqlite_stat1 table. Legacy versions of the + ** sqlite3changeset_apply() function silently ignore any modifications to the + ** sqlite_stat1 table that are part of a changeset or patchset. + */ + SQLITE_API int sqlite3session_attach(sqlite3_session* pSession, /* Session object */ + const char* zTab /* Table name */ + ); + + /* + ** CAPI3REF: Set a table filter on a Session Object. + ** METHOD: sqlite3_session + ** + ** The second argument (xFilter) is the "filter callback". For changes to rows + ** in tables that are not attached to the Session object, the filter is called + ** to determine whether changes to the table's rows should be tracked or not. + ** If xFilter returns 0, changes are not tracked. Note that once a table is + ** attached, xFilter will not be called again. + */ + SQLITE_API void sqlite3session_table_filter(sqlite3_session* pSession, /* Session object */ + int (*xFilter)(void* pCtx, /* Copy of third arg to _filter_table() */ + const char* zTab /* Table name */ + ), + void* pCtx /* First argument passed to xFilter */ + ); + + /* + ** CAPI3REF: Generate A Changeset From A Session Object + ** METHOD: sqlite3_session + ** + ** Obtain a changeset containing changes to the tables attached to the + ** session object passed as the first argument. If successful, + ** set *ppChangeset to point to a buffer containing the changeset + ** and *pnChangeset to the size of the changeset in bytes before returning + ** SQLITE_OK. If an error occurs, set both *ppChangeset and *pnChangeset to + ** zero and return an SQLite error code. + ** + ** A changeset consists of zero or more INSERT, UPDATE and/or DELETE changes, + ** each representing a change to a single row of an attached table. An INSERT + ** change contains the values of each field of a new database row. A DELETE + ** contains the original values of each field of a deleted database row. An + ** UPDATE change contains the original values of each field of an updated + ** database row along with the updated values for each updated non-primary-key + ** column. It is not possible for an UPDATE change to represent a change that + ** modifies the values of primary key columns. If such a change is made, it + ** is represented in a changeset as a DELETE followed by an INSERT. + ** + ** Changes are not recorded for rows that have NULL values stored in one or + ** more of their PRIMARY KEY columns. If such a row is inserted or deleted, + ** no corresponding change is present in the changesets returned by this + ** function. If an existing row with one or more NULL values stored in + ** PRIMARY KEY columns is updated so that all PRIMARY KEY columns are non-NULL, + ** only an INSERT is appears in the changeset. Similarly, if an existing row + ** with non-NULL PRIMARY KEY values is updated so that one or more of its + ** PRIMARY KEY columns are set to NULL, the resulting changeset contains a + ** DELETE change only. + ** + ** The contents of a changeset may be traversed using an iterator created + ** using the [sqlite3changeset_start()] API. A changeset may be applied to + ** a database with a compatible schema using the [sqlite3changeset_apply()] + ** API. + ** + ** Within a changeset generated by this function, all changes related to a + ** single table are grouped together. In other words, when iterating through + ** a changeset or when applying a changeset to a database, all changes related + ** to a single table are processed before moving on to the next table. Tables + ** are sorted in the same order in which they were attached (or auto-attached) + ** to the sqlite3_session object. The order in which the changes related to + ** a single table are stored is undefined. + ** + ** Following a successful call to this function, it is the responsibility of + ** the caller to eventually free the buffer that *ppChangeset points to using + ** [sqlite3_free()]. + ** + **

Changeset Generation

+ ** + ** Once a table has been attached to a session object, the session object + ** records the primary key values of all new rows inserted into the table. + ** It also records the original primary key and other column values of any + ** deleted or updated rows. For each unique primary key value, data is only + ** recorded once - the first time a row with said primary key is inserted, + ** updated or deleted in the lifetime of the session. + ** + ** There is one exception to the previous paragraph: when a row is inserted, + ** updated or deleted, if one or more of its primary key columns contain a + ** NULL value, no record of the change is made. + ** + ** The session object therefore accumulates two types of records - those + ** that consist of primary key values only (created when the user inserts + ** a new record) and those that consist of the primary key values and the + ** original values of other table columns (created when the users deletes + ** or updates a record). + ** + ** When this function is called, the requested changeset is created using + ** both the accumulated records and the current contents of the database + ** file. Specifically: + ** + **
    + **
  • For each record generated by an insert, the database is queried + ** for a row with a matching primary key. If one is found, an INSERT + ** change is added to the changeset. If no such row is found, no change + ** is added to the changeset. + ** + **
  • For each record generated by an update or delete, the database is + ** queried for a row with a matching primary key. If such a row is + ** found and one or more of the non-primary key fields have been + ** modified from their original values, an UPDATE change is added to + ** the changeset. Or, if no such row is found in the table, a DELETE + ** change is added to the changeset. If there is a row with a matching + ** primary key in the database, but all fields contain their original + ** values, no change is added to the changeset. + **
+ ** + ** This means, amongst other things, that if a row is inserted and then later + ** deleted while a session object is active, neither the insert nor the delete + ** will be present in the changeset. Or if a row is deleted and then later a + ** row with the same primary key values inserted while a session object is + ** active, the resulting changeset will contain an UPDATE change instead of + ** a DELETE and an INSERT. + ** + ** When a session object is disabled (see the [sqlite3session_enable()] API), + ** it does not accumulate records when rows are inserted, updated or deleted. + ** This may appear to have some counter-intuitive effects if a single row + ** is written to more than once during a session. For example, if a row + ** is inserted while a session object is enabled, then later deleted while + ** the same session object is disabled, no INSERT record will appear in the + ** changeset, even though the delete took place while the session was disabled. + ** Or, if one field of a row is updated while a session is disabled, and + ** another field of the same row is updated while the session is enabled, the + ** resulting changeset will contain an UPDATE change that updates both fields. + */ + SQLITE_API int sqlite3session_changeset(sqlite3_session* pSession, /* Session object */ + int* pnChangeset, /* OUT: Size of buffer at *ppChangeset */ + void** ppChangeset /* OUT: Buffer containing changeset */ + ); + + /* + ** CAPI3REF: Return An Upper-limit For The Size Of The Changeset + ** METHOD: sqlite3_session + ** + ** By default, this function always returns 0. For it to return + ** a useful result, the sqlite3_session object must have been configured + ** to enable this API using sqlite3session_object_config() with the + ** SQLITE_SESSION_OBJCONFIG_SIZE verb. + ** + ** When enabled, this function returns an upper limit, in bytes, for the size + ** of the changeset that might be produced if sqlite3session_changeset() were + ** called. The final changeset size might be equal to or smaller than the + ** size in bytes returned by this function. + */ + SQLITE_API sqlite3_int64 sqlite3session_changeset_size(sqlite3_session* pSession); + + /* + ** CAPI3REF: Load The Difference Between Tables Into A Session + ** METHOD: sqlite3_session + ** + ** If it is not already attached to the session object passed as the first + ** argument, this function attaches table zTbl in the same manner as the + ** [sqlite3session_attach()] function. If zTbl does not exist, or if it + ** does not have a primary key, this function is a no-op (but does not return + ** an error). + ** + ** Argument zFromDb must be the name of a database ("main", "temp" etc.) + ** attached to the same database handle as the session object that contains + ** a table compatible with the table attached to the session by this function. + ** A table is considered compatible if it: + ** + **
    + **
  • Has the same name, + **
  • Has the same set of columns declared in the same order, and + **
  • Has the same PRIMARY KEY definition. + **
+ ** + ** If the tables are not compatible, SQLITE_SCHEMA is returned. If the tables + ** are compatible but do not have any PRIMARY KEY columns, it is not an error + ** but no changes are added to the session object. As with other session + ** APIs, tables without PRIMARY KEYs are simply ignored. + ** + ** This function adds a set of changes to the session object that could be + ** used to update the table in database zFrom (call this the "from-table") + ** so that its content is the same as the table attached to the session + ** object (call this the "to-table"). Specifically: + ** + **
    + **
  • For each row (primary key) that exists in the to-table but not in + ** the from-table, an INSERT record is added to the session object. + ** + **
  • For each row (primary key) that exists in the to-table but not in + ** the from-table, a DELETE record is added to the session object. + ** + **
  • For each row (primary key) that exists in both tables, but features + ** different non-PK values in each, an UPDATE record is added to the + ** session. + **
+ ** + ** To clarify, if this function is called and then a changeset constructed + ** using [sqlite3session_changeset()], then after applying that changeset to + ** database zFrom the contents of the two compatible tables would be + ** identical. + ** + ** It an error if database zFrom does not exist or does not contain the + ** required compatible table. + ** + ** If the operation is successful, SQLITE_OK is returned. Otherwise, an SQLite + ** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg + ** may be set to point to a buffer containing an English language error + ** message. It is the responsibility of the caller to free this buffer using + ** sqlite3_free(). + */ + SQLITE_API int + sqlite3session_diff(sqlite3_session* pSession, const char* zFromDb, const char* zTbl, char** pzErrMsg); + + /* + ** CAPI3REF: Generate A Patchset From A Session Object + ** METHOD: sqlite3_session + ** + ** The differences between a patchset and a changeset are that: + ** + **
    + **
  • DELETE records consist of the primary key fields only. The + ** original values of other fields are omitted. + **
  • The original values of any modified fields are omitted from + ** UPDATE records. + **
+ ** + ** A patchset blob may be used with up to date versions of all + ** sqlite3changeset_xxx API functions except for sqlite3changeset_invert(), + ** which returns SQLITE_CORRUPT if it is passed a patchset. Similarly, + ** attempting to use a patchset blob with old versions of the + ** sqlite3changeset_xxx APIs also provokes an SQLITE_CORRUPT error. + ** + ** Because the non-primary key "old.*" fields are omitted, no + ** SQLITE_CHANGESET_DATA conflicts can be detected or reported if a patchset + ** is passed to the sqlite3changeset_apply() API. Other conflict types work + ** in the same way as for changesets. + ** + ** Changes within a patchset are ordered in the same way as for changesets + ** generated by the sqlite3session_changeset() function (i.e. all changes for + ** a single table are grouped together, tables appear in the order in which + ** they were attached to the session object). + */ + SQLITE_API int sqlite3session_patchset(sqlite3_session* pSession, /* Session object */ + int* pnPatchset, /* OUT: Size of buffer at *ppPatchset */ + void** ppPatchset /* OUT: Buffer containing patchset */ + ); + + /* + ** CAPI3REF: Test if a changeset has recorded any changes. + ** + ** Return non-zero if no changes to attached tables have been recorded by + ** the session object passed as the first argument. Otherwise, if one or + ** more changes have been recorded, return zero. + ** + ** Even if this function returns zero, it is possible that calling + ** [sqlite3session_changeset()] on the session handle may still return a + ** changeset that contains no changes. This can happen when a row in + ** an attached table is modified and then later on the original values + ** are restored. However, if this function returns non-zero, then it is + ** guaranteed that a call to sqlite3session_changeset() will return a + ** changeset containing zero changes. + */ + SQLITE_API int sqlite3session_isempty(sqlite3_session* pSession); + + /* + ** CAPI3REF: Query for the amount of heap memory used by a session object. + ** + ** This API returns the total amount of heap memory in bytes currently + ** used by the session object passed as the only argument. + */ + SQLITE_API sqlite3_int64 sqlite3session_memory_used(sqlite3_session* pSession); + + /* + ** CAPI3REF: Create An Iterator To Traverse A Changeset + ** CONSTRUCTOR: sqlite3_changeset_iter + ** + ** Create an iterator used to iterate through the contents of a changeset. + ** If successful, *pp is set to point to the iterator handle and SQLITE_OK + ** is returned. Otherwise, if an error occurs, *pp is set to zero and an + ** SQLite error code is returned. + ** + ** The following functions can be used to advance and query a changeset + ** iterator created by this function: + ** + **
    + **
  • [sqlite3changeset_next()] + **
  • [sqlite3changeset_op()] + **
  • [sqlite3changeset_new()] + **
  • [sqlite3changeset_old()] + **
+ ** + ** It is the responsibility of the caller to eventually destroy the iterator + ** by passing it to [sqlite3changeset_finalize()]. The buffer containing the + ** changeset (pChangeset) must remain valid until after the iterator is + ** destroyed. + ** + ** Assuming the changeset blob was created by one of the + ** [sqlite3session_changeset()], [sqlite3changeset_concat()] or + ** [sqlite3changeset_invert()] functions, all changes within the changeset + ** that apply to a single table are grouped together. This means that when + ** an application iterates through a changeset using an iterator created by + ** this function, all changes that relate to a single table are visited + ** consecutively. There is no chance that the iterator will visit a change + ** the applies to table X, then one for table Y, and then later on visit + ** another change for table X. + ** + ** The behavior of sqlite3changeset_start_v2() and its streaming equivalent + ** may be modified by passing a combination of + ** [SQLITE_CHANGESETSTART_INVERT | supported flags] as the 4th parameter. + ** + ** Note that the sqlite3changeset_start_v2() API is still experimental + ** and therefore subject to change. + */ + SQLITE_API int sqlite3changeset_start(sqlite3_changeset_iter** pp, /* OUT: New changeset iterator handle */ + int nChangeset, /* Size of changeset blob in bytes */ + void* pChangeset /* Pointer to blob containing changeset */ + ); + SQLITE_API int sqlite3changeset_start_v2(sqlite3_changeset_iter** pp, /* OUT: New changeset iterator handle */ + int nChangeset, /* Size of changeset blob in bytes */ + void* pChangeset, /* Pointer to blob containing changeset */ + int flags /* SESSION_CHANGESETSTART_* flags */ + ); /* -** CAPI3REF: Apply A Changeset To A Database -** -** Apply a changeset or patchset to a database. These functions attempt to -** update the "main" database attached to handle db with the changes found in -** the changeset passed via the second and third arguments. -** -** The fourth argument (xFilter) passed to these functions is the "filter -** callback". If it is not NULL, then for each table affected by at least one -** change in the changeset, the filter callback is invoked with -** the table name as the second argument, and a copy of the context pointer -** passed as the sixth argument as the first. If the "filter callback" -** returns zero, then no attempt is made to apply any changes to the table. -** Otherwise, if the return value is non-zero or the xFilter argument to -** is NULL, all changes related to the table are attempted. -** -** For each table that is not excluded by the filter callback, this function -** tests that the target database contains a compatible table. A table is -** considered compatible if all of the following are true: -** -**
    -**
  • The table has the same name as the name recorded in the -** changeset, and -**
  • The table has at least as many columns as recorded in the -** changeset, and -**
  • The table has primary key columns in the same position as -** recorded in the changeset. -**
-** -** If there is no compatible table, it is not an error, but none of the -** changes associated with the table are applied. A warning message is issued -** via the sqlite3_log() mechanism with the error code SQLITE_SCHEMA. At most -** one such warning is issued for each table in the changeset. -** -** For each change for which there is a compatible table, an attempt is made -** to modify the table contents according to the UPDATE, INSERT or DELETE -** change. If a change cannot be applied cleanly, the conflict handler -** function passed as the fifth argument to sqlite3changeset_apply() may be -** invoked. A description of exactly when the conflict handler is invoked for -** each type of change is below. -** -** Unlike the xFilter argument, xConflict may not be passed NULL. The results -** of passing anything other than a valid function pointer as the xConflict -** argument are undefined. -** -** Each time the conflict handler function is invoked, it must return one -** of [SQLITE_CHANGESET_OMIT], [SQLITE_CHANGESET_ABORT] or -** [SQLITE_CHANGESET_REPLACE]. SQLITE_CHANGESET_REPLACE may only be returned -** if the second argument passed to the conflict handler is either -** SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If the conflict-handler -** returns an illegal value, any changes already made are rolled back and -** the call to sqlite3changeset_apply() returns SQLITE_MISUSE. Different -** actions are taken by sqlite3changeset_apply() depending on the value -** returned by each invocation of the conflict-handler function. Refer to -** the documentation for the three -** [SQLITE_CHANGESET_OMIT|available return values] for details. +** CAPI3REF: Flags for sqlite3changeset_start_v2 ** -**
-**
DELETE Changes
-** For each DELETE change, the function checks if the target database -** contains a row with the same primary key value (or values) as the -** original row values stored in the changeset. If it does, and the values -** stored in all non-primary key columns also match the values stored in -** the changeset the row is deleted from the target database. -** -** If a row with matching primary key values is found, but one or more of -** the non-primary key fields contains a value different from the original -** row value stored in the changeset, the conflict-handler function is -** invoked with [SQLITE_CHANGESET_DATA] as the second argument. If the -** database table has more columns than are recorded in the changeset, -** only the values of those non-primary key fields are compared against -** the current database contents - any trailing database table columns -** are ignored. -** -** If no row with matching primary key values is found in the database, -** the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND] -** passed as the second argument. -** -** If the DELETE operation is attempted, but SQLite returns SQLITE_CONSTRAINT -** (which can only happen if a foreign key constraint is violated), the -** conflict-handler function is invoked with [SQLITE_CHANGESET_CONSTRAINT] -** passed as the second argument. This includes the case where the DELETE -** operation is attempted because an earlier call to the conflict handler -** function returned [SQLITE_CHANGESET_REPLACE]. -** -**
INSERT Changes
-** For each INSERT change, an attempt is made to insert the new row into -** the database. If the changeset row contains fewer fields than the -** database table, the trailing fields are populated with their default -** values. -** -** If the attempt to insert the row fails because the database already -** contains a row with the same primary key values, the conflict handler -** function is invoked with the second argument set to -** [SQLITE_CHANGESET_CONFLICT]. -** -** If the attempt to insert the row fails because of some other constraint -** violation (e.g. NOT NULL or UNIQUE), the conflict handler function is -** invoked with the second argument set to [SQLITE_CHANGESET_CONSTRAINT]. -** This includes the case where the INSERT operation is re-attempted because -** an earlier call to the conflict handler function returned -** [SQLITE_CHANGESET_REPLACE]. -** -**
UPDATE Changes
-** For each UPDATE change, the function checks if the target database -** contains a row with the same primary key value (or values) as the -** original row values stored in the changeset. If it does, and the values -** stored in all modified non-primary key columns also match the values -** stored in the changeset the row is updated within the target database. -** -** If a row with matching primary key values is found, but one or more of -** the modified non-primary key fields contains a value different from an -** original row value stored in the changeset, the conflict-handler function -** is invoked with [SQLITE_CHANGESET_DATA] as the second argument. Since -** UPDATE changes only contain values for non-primary key fields that are -** to be modified, only those fields need to match the original values to -** avoid the SQLITE_CHANGESET_DATA conflict-handler callback. -** -** If no row with matching primary key values is found in the database, -** the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND] -** passed as the second argument. -** -** If the UPDATE operation is attempted, but SQLite returns -** SQLITE_CONSTRAINT, the conflict-handler function is invoked with -** [SQLITE_CHANGESET_CONSTRAINT] passed as the second argument. -** This includes the case where the UPDATE operation is attempted after -** an earlier call to the conflict handler function returned -** [SQLITE_CHANGESET_REPLACE]. -**
+** The following flags may passed via the 4th parameter to +** [sqlite3changeset_start_v2] and [sqlite3changeset_start_v2_strm]: ** -** It is safe to execute SQL statements, including those that write to the -** table that the callback related to, from within the xConflict callback. -** This can be used to further customize the application's conflict -** resolution strategy. -** -** All changes made by these functions are enclosed in a savepoint transaction. -** If any other error (aside from a constraint failure when attempting to -** write to the target database) occurs, then the savepoint transaction is -** rolled back, restoring the target database to its original state, and an -** SQLite error code returned. -** -** If the output parameters (ppRebase) and (pnRebase) are non-NULL and -** the input is a changeset (not a patchset), then sqlite3changeset_apply_v2() -** may set (*ppRebase) to point to a "rebase" that may be used with the -** sqlite3_rebaser APIs buffer before returning. In this case (*pnRebase) -** is set to the size of the buffer in bytes. It is the responsibility of the -** caller to eventually free any such buffer using sqlite3_free(). The buffer -** is only allocated and populated if one or more conflicts were encountered -** while applying the patchset. See comments surrounding the sqlite3_rebaser -** APIs for further details. -** -** The behavior of sqlite3changeset_apply_v2() and its streaming equivalent -** may be modified by passing a combination of -** [SQLITE_CHANGESETAPPLY_NOSAVEPOINT | supported flags] as the 9th parameter. -** -** Note that the sqlite3changeset_apply_v2() API is still experimental -** and therefore subject to change. +**
SQLITE_CHANGESETAPPLY_INVERT
+** Invert the changeset while iterating through it. This is equivalent to +** inverting a changeset using sqlite3changeset_invert() before applying it. +** It is an error to specify this flag with a patchset. */ -SQLITE_API int sqlite3changeset_apply( - sqlite3 *db, /* Apply change to "main" db of this handle */ - int nChangeset, /* Size of changeset in bytes */ - void *pChangeset, /* Changeset blob */ - int(*xFilter)( - void *pCtx, /* Copy of sixth arg to _apply() */ - const char *zTab /* Table name */ - ), - int(*xConflict)( - void *pCtx, /* Copy of sixth arg to _apply() */ - int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ - sqlite3_changeset_iter *p /* Handle describing change and conflict */ - ), - void *pCtx /* First argument passed to xConflict */ -); -SQLITE_API int sqlite3changeset_apply_v2( - sqlite3 *db, /* Apply change to "main" db of this handle */ - int nChangeset, /* Size of changeset in bytes */ - void *pChangeset, /* Changeset blob */ - int(*xFilter)( - void *pCtx, /* Copy of sixth arg to _apply() */ - const char *zTab /* Table name */ - ), - int(*xConflict)( - void *pCtx, /* Copy of sixth arg to _apply() */ - int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ - sqlite3_changeset_iter *p /* Handle describing change and conflict */ - ), - void *pCtx, /* First argument passed to xConflict */ - void **ppRebase, int *pnRebase, /* OUT: Rebase data */ - int flags /* SESSION_CHANGESETAPPLY_* flags */ -); +#define SQLITE_CHANGESETSTART_INVERT 0x0002 + + /* + ** CAPI3REF: Advance A Changeset Iterator + ** METHOD: sqlite3_changeset_iter + ** + ** This function may only be used with iterators created by the function + ** [sqlite3changeset_start()]. If it is called on an iterator passed to + ** a conflict-handler callback by [sqlite3changeset_apply()], SQLITE_MISUSE + ** is returned and the call has no effect. + ** + ** Immediately after an iterator is created by sqlite3changeset_start(), it + ** does not point to any change in the changeset. Assuming the changeset + ** is not empty, the first call to this function advances the iterator to + ** point to the first change in the changeset. Each subsequent call advances + ** the iterator to point to the next change in the changeset (if any). If + ** no error occurs and the iterator points to a valid change after a call + ** to sqlite3changeset_next() has advanced it, SQLITE_ROW is returned. + ** Otherwise, if all changes in the changeset have already been visited, + ** SQLITE_DONE is returned. + ** + ** If an error occurs, an SQLite error code is returned. Possible error + ** codes include SQLITE_CORRUPT (if the changeset buffer is corrupt) or + ** SQLITE_NOMEM. + */ + SQLITE_API int sqlite3changeset_next(sqlite3_changeset_iter* pIter); + + /* + ** CAPI3REF: Obtain The Current Operation From A Changeset Iterator + ** METHOD: sqlite3_changeset_iter + ** + ** The pIter argument passed to this function may either be an iterator + ** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator + ** created by [sqlite3changeset_start()]. In the latter case, the most recent + ** call to [sqlite3changeset_next()] must have returned [SQLITE_ROW]. If this + ** is not the case, this function returns [SQLITE_MISUSE]. + ** + ** Arguments pOp, pnCol and pzTab may not be NULL. Upon return, three + ** outputs are set through these pointers: + ** + ** *pOp is set to one of [SQLITE_INSERT], [SQLITE_DELETE] or [SQLITE_UPDATE], + ** depending on the type of change that the iterator currently points to; + ** + ** *pnCol is set to the number of columns in the table affected by the change; and + ** + ** *pzTab is set to point to a nul-terminated utf-8 encoded string containing + ** the name of the table affected by the current change. The buffer remains + ** valid until either sqlite3changeset_next() is called on the iterator + ** or until the conflict-handler function returns. + ** + ** If pbIndirect is not NULL, then *pbIndirect is set to true (1) if the change + ** is an indirect change, or false (0) otherwise. See the documentation for + ** [sqlite3session_indirect()] for a description of direct and indirect + ** changes. + ** + ** If no error occurs, SQLITE_OK is returned. If an error does occur, an + ** SQLite error code is returned. The values of the output variables may not + ** be trusted in this case. + */ + SQLITE_API int sqlite3changeset_op(sqlite3_changeset_iter* pIter, /* Iterator object */ + const char** pzTab, /* OUT: Pointer to table name */ + int* pnCol, /* OUT: Number of columns in table */ + int* pOp, /* OUT: SQLITE_INSERT, DELETE or UPDATE */ + int* pbIndirect /* OUT: True for an 'indirect' change */ + ); + + /* + ** CAPI3REF: Obtain The Primary Key Definition Of A Table + ** METHOD: sqlite3_changeset_iter + ** + ** For each modified table, a changeset includes the following: + ** + **
    + **
  • The number of columns in the table, and + **
  • Which of those columns make up the tables PRIMARY KEY. + **
+ ** + ** This function is used to find which columns comprise the PRIMARY KEY of + ** the table modified by the change that iterator pIter currently points to. + ** If successful, *pabPK is set to point to an array of nCol entries, where + ** nCol is the number of columns in the table. Elements of *pabPK are set to + ** 0x01 if the corresponding column is part of the tables primary key, or + ** 0x00 if it is not. + ** + ** If argument pnCol is not NULL, then *pnCol is set to the number of columns + ** in the table. + ** + ** If this function is called when the iterator does not point to a valid + ** entry, SQLITE_MISUSE is returned and the output variables zeroed. Otherwise, + ** SQLITE_OK is returned and the output variables populated as described + ** above. + */ + SQLITE_API int sqlite3changeset_pk(sqlite3_changeset_iter* pIter, /* Iterator object */ + unsigned char** pabPK, /* OUT: Array of boolean - true for PK cols */ + int* pnCol /* OUT: Number of entries in output array */ + ); + + /* + ** CAPI3REF: Obtain old.* Values From A Changeset Iterator + ** METHOD: sqlite3_changeset_iter + ** + ** The pIter argument passed to this function may either be an iterator + ** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator + ** created by [sqlite3changeset_start()]. In the latter case, the most recent + ** call to [sqlite3changeset_next()] must have returned SQLITE_ROW. + ** Furthermore, it may only be called if the type of change that the iterator + ** currently points to is either [SQLITE_DELETE] or [SQLITE_UPDATE]. Otherwise, + ** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL. + ** + ** Argument iVal must be greater than or equal to 0, and less than the number + ** of columns in the table affected by the current change. Otherwise, + ** [SQLITE_RANGE] is returned and *ppValue is set to NULL. + ** + ** If successful, this function sets *ppValue to point to a protected + ** sqlite3_value object containing the iVal'th value from the vector of + ** original row values stored as part of the UPDATE or DELETE change and + ** returns SQLITE_OK. The name of the function comes from the fact that this + ** is similar to the "old.*" columns available to update or delete triggers. + ** + ** If some other error occurs (e.g. an OOM condition), an SQLite error code + ** is returned and *ppValue is set to NULL. + */ + SQLITE_API int sqlite3changeset_old(sqlite3_changeset_iter* pIter, /* Changeset iterator */ + int iVal, /* Column number */ + sqlite3_value** ppValue /* OUT: Old value (or NULL pointer) */ + ); + + /* + ** CAPI3REF: Obtain new.* Values From A Changeset Iterator + ** METHOD: sqlite3_changeset_iter + ** + ** The pIter argument passed to this function may either be an iterator + ** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator + ** created by [sqlite3changeset_start()]. In the latter case, the most recent + ** call to [sqlite3changeset_next()] must have returned SQLITE_ROW. + ** Furthermore, it may only be called if the type of change that the iterator + ** currently points to is either [SQLITE_UPDATE] or [SQLITE_INSERT]. Otherwise, + ** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL. + ** + ** Argument iVal must be greater than or equal to 0, and less than the number + ** of columns in the table affected by the current change. Otherwise, + ** [SQLITE_RANGE] is returned and *ppValue is set to NULL. + ** + ** If successful, this function sets *ppValue to point to a protected + ** sqlite3_value object containing the iVal'th value from the vector of + ** new row values stored as part of the UPDATE or INSERT change and + ** returns SQLITE_OK. If the change is an UPDATE and does not include + ** a new value for the requested column, *ppValue is set to NULL and + ** SQLITE_OK returned. The name of the function comes from the fact that + ** this is similar to the "new.*" columns available to update or delete + ** triggers. + ** + ** If some other error occurs (e.g. an OOM condition), an SQLite error code + ** is returned and *ppValue is set to NULL. + */ + SQLITE_API int sqlite3changeset_new(sqlite3_changeset_iter* pIter, /* Changeset iterator */ + int iVal, /* Column number */ + sqlite3_value** ppValue /* OUT: New value (or NULL pointer) */ + ); + + /* + ** CAPI3REF: Obtain Conflicting Row Values From A Changeset Iterator + ** METHOD: sqlite3_changeset_iter + ** + ** This function should only be used with iterator objects passed to a + ** conflict-handler callback by [sqlite3changeset_apply()] with either + ** [SQLITE_CHANGESET_DATA] or [SQLITE_CHANGESET_CONFLICT]. If this function + ** is called on any other iterator, [SQLITE_MISUSE] is returned and *ppValue + ** is set to NULL. + ** + ** Argument iVal must be greater than or equal to 0, and less than the number + ** of columns in the table affected by the current change. Otherwise, + ** [SQLITE_RANGE] is returned and *ppValue is set to NULL. + ** + ** If successful, this function sets *ppValue to point to a protected + ** sqlite3_value object containing the iVal'th value from the + ** "conflicting row" associated with the current conflict-handler callback + ** and returns SQLITE_OK. + ** + ** If some other error occurs (e.g. an OOM condition), an SQLite error code + ** is returned and *ppValue is set to NULL. + */ + SQLITE_API int sqlite3changeset_conflict(sqlite3_changeset_iter* pIter, /* Changeset iterator */ + int iVal, /* Column number */ + sqlite3_value** ppValue /* OUT: Value from conflicting row */ + ); + + /* + ** CAPI3REF: Determine The Number Of Foreign Key Constraint Violations + ** METHOD: sqlite3_changeset_iter + ** + ** This function may only be called with an iterator passed to an + ** SQLITE_CHANGESET_FOREIGN_KEY conflict handler callback. In this case + ** it sets the output variable to the total number of known foreign key + ** violations in the destination database and returns SQLITE_OK. + ** + ** In all other cases this function returns SQLITE_MISUSE. + */ + SQLITE_API int sqlite3changeset_fk_conflicts(sqlite3_changeset_iter* pIter, /* Changeset iterator */ + int* pnOut /* OUT: Number of FK violations */ + ); + + /* + ** CAPI3REF: Finalize A Changeset Iterator + ** METHOD: sqlite3_changeset_iter + ** + ** This function is used to finalize an iterator allocated with + ** [sqlite3changeset_start()]. + ** + ** This function should only be called on iterators created using the + ** [sqlite3changeset_start()] function. If an application calls this + ** function with an iterator passed to a conflict-handler by + ** [sqlite3changeset_apply()], [SQLITE_MISUSE] is immediately returned and the + ** call has no effect. + ** + ** If an error was encountered within a call to an sqlite3changeset_xxx() + ** function (for example an [SQLITE_CORRUPT] in [sqlite3changeset_next()] or an + ** [SQLITE_NOMEM] in [sqlite3changeset_new()]) then an error code corresponding + ** to that error is returned by this function. Otherwise, SQLITE_OK is + ** returned. This is to allow the following pattern (pseudo-code): + ** + **
+    **   sqlite3changeset_start();
+    **   while( SQLITE_ROW==sqlite3changeset_next() ){
+    **     // Do something with change.
+    **   }
+    **   rc = sqlite3changeset_finalize();
+    **   if( rc!=SQLITE_OK ){
+    **     // An error has occurred
+    **   }
+    ** 
+ */ + SQLITE_API int sqlite3changeset_finalize(sqlite3_changeset_iter* pIter); + + /* + ** CAPI3REF: Invert A Changeset + ** + ** This function is used to "invert" a changeset object. Applying an inverted + ** changeset to a database reverses the effects of applying the uninverted + ** changeset. Specifically: + ** + **
    + **
  • Each DELETE change is changed to an INSERT, and + **
  • Each INSERT change is changed to a DELETE, and + **
  • For each UPDATE change, the old.* and new.* values are exchanged. + **
+ ** + ** This function does not change the order in which changes appear within + ** the changeset. It merely reverses the sense of each individual change. + ** + ** If successful, a pointer to a buffer containing the inverted changeset + ** is stored in *ppOut, the size of the same buffer is stored in *pnOut, and + ** SQLITE_OK is returned. If an error occurs, both *pnOut and *ppOut are + ** zeroed and an SQLite error code returned. + ** + ** It is the responsibility of the caller to eventually call sqlite3_free() + ** on the *ppOut pointer to free the buffer allocation following a successful + ** call to this function. + ** + ** WARNING/TODO: This function currently assumes that the input is a valid + ** changeset. If it is not, the results are undefined. + */ + SQLITE_API int sqlite3changeset_invert(int nIn, + const void* pIn, /* Input changeset */ + int* pnOut, + void** ppOut /* OUT: Inverse of input */ + ); + + /* + ** CAPI3REF: Concatenate Two Changeset Objects + ** + ** This function is used to concatenate two changesets, A and B, into a + ** single changeset. The result is a changeset equivalent to applying + ** changeset A followed by changeset B. + ** + ** This function combines the two input changesets using an + ** sqlite3_changegroup object. Calling it produces similar results as the + ** following code fragment: + ** + **
+    **   sqlite3_changegroup *pGrp;
+    **   rc = sqlite3_changegroup_new(&pGrp);
+    **   if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nA, pA);
+    **   if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nB, pB);
+    **   if( rc==SQLITE_OK ){
+    **     rc = sqlite3changegroup_output(pGrp, pnOut, ppOut);
+    **   }else{
+    **     *ppOut = 0;
+    **     *pnOut = 0;
+    **   }
+    ** 
+ ** + ** Refer to the sqlite3_changegroup documentation below for details. + */ + SQLITE_API int sqlite3changeset_concat(int nA, /* Number of bytes in buffer pA */ + void* pA, /* Pointer to buffer containing changeset A */ + int nB, /* Number of bytes in buffer pB */ + void* pB, /* Pointer to buffer containing changeset B */ + int* pnOut, /* OUT: Number of bytes in output changeset */ + void** ppOut /* OUT: Buffer containing output changeset */ + ); + + /* + ** CAPI3REF: Changegroup Handle + ** + ** A changegroup is an object used to combine two or more + ** [changesets] or [patchsets] + */ + typedef struct sqlite3_changegroup sqlite3_changegroup; + + /* + ** CAPI3REF: Create A New Changegroup Object + ** CONSTRUCTOR: sqlite3_changegroup + ** + ** An sqlite3_changegroup object is used to combine two or more changesets + ** (or patchsets) into a single changeset (or patchset). A single changegroup + ** object may combine changesets or patchsets, but not both. The output is + ** always in the same format as the input. + ** + ** If successful, this function returns SQLITE_OK and populates (*pp) with + ** a pointer to a new sqlite3_changegroup object before returning. The caller + ** should eventually free the returned object using a call to + ** sqlite3changegroup_delete(). If an error occurs, an SQLite error code + ** (i.e. SQLITE_NOMEM) is returned and *pp is set to NULL. + ** + ** The usual usage pattern for an sqlite3_changegroup object is as follows: + ** + **
    + **
  • It is created using a call to sqlite3changegroup_new(). + ** + **
  • Zero or more changesets (or patchsets) are added to the object + ** by calling sqlite3changegroup_add(). + ** + **
  • The result of combining all input changesets together is obtained + ** by the application via a call to sqlite3changegroup_output(). + ** + **
  • The object is deleted using a call to sqlite3changegroup_delete(). + **
+ ** + ** Any number of calls to add() and output() may be made between the calls to + ** new() and delete(), and in any order. + ** + ** As well as the regular sqlite3changegroup_add() and + ** sqlite3changegroup_output() functions, also available are the streaming + ** versions sqlite3changegroup_add_strm() and sqlite3changegroup_output_strm(). + */ + SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup** pp); + + /* + ** CAPI3REF: Add A Changeset To A Changegroup + ** METHOD: sqlite3_changegroup + ** + ** Add all changes within the changeset (or patchset) in buffer pData (size + ** nData bytes) to the changegroup. + ** + ** If the buffer contains a patchset, then all prior calls to this function + ** on the same changegroup object must also have specified patchsets. Or, if + ** the buffer contains a changeset, so must have the earlier calls to this + ** function. Otherwise, SQLITE_ERROR is returned and no changes are added + ** to the changegroup. + ** + ** Rows within the changeset and changegroup are identified by the values in + ** their PRIMARY KEY columns. A change in the changeset is considered to + ** apply to the same row as a change already present in the changegroup if + ** the two rows have the same primary key. + ** + ** Changes to rows that do not already appear in the changegroup are + ** simply copied into it. Or, if both the new changeset and the changegroup + ** contain changes that apply to a single row, the final contents of the + ** changegroup depends on the type of each change, as follows: + ** + ** + ** + ** + **
Existing Change New Change Output Change + **
INSERT INSERT + ** The new change is ignored. This case does not occur if the new + ** changeset was recorded immediately after the changesets already + ** added to the changegroup. + **
INSERT UPDATE + ** The INSERT change remains in the changegroup. The values in the + ** INSERT change are modified as if the row was inserted by the + ** existing change and then updated according to the new change. + **
INSERT DELETE + ** The existing INSERT is removed from the changegroup. The DELETE is + ** not added. + **
UPDATE INSERT + ** The new change is ignored. This case does not occur if the new + ** changeset was recorded immediately after the changesets already + ** added to the changegroup. + **
UPDATE UPDATE + ** The existing UPDATE remains within the changegroup. It is amended + ** so that the accompanying values are as if the row was updated once + ** by the existing change and then again by the new change. + **
UPDATE DELETE + ** The existing UPDATE is replaced by the new DELETE within the + ** changegroup. + **
DELETE INSERT + ** If one or more of the column values in the row inserted by the + ** new change differ from those in the row deleted by the existing + ** change, the existing DELETE is replaced by an UPDATE within the + ** changegroup. Otherwise, if the inserted row is exactly the same + ** as the deleted row, the existing DELETE is simply discarded. + **
DELETE UPDATE + ** The new change is ignored. This case does not occur if the new + ** changeset was recorded immediately after the changesets already + ** added to the changegroup. + **
DELETE DELETE + ** The new change is ignored. This case does not occur if the new + ** changeset was recorded immediately after the changesets already + ** added to the changegroup. + **
+ ** + ** If the new changeset contains changes to a table that is already present + ** in the changegroup, then the number of columns and the position of the + ** primary key columns for the table must be consistent. If this is not the + ** case, this function fails with SQLITE_SCHEMA. If the input changeset + ** appears to be corrupt and the corruption is detected, SQLITE_CORRUPT is + ** returned. Or, if an out-of-memory condition occurs during processing, this + ** function returns SQLITE_NOMEM. In all cases, if an error occurs the state + ** of the final contents of the changegroup is undefined. + ** + ** If no error occurs, SQLITE_OK is returned. + */ + SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void* pData); + + /* + ** CAPI3REF: Obtain A Composite Changeset From A Changegroup + ** METHOD: sqlite3_changegroup + ** + ** Obtain a buffer containing a changeset (or patchset) representing the + ** current contents of the changegroup. If the inputs to the changegroup + ** were themselves changesets, the output is a changeset. Or, if the + ** inputs were patchsets, the output is also a patchset. + ** + ** As with the output of the sqlite3session_changeset() and + ** sqlite3session_patchset() functions, all changes related to a single + ** table are grouped together in the output of this function. Tables appear + ** in the same order as for the very first changeset added to the changegroup. + ** If the second or subsequent changesets added to the changegroup contain + ** changes for tables that do not appear in the first changeset, they are + ** appended onto the end of the output changeset, again in the order in + ** which they are first encountered. + ** + ** If an error occurs, an SQLite error code is returned and the output + ** variables (*pnData) and (*ppData) are set to 0. Otherwise, SQLITE_OK + ** is returned and the output variables are set to the size of and a + ** pointer to the output buffer, respectively. In this case it is the + ** responsibility of the caller to eventually free the buffer using a + ** call to sqlite3_free(). + */ + SQLITE_API int sqlite3changegroup_output(sqlite3_changegroup*, + int* pnData, /* OUT: Size of output buffer in bytes */ + void** ppData /* OUT: Pointer to output buffer */ + ); + + /* + ** CAPI3REF: Delete A Changegroup Object + ** DESTRUCTOR: sqlite3_changegroup + */ + SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*); + + /* + ** CAPI3REF: Apply A Changeset To A Database + ** + ** Apply a changeset or patchset to a database. These functions attempt to + ** update the "main" database attached to handle db with the changes found in + ** the changeset passed via the second and third arguments. + ** + ** The fourth argument (xFilter) passed to these functions is the "filter + ** callback". If it is not NULL, then for each table affected by at least one + ** change in the changeset, the filter callback is invoked with + ** the table name as the second argument, and a copy of the context pointer + ** passed as the sixth argument as the first. If the "filter callback" + ** returns zero, then no attempt is made to apply any changes to the table. + ** Otherwise, if the return value is non-zero or the xFilter argument to + ** is NULL, all changes related to the table are attempted. + ** + ** For each table that is not excluded by the filter callback, this function + ** tests that the target database contains a compatible table. A table is + ** considered compatible if all of the following are true: + ** + **
    + **
  • The table has the same name as the name recorded in the + ** changeset, and + **
  • The table has at least as many columns as recorded in the + ** changeset, and + **
  • The table has primary key columns in the same position as + ** recorded in the changeset. + **
+ ** + ** If there is no compatible table, it is not an error, but none of the + ** changes associated with the table are applied. A warning message is issued + ** via the sqlite3_log() mechanism with the error code SQLITE_SCHEMA. At most + ** one such warning is issued for each table in the changeset. + ** + ** For each change for which there is a compatible table, an attempt is made + ** to modify the table contents according to the UPDATE, INSERT or DELETE + ** change. If a change cannot be applied cleanly, the conflict handler + ** function passed as the fifth argument to sqlite3changeset_apply() may be + ** invoked. A description of exactly when the conflict handler is invoked for + ** each type of change is below. + ** + ** Unlike the xFilter argument, xConflict may not be passed NULL. The results + ** of passing anything other than a valid function pointer as the xConflict + ** argument are undefined. + ** + ** Each time the conflict handler function is invoked, it must return one + ** of [SQLITE_CHANGESET_OMIT], [SQLITE_CHANGESET_ABORT] or + ** [SQLITE_CHANGESET_REPLACE]. SQLITE_CHANGESET_REPLACE may only be returned + ** if the second argument passed to the conflict handler is either + ** SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If the conflict-handler + ** returns an illegal value, any changes already made are rolled back and + ** the call to sqlite3changeset_apply() returns SQLITE_MISUSE. Different + ** actions are taken by sqlite3changeset_apply() depending on the value + ** returned by each invocation of the conflict-handler function. Refer to + ** the documentation for the three + ** [SQLITE_CHANGESET_OMIT|available return values] for details. + ** + **
+ **
DELETE Changes
+ ** For each DELETE change, the function checks if the target database + ** contains a row with the same primary key value (or values) as the + ** original row values stored in the changeset. If it does, and the values + ** stored in all non-primary key columns also match the values stored in + ** the changeset the row is deleted from the target database. + ** + ** If a row with matching primary key values is found, but one or more of + ** the non-primary key fields contains a value different from the original + ** row value stored in the changeset, the conflict-handler function is + ** invoked with [SQLITE_CHANGESET_DATA] as the second argument. If the + ** database table has more columns than are recorded in the changeset, + ** only the values of those non-primary key fields are compared against + ** the current database contents - any trailing database table columns + ** are ignored. + ** + ** If no row with matching primary key values is found in the database, + ** the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND] + ** passed as the second argument. + ** + ** If the DELETE operation is attempted, but SQLite returns SQLITE_CONSTRAINT + ** (which can only happen if a foreign key constraint is violated), the + ** conflict-handler function is invoked with [SQLITE_CHANGESET_CONSTRAINT] + ** passed as the second argument. This includes the case where the DELETE + ** operation is attempted because an earlier call to the conflict handler + ** function returned [SQLITE_CHANGESET_REPLACE]. + ** + **
INSERT Changes
+ ** For each INSERT change, an attempt is made to insert the new row into + ** the database. If the changeset row contains fewer fields than the + ** database table, the trailing fields are populated with their default + ** values. + ** + ** If the attempt to insert the row fails because the database already + ** contains a row with the same primary key values, the conflict handler + ** function is invoked with the second argument set to + ** [SQLITE_CHANGESET_CONFLICT]. + ** + ** If the attempt to insert the row fails because of some other constraint + ** violation (e.g. NOT NULL or UNIQUE), the conflict handler function is + ** invoked with the second argument set to [SQLITE_CHANGESET_CONSTRAINT]. + ** This includes the case where the INSERT operation is re-attempted because + ** an earlier call to the conflict handler function returned + ** [SQLITE_CHANGESET_REPLACE]. + ** + **
UPDATE Changes
+ ** For each UPDATE change, the function checks if the target database + ** contains a row with the same primary key value (or values) as the + ** original row values stored in the changeset. If it does, and the values + ** stored in all modified non-primary key columns also match the values + ** stored in the changeset the row is updated within the target database. + ** + ** If a row with matching primary key values is found, but one or more of + ** the modified non-primary key fields contains a value different from an + ** original row value stored in the changeset, the conflict-handler function + ** is invoked with [SQLITE_CHANGESET_DATA] as the second argument. Since + ** UPDATE changes only contain values for non-primary key fields that are + ** to be modified, only those fields need to match the original values to + ** avoid the SQLITE_CHANGESET_DATA conflict-handler callback. + ** + ** If no row with matching primary key values is found in the database, + ** the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND] + ** passed as the second argument. + ** + ** If the UPDATE operation is attempted, but SQLite returns + ** SQLITE_CONSTRAINT, the conflict-handler function is invoked with + ** [SQLITE_CHANGESET_CONSTRAINT] passed as the second argument. + ** This includes the case where the UPDATE operation is attempted after + ** an earlier call to the conflict handler function returned + ** [SQLITE_CHANGESET_REPLACE]. + **
+ ** + ** It is safe to execute SQL statements, including those that write to the + ** table that the callback related to, from within the xConflict callback. + ** This can be used to further customize the application's conflict + ** resolution strategy. + ** + ** All changes made by these functions are enclosed in a savepoint transaction. + ** If any other error (aside from a constraint failure when attempting to + ** write to the target database) occurs, then the savepoint transaction is + ** rolled back, restoring the target database to its original state, and an + ** SQLite error code returned. + ** + ** If the output parameters (ppRebase) and (pnRebase) are non-NULL and + ** the input is a changeset (not a patchset), then sqlite3changeset_apply_v2() + ** may set (*ppRebase) to point to a "rebase" that may be used with the + ** sqlite3_rebaser APIs buffer before returning. In this case (*pnRebase) + ** is set to the size of the buffer in bytes. It is the responsibility of the + ** caller to eventually free any such buffer using sqlite3_free(). The buffer + ** is only allocated and populated if one or more conflicts were encountered + ** while applying the patchset. See comments surrounding the sqlite3_rebaser + ** APIs for further details. + ** + ** The behavior of sqlite3changeset_apply_v2() and its streaming equivalent + ** may be modified by passing a combination of + ** [SQLITE_CHANGESETAPPLY_NOSAVEPOINT | supported flags] as the 9th parameter. + ** + ** Note that the sqlite3changeset_apply_v2() API is still experimental + ** and therefore subject to change. + */ + SQLITE_API int sqlite3changeset_apply(sqlite3* db, /* Apply change to "main" db of this handle */ + int nChangeset, /* Size of changeset in bytes */ + void* pChangeset, /* Changeset blob */ + int (*xFilter)(void* pCtx, /* Copy of sixth arg to _apply() */ + const char* zTab /* Table name */ + ), + int (*xConflict)(void* pCtx, /* Copy of sixth arg to _apply() */ + int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ + sqlite3_changeset_iter* p /* Handle describing change and + conflict */ + ), + void* pCtx /* First argument passed to xConflict */ + ); + SQLITE_API int sqlite3changeset_apply_v2(sqlite3* db, /* Apply change to "main" db of this handle */ + int nChangeset, /* Size of changeset in bytes */ + void* pChangeset, /* Changeset blob */ + int (*xFilter)(void* pCtx, /* Copy of sixth arg to _apply() */ + const char* zTab /* Table name */ + ), + int (*xConflict)(void* pCtx, /* Copy of sixth arg to _apply() */ + int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ + sqlite3_changeset_iter* p /* Handle describing change and + conflict */ + ), + void* pCtx, /* First argument passed to xConflict */ + void** ppRebase, + int* pnRebase, /* OUT: Rebase data */ + int flags /* SESSION_CHANGESETAPPLY_* flags */ + ); /* ** CAPI3REF: Flags for sqlite3changeset_apply_v2 @@ -11746,8 +11630,8 @@ SQLITE_API int sqlite3changeset_apply_v2( ** a changeset using sqlite3changeset_invert() before applying it. It is ** an error to specify this flag with a patchset. */ -#define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001 -#define SQLITE_CHANGESETAPPLY_INVERT 0x0002 +#define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001 +#define SQLITE_CHANGESETAPPLY_INVERT 0x0002 /* ** CAPI3REF: Constants Passed To The Conflict Handler @@ -11804,10 +11688,10 @@ SQLITE_API int sqlite3changeset_apply_v2( ** ** */ -#define SQLITE_CHANGESET_DATA 1 -#define SQLITE_CHANGESET_NOTFOUND 2 -#define SQLITE_CHANGESET_CONFLICT 3 -#define SQLITE_CHANGESET_CONSTRAINT 4 +#define SQLITE_CHANGESET_DATA 1 +#define SQLITE_CHANGESET_NOTFOUND 2 +#define SQLITE_CHANGESET_CONFLICT 3 +#define SQLITE_CHANGESET_CONSTRAINT 4 #define SQLITE_CHANGESET_FOREIGN_KEY 5 /* @@ -11841,372 +11725,345 @@ SQLITE_API int sqlite3changeset_apply_v2( ** and the call to sqlite3changeset_apply() returns SQLITE_ABORT. ** */ -#define SQLITE_CHANGESET_OMIT 0 -#define SQLITE_CHANGESET_REPLACE 1 -#define SQLITE_CHANGESET_ABORT 2 - -/* -** CAPI3REF: Rebasing changesets -** EXPERIMENTAL -** -** Suppose there is a site hosting a database in state S0. And that -** modifications are made that move that database to state S1 and a -** changeset recorded (the "local" changeset). Then, a changeset based -** on S0 is received from another site (the "remote" changeset) and -** applied to the database. The database is then in state -** (S1+"remote"), where the exact state depends on any conflict -** resolution decisions (OMIT or REPLACE) made while applying "remote". -** Rebasing a changeset is to update it to take those conflict -** resolution decisions into account, so that the same conflicts -** do not have to be resolved elsewhere in the network. -** -** For example, if both the local and remote changesets contain an -** INSERT of the same key on "CREATE TABLE t1(a PRIMARY KEY, b)": -** -** local: INSERT INTO t1 VALUES(1, 'v1'); -** remote: INSERT INTO t1 VALUES(1, 'v2'); -** -** and the conflict resolution is REPLACE, then the INSERT change is -** removed from the local changeset (it was overridden). Or, if the -** conflict resolution was "OMIT", then the local changeset is modified -** to instead contain: -** -** UPDATE t1 SET b = 'v2' WHERE a=1; -** -** Changes within the local changeset are rebased as follows: -** -**
-**
Local INSERT
-** This may only conflict with a remote INSERT. If the conflict -** resolution was OMIT, then add an UPDATE change to the rebased -** changeset. Or, if the conflict resolution was REPLACE, add -** nothing to the rebased changeset. -** -**
Local DELETE
-** This may conflict with a remote UPDATE or DELETE. In both cases the -** only possible resolution is OMIT. If the remote operation was a -** DELETE, then add no change to the rebased changeset. If the remote -** operation was an UPDATE, then the old.* fields of change are updated -** to reflect the new.* values in the UPDATE. -** -**
Local UPDATE
-** This may conflict with a remote UPDATE or DELETE. If it conflicts -** with a DELETE, and the conflict resolution was OMIT, then the update -** is changed into an INSERT. Any undefined values in the new.* record -** from the update change are filled in using the old.* values from -** the conflicting DELETE. Or, if the conflict resolution was REPLACE, -** the UPDATE change is simply omitted from the rebased changeset. -** -** If conflict is with a remote UPDATE and the resolution is OMIT, then -** the old.* values are rebased using the new.* values in the remote -** change. Or, if the resolution is REPLACE, then the change is copied -** into the rebased changeset with updates to columns also updated by -** the conflicting remote UPDATE removed. If this means no columns would -** be updated, the change is omitted. -**
-** -** A local change may be rebased against multiple remote changes -** simultaneously. If a single key is modified by multiple remote -** changesets, they are combined as follows before the local changeset -** is rebased: -** -**
    -**
  • If there has been one or more REPLACE resolutions on a -** key, it is rebased according to a REPLACE. -** -**
  • If there have been no REPLACE resolutions on a key, then -** the local changeset is rebased according to the most recent -** of the OMIT resolutions. -**
-** -** Note that conflict resolutions from multiple remote changesets are -** combined on a per-field basis, not per-row. This means that in the -** case of multiple remote UPDATE operations, some fields of a single -** local change may be rebased for REPLACE while others are rebased for -** OMIT. -** -** In order to rebase a local changeset, the remote changeset must first -** be applied to the local database using sqlite3changeset_apply_v2() and -** the buffer of rebase information captured. Then: -** -**
    -**
  1. An sqlite3_rebaser object is created by calling -** sqlite3rebaser_create(). -**
  2. The new object is configured with the rebase buffer obtained from -** sqlite3changeset_apply_v2() by calling sqlite3rebaser_configure(). -** If the local changeset is to be rebased against multiple remote -** changesets, then sqlite3rebaser_configure() should be called -** multiple times, in the same order that the multiple -** sqlite3changeset_apply_v2() calls were made. -**
  3. Each local changeset is rebased by calling sqlite3rebaser_rebase(). -**
  4. The sqlite3_rebaser object is deleted by calling -** sqlite3rebaser_delete(). -**
-*/ -typedef struct sqlite3_rebaser sqlite3_rebaser; - -/* -** CAPI3REF: Create a changeset rebaser object. -** EXPERIMENTAL -** -** Allocate a new changeset rebaser object. If successful, set (*ppNew) to -** point to the new object and return SQLITE_OK. Otherwise, if an error -** occurs, return an SQLite error code (e.g. SQLITE_NOMEM) and set (*ppNew) -** to NULL. -*/ -SQLITE_API int sqlite3rebaser_create(sqlite3_rebaser **ppNew); - -/* -** CAPI3REF: Configure a changeset rebaser object. -** EXPERIMENTAL -** -** Configure the changeset rebaser object to rebase changesets according -** to the conflict resolutions described by buffer pRebase (size nRebase -** bytes), which must have been obtained from a previous call to -** sqlite3changeset_apply_v2(). -*/ -SQLITE_API int sqlite3rebaser_configure( - sqlite3_rebaser*, - int nRebase, const void *pRebase -); - -/* -** CAPI3REF: Rebase a changeset -** EXPERIMENTAL -** -** Argument pIn must point to a buffer containing a changeset nIn bytes -** in size. This function allocates and populates a buffer with a copy -** of the changeset rebased according to the configuration of the -** rebaser object passed as the first argument. If successful, (*ppOut) -** is set to point to the new buffer containing the rebased changeset and -** (*pnOut) to its size in bytes and SQLITE_OK returned. It is the -** responsibility of the caller to eventually free the new buffer using -** sqlite3_free(). Otherwise, if an error occurs, (*ppOut) and (*pnOut) -** are set to zero and an SQLite error code returned. -*/ -SQLITE_API int sqlite3rebaser_rebase( - sqlite3_rebaser*, - int nIn, const void *pIn, - int *pnOut, void **ppOut -); - -/* -** CAPI3REF: Delete a changeset rebaser object. -** EXPERIMENTAL -** -** Delete the changeset rebaser object and all associated resources. There -** should be one call to this function for each successful invocation -** of sqlite3rebaser_create(). -*/ -SQLITE_API void sqlite3rebaser_delete(sqlite3_rebaser *p); - -/* -** CAPI3REF: Streaming Versions of API functions. -** -** The six streaming API xxx_strm() functions serve similar purposes to the -** corresponding non-streaming API functions: -** -** -** -**
Streaming functionNon-streaming equivalent
sqlite3changeset_apply_strm[sqlite3changeset_apply] -**
sqlite3changeset_apply_strm_v2[sqlite3changeset_apply_v2] -**
sqlite3changeset_concat_strm[sqlite3changeset_concat] -**
sqlite3changeset_invert_strm[sqlite3changeset_invert] -**
sqlite3changeset_start_strm[sqlite3changeset_start] -**
sqlite3session_changeset_strm[sqlite3session_changeset] -**
sqlite3session_patchset_strm[sqlite3session_patchset] -**
-** -** Non-streaming functions that accept changesets (or patchsets) as input -** require that the entire changeset be stored in a single buffer in memory. -** Similarly, those that return a changeset or patchset do so by returning -** a pointer to a single large buffer allocated using sqlite3_malloc(). -** Normally this is convenient. However, if an application running in a -** low-memory environment is required to handle very large changesets, the -** large contiguous memory allocations required can become onerous. -** -** In order to avoid this problem, instead of a single large buffer, input -** is passed to a streaming API functions by way of a callback function that -** the sessions module invokes to incrementally request input data as it is -** required. In all cases, a pair of API function parameters such as -** -**
-**        int nChangeset,
-**        void *pChangeset,
-**  
-** -** Is replaced by: -** -**
-**        int (*xInput)(void *pIn, void *pData, int *pnData),
-**        void *pIn,
-**  
-** -** Each time the xInput callback is invoked by the sessions module, the first -** argument passed is a copy of the supplied pIn context pointer. The second -** argument, pData, points to a buffer (*pnData) bytes in size. Assuming no -** error occurs the xInput method should copy up to (*pnData) bytes of data -** into the buffer and set (*pnData) to the actual number of bytes copied -** before returning SQLITE_OK. If the input is completely exhausted, (*pnData) -** should be set to zero to indicate this. Or, if an error occurs, an SQLite -** error code should be returned. In all cases, if an xInput callback returns -** an error, all processing is abandoned and the streaming API function -** returns a copy of the error code to the caller. -** -** In the case of sqlite3changeset_start_strm(), the xInput callback may be -** invoked by the sessions module at any point during the lifetime of the -** iterator. If such an xInput callback returns an error, the iterator enters -** an error state, whereby all subsequent calls to iterator functions -** immediately fail with the same error code as returned by xInput. -** -** Similarly, streaming API functions that return changesets (or patchsets) -** return them in chunks by way of a callback function instead of via a -** pointer to a single large buffer. In this case, a pair of parameters such -** as: -** -**
-**        int *pnChangeset,
-**        void **ppChangeset,
-**  
-** -** Is replaced by: -** -**
-**        int (*xOutput)(void *pOut, const void *pData, int nData),
-**        void *pOut
-**  
-** -** The xOutput callback is invoked zero or more times to return data to -** the application. The first parameter passed to each call is a copy of the -** pOut pointer supplied by the application. The second parameter, pData, -** points to a buffer nData bytes in size containing the chunk of output -** data being returned. If the xOutput callback successfully processes the -** supplied data, it should return SQLITE_OK to indicate success. Otherwise, -** it should return some other SQLite error code. In this case processing -** is immediately abandoned and the streaming API function returns a copy -** of the xOutput error code to the application. -** -** The sessions module never invokes an xOutput callback with the third -** parameter set to a value less than or equal to zero. Other than this, -** no guarantees are made as to the size of the chunks of data returned. -*/ -SQLITE_API int sqlite3changeset_apply_strm( - sqlite3 *db, /* Apply change to "main" db of this handle */ - int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */ - void *pIn, /* First arg for xInput */ - int(*xFilter)( - void *pCtx, /* Copy of sixth arg to _apply() */ - const char *zTab /* Table name */ - ), - int(*xConflict)( - void *pCtx, /* Copy of sixth arg to _apply() */ - int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ - sqlite3_changeset_iter *p /* Handle describing change and conflict */ - ), - void *pCtx /* First argument passed to xConflict */ -); -SQLITE_API int sqlite3changeset_apply_v2_strm( - sqlite3 *db, /* Apply change to "main" db of this handle */ - int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */ - void *pIn, /* First arg for xInput */ - int(*xFilter)( - void *pCtx, /* Copy of sixth arg to _apply() */ - const char *zTab /* Table name */ - ), - int(*xConflict)( - void *pCtx, /* Copy of sixth arg to _apply() */ - int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ - sqlite3_changeset_iter *p /* Handle describing change and conflict */ - ), - void *pCtx, /* First argument passed to xConflict */ - void **ppRebase, int *pnRebase, - int flags -); -SQLITE_API int sqlite3changeset_concat_strm( - int (*xInputA)(void *pIn, void *pData, int *pnData), - void *pInA, - int (*xInputB)(void *pIn, void *pData, int *pnData), - void *pInB, - int (*xOutput)(void *pOut, const void *pData, int nData), - void *pOut -); -SQLITE_API int sqlite3changeset_invert_strm( - int (*xInput)(void *pIn, void *pData, int *pnData), - void *pIn, - int (*xOutput)(void *pOut, const void *pData, int nData), - void *pOut -); -SQLITE_API int sqlite3changeset_start_strm( - sqlite3_changeset_iter **pp, - int (*xInput)(void *pIn, void *pData, int *pnData), - void *pIn -); -SQLITE_API int sqlite3changeset_start_v2_strm( - sqlite3_changeset_iter **pp, - int (*xInput)(void *pIn, void *pData, int *pnData), - void *pIn, - int flags -); -SQLITE_API int sqlite3session_changeset_strm( - sqlite3_session *pSession, - int (*xOutput)(void *pOut, const void *pData, int nData), - void *pOut -); -SQLITE_API int sqlite3session_patchset_strm( - sqlite3_session *pSession, - int (*xOutput)(void *pOut, const void *pData, int nData), - void *pOut -); -SQLITE_API int sqlite3changegroup_add_strm(sqlite3_changegroup*, - int (*xInput)(void *pIn, void *pData, int *pnData), - void *pIn -); -SQLITE_API int sqlite3changegroup_output_strm(sqlite3_changegroup*, - int (*xOutput)(void *pOut, const void *pData, int nData), - void *pOut -); -SQLITE_API int sqlite3rebaser_rebase_strm( - sqlite3_rebaser *pRebaser, - int (*xInput)(void *pIn, void *pData, int *pnData), - void *pIn, - int (*xOutput)(void *pOut, const void *pData, int nData), - void *pOut -); - -/* -** CAPI3REF: Configure global parameters -** -** The sqlite3session_config() interface is used to make global configuration -** changes to the sessions module in order to tune it to the specific needs -** of the application. -** -** The sqlite3session_config() interface is not threadsafe. If it is invoked -** while any other thread is inside any other sessions method then the -** results are undefined. Furthermore, if it is invoked after any sessions -** related objects have been created, the results are also undefined. -** -** The first argument to the sqlite3session_config() function must be one -** of the SQLITE_SESSION_CONFIG_XXX constants defined below. The -** interpretation of the (void*) value passed as the second parameter and -** the effect of calling this function depends on the value of the first -** parameter. -** -**
-**
SQLITE_SESSION_CONFIG_STRMSIZE
-** By default, the sessions module streaming interfaces attempt to input -** and output data in approximately 1 KiB chunks. This operand may be used -** to set and query the value of this configuration setting. The pointer -** passed as the second argument must point to a value of type (int). -** If this value is greater than 0, it is used as the new streaming data -** chunk size for both input and output. Before returning, the (int) value -** pointed to by pArg is set to the final value of the streaming interface -** chunk size. -**
-** -** This function returns SQLITE_OK if successful, or an SQLite error code -** otherwise. -*/ -SQLITE_API int sqlite3session_config(int op, void *pArg); +#define SQLITE_CHANGESET_OMIT 0 +#define SQLITE_CHANGESET_REPLACE 1 +#define SQLITE_CHANGESET_ABORT 2 + + /* + ** CAPI3REF: Rebasing changesets + ** EXPERIMENTAL + ** + ** Suppose there is a site hosting a database in state S0. And that + ** modifications are made that move that database to state S1 and a + ** changeset recorded (the "local" changeset). Then, a changeset based + ** on S0 is received from another site (the "remote" changeset) and + ** applied to the database. The database is then in state + ** (S1+"remote"), where the exact state depends on any conflict + ** resolution decisions (OMIT or REPLACE) made while applying "remote". + ** Rebasing a changeset is to update it to take those conflict + ** resolution decisions into account, so that the same conflicts + ** do not have to be resolved elsewhere in the network. + ** + ** For example, if both the local and remote changesets contain an + ** INSERT of the same key on "CREATE TABLE t1(a PRIMARY KEY, b)": + ** + ** local: INSERT INTO t1 VALUES(1, 'v1'); + ** remote: INSERT INTO t1 VALUES(1, 'v2'); + ** + ** and the conflict resolution is REPLACE, then the INSERT change is + ** removed from the local changeset (it was overridden). Or, if the + ** conflict resolution was "OMIT", then the local changeset is modified + ** to instead contain: + ** + ** UPDATE t1 SET b = 'v2' WHERE a=1; + ** + ** Changes within the local changeset are rebased as follows: + ** + **
+ **
Local INSERT
+ ** This may only conflict with a remote INSERT. If the conflict + ** resolution was OMIT, then add an UPDATE change to the rebased + ** changeset. Or, if the conflict resolution was REPLACE, add + ** nothing to the rebased changeset. + ** + **
Local DELETE
+ ** This may conflict with a remote UPDATE or DELETE. In both cases the + ** only possible resolution is OMIT. If the remote operation was a + ** DELETE, then add no change to the rebased changeset. If the remote + ** operation was an UPDATE, then the old.* fields of change are updated + ** to reflect the new.* values in the UPDATE. + ** + **
Local UPDATE
+ ** This may conflict with a remote UPDATE or DELETE. If it conflicts + ** with a DELETE, and the conflict resolution was OMIT, then the update + ** is changed into an INSERT. Any undefined values in the new.* record + ** from the update change are filled in using the old.* values from + ** the conflicting DELETE. Or, if the conflict resolution was REPLACE, + ** the UPDATE change is simply omitted from the rebased changeset. + ** + ** If conflict is with a remote UPDATE and the resolution is OMIT, then + ** the old.* values are rebased using the new.* values in the remote + ** change. Or, if the resolution is REPLACE, then the change is copied + ** into the rebased changeset with updates to columns also updated by + ** the conflicting remote UPDATE removed. If this means no columns would + ** be updated, the change is omitted. + **
+ ** + ** A local change may be rebased against multiple remote changes + ** simultaneously. If a single key is modified by multiple remote + ** changesets, they are combined as follows before the local changeset + ** is rebased: + ** + **
    + **
  • If there has been one or more REPLACE resolutions on a + ** key, it is rebased according to a REPLACE. + ** + **
  • If there have been no REPLACE resolutions on a key, then + ** the local changeset is rebased according to the most recent + ** of the OMIT resolutions. + **
+ ** + ** Note that conflict resolutions from multiple remote changesets are + ** combined on a per-field basis, not per-row. This means that in the + ** case of multiple remote UPDATE operations, some fields of a single + ** local change may be rebased for REPLACE while others are rebased for + ** OMIT. + ** + ** In order to rebase a local changeset, the remote changeset must first + ** be applied to the local database using sqlite3changeset_apply_v2() and + ** the buffer of rebase information captured. Then: + ** + **
    + **
  1. An sqlite3_rebaser object is created by calling + ** sqlite3rebaser_create(). + **
  2. The new object is configured with the rebase buffer obtained from + ** sqlite3changeset_apply_v2() by calling sqlite3rebaser_configure(). + ** If the local changeset is to be rebased against multiple remote + ** changesets, then sqlite3rebaser_configure() should be called + ** multiple times, in the same order that the multiple + ** sqlite3changeset_apply_v2() calls were made. + **
  3. Each local changeset is rebased by calling sqlite3rebaser_rebase(). + **
  4. The sqlite3_rebaser object is deleted by calling + ** sqlite3rebaser_delete(). + **
+ */ + typedef struct sqlite3_rebaser sqlite3_rebaser; + + /* + ** CAPI3REF: Create a changeset rebaser object. + ** EXPERIMENTAL + ** + ** Allocate a new changeset rebaser object. If successful, set (*ppNew) to + ** point to the new object and return SQLITE_OK. Otherwise, if an error + ** occurs, return an SQLite error code (e.g. SQLITE_NOMEM) and set (*ppNew) + ** to NULL. + */ + SQLITE_API int sqlite3rebaser_create(sqlite3_rebaser** ppNew); + + /* + ** CAPI3REF: Configure a changeset rebaser object. + ** EXPERIMENTAL + ** + ** Configure the changeset rebaser object to rebase changesets according + ** to the conflict resolutions described by buffer pRebase (size nRebase + ** bytes), which must have been obtained from a previous call to + ** sqlite3changeset_apply_v2(). + */ + SQLITE_API int sqlite3rebaser_configure(sqlite3_rebaser*, int nRebase, const void* pRebase); + + /* + ** CAPI3REF: Rebase a changeset + ** EXPERIMENTAL + ** + ** Argument pIn must point to a buffer containing a changeset nIn bytes + ** in size. This function allocates and populates a buffer with a copy + ** of the changeset rebased according to the configuration of the + ** rebaser object passed as the first argument. If successful, (*ppOut) + ** is set to point to the new buffer containing the rebased changeset and + ** (*pnOut) to its size in bytes and SQLITE_OK returned. It is the + ** responsibility of the caller to eventually free the new buffer using + ** sqlite3_free(). Otherwise, if an error occurs, (*ppOut) and (*pnOut) + ** are set to zero and an SQLite error code returned. + */ + SQLITE_API int sqlite3rebaser_rebase(sqlite3_rebaser*, int nIn, const void* pIn, int* pnOut, void** ppOut); + + /* + ** CAPI3REF: Delete a changeset rebaser object. + ** EXPERIMENTAL + ** + ** Delete the changeset rebaser object and all associated resources. There + ** should be one call to this function for each successful invocation + ** of sqlite3rebaser_create(). + */ + SQLITE_API void sqlite3rebaser_delete(sqlite3_rebaser* p); + + /* + ** CAPI3REF: Streaming Versions of API functions. + ** + ** The six streaming API xxx_strm() functions serve similar purposes to the + ** corresponding non-streaming API functions: + ** + ** + ** + **
Streaming functionNon-streaming equivalent
sqlite3changeset_apply_strm[sqlite3changeset_apply] + **
sqlite3changeset_apply_strm_v2[sqlite3changeset_apply_v2] + **
sqlite3changeset_concat_strm[sqlite3changeset_concat] + **
sqlite3changeset_invert_strm[sqlite3changeset_invert] + **
sqlite3changeset_start_strm[sqlite3changeset_start] + **
sqlite3session_changeset_strm[sqlite3session_changeset] + **
sqlite3session_patchset_strm[sqlite3session_patchset] + **
+ ** + ** Non-streaming functions that accept changesets (or patchsets) as input + ** require that the entire changeset be stored in a single buffer in memory. + ** Similarly, those that return a changeset or patchset do so by returning + ** a pointer to a single large buffer allocated using sqlite3_malloc(). + ** Normally this is convenient. However, if an application running in a + ** low-memory environment is required to handle very large changesets, the + ** large contiguous memory allocations required can become onerous. + ** + ** In order to avoid this problem, instead of a single large buffer, input + ** is passed to a streaming API functions by way of a callback function that + ** the sessions module invokes to incrementally request input data as it is + ** required. In all cases, a pair of API function parameters such as + ** + **
+    **        int nChangeset,
+    **        void *pChangeset,
+    **  
+ ** + ** Is replaced by: + ** + **
+    **        int (*xInput)(void *pIn, void *pData, int *pnData),
+    **        void *pIn,
+    **  
+ ** + ** Each time the xInput callback is invoked by the sessions module, the first + ** argument passed is a copy of the supplied pIn context pointer. The second + ** argument, pData, points to a buffer (*pnData) bytes in size. Assuming no + ** error occurs the xInput method should copy up to (*pnData) bytes of data + ** into the buffer and set (*pnData) to the actual number of bytes copied + ** before returning SQLITE_OK. If the input is completely exhausted, (*pnData) + ** should be set to zero to indicate this. Or, if an error occurs, an SQLite + ** error code should be returned. In all cases, if an xInput callback returns + ** an error, all processing is abandoned and the streaming API function + ** returns a copy of the error code to the caller. + ** + ** In the case of sqlite3changeset_start_strm(), the xInput callback may be + ** invoked by the sessions module at any point during the lifetime of the + ** iterator. If such an xInput callback returns an error, the iterator enters + ** an error state, whereby all subsequent calls to iterator functions + ** immediately fail with the same error code as returned by xInput. + ** + ** Similarly, streaming API functions that return changesets (or patchsets) + ** return them in chunks by way of a callback function instead of via a + ** pointer to a single large buffer. In this case, a pair of parameters such + ** as: + ** + **
+    **        int *pnChangeset,
+    **        void **ppChangeset,
+    **  
+ ** + ** Is replaced by: + ** + **
+    **        int (*xOutput)(void *pOut, const void *pData, int nData),
+    **        void *pOut
+    **  
+ ** + ** The xOutput callback is invoked zero or more times to return data to + ** the application. The first parameter passed to each call is a copy of the + ** pOut pointer supplied by the application. The second parameter, pData, + ** points to a buffer nData bytes in size containing the chunk of output + ** data being returned. If the xOutput callback successfully processes the + ** supplied data, it should return SQLITE_OK to indicate success. Otherwise, + ** it should return some other SQLite error code. In this case processing + ** is immediately abandoned and the streaming API function returns a copy + ** of the xOutput error code to the application. + ** + ** The sessions module never invokes an xOutput callback with the third + ** parameter set to a value less than or equal to zero. Other than this, + ** no guarantees are made as to the size of the chunks of data returned. + */ + SQLITE_API int sqlite3changeset_apply_strm(sqlite3* db, /* Apply change to "main" db of this handle */ + int (*xInput)(void* pIn, void* pData, int* pnData), /* Input function */ + void* pIn, /* First arg for xInput */ + int (*xFilter)(void* pCtx, /* Copy of sixth arg to _apply() */ + const char* zTab /* Table name */ + ), + int (*xConflict)(void* pCtx, /* Copy of sixth arg to _apply() */ + int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ + sqlite3_changeset_iter* p /* Handle describing change + and conflict */ + ), + void* pCtx /* First argument passed to xConflict */ + ); + SQLITE_API int + sqlite3changeset_apply_v2_strm(sqlite3* db, /* Apply change to "main" db of this handle */ + int (*xInput)(void* pIn, void* pData, int* pnData), /* Input function */ + void* pIn, /* First arg for xInput */ + int (*xFilter)(void* pCtx, /* Copy of sixth arg to _apply() */ + const char* zTab /* Table name */ + ), + int (*xConflict)(void* pCtx, /* Copy of sixth arg to _apply() */ + int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ + sqlite3_changeset_iter* p /* Handle describing change and conflict + */ + ), + void* pCtx, /* First argument passed to xConflict */ + void** ppRebase, + int* pnRebase, + int flags); + SQLITE_API int sqlite3changeset_concat_strm(int (*xInputA)(void* pIn, void* pData, int* pnData), + void* pInA, + int (*xInputB)(void* pIn, void* pData, int* pnData), + void* pInB, + int (*xOutput)(void* pOut, const void* pData, int nData), + void* pOut); + SQLITE_API int sqlite3changeset_invert_strm(int (*xInput)(void* pIn, void* pData, int* pnData), + void* pIn, + int (*xOutput)(void* pOut, const void* pData, int nData), + void* pOut); + SQLITE_API int sqlite3changeset_start_strm(sqlite3_changeset_iter** pp, + int (*xInput)(void* pIn, void* pData, int* pnData), + void* pIn); + SQLITE_API int sqlite3changeset_start_v2_strm(sqlite3_changeset_iter** pp, + int (*xInput)(void* pIn, void* pData, int* pnData), + void* pIn, + int flags); + SQLITE_API int sqlite3session_changeset_strm(sqlite3_session* pSession, + int (*xOutput)(void* pOut, const void* pData, int nData), + void* pOut); + SQLITE_API int sqlite3session_patchset_strm(sqlite3_session* pSession, + int (*xOutput)(void* pOut, const void* pData, int nData), + void* pOut); + SQLITE_API int + sqlite3changegroup_add_strm(sqlite3_changegroup*, int (*xInput)(void* pIn, void* pData, int* pnData), void* pIn); + SQLITE_API int sqlite3changegroup_output_strm(sqlite3_changegroup*, + int (*xOutput)(void* pOut, const void* pData, int nData), + void* pOut); + SQLITE_API int sqlite3rebaser_rebase_strm(sqlite3_rebaser* pRebaser, + int (*xInput)(void* pIn, void* pData, int* pnData), + void* pIn, + int (*xOutput)(void* pOut, const void* pData, int nData), + void* pOut); + + /* + ** CAPI3REF: Configure global parameters + ** + ** The sqlite3session_config() interface is used to make global configuration + ** changes to the sessions module in order to tune it to the specific needs + ** of the application. + ** + ** The sqlite3session_config() interface is not threadsafe. If it is invoked + ** while any other thread is inside any other sessions method then the + ** results are undefined. Furthermore, if it is invoked after any sessions + ** related objects have been created, the results are also undefined. + ** + ** The first argument to the sqlite3session_config() function must be one + ** of the SQLITE_SESSION_CONFIG_XXX constants defined below. The + ** interpretation of the (void*) value passed as the second parameter and + ** the effect of calling this function depends on the value of the first + ** parameter. + ** + **
+ **
SQLITE_SESSION_CONFIG_STRMSIZE
+ ** By default, the sessions module streaming interfaces attempt to input + ** and output data in approximately 1 KiB chunks. This operand may be used + ** to set and query the value of this configuration setting. The pointer + ** passed as the second argument must point to a value of type (int). + ** If this value is greater than 0, it is used as the new streaming data + ** chunk size for both input and output. Before returning, the (int) value + ** pointed to by pArg is set to the final value of the streaming interface + ** chunk size. + **
+ ** + ** This function returns SQLITE_OK if successful, or an SQLite error code + ** otherwise. + */ + SQLITE_API int sqlite3session_config(int op, void* pArg); /* ** CAPI3REF: Values for sqlite3session_config(). @@ -12220,7 +12077,7 @@ SQLITE_API int sqlite3session_config(int op, void *pArg); } #endif -#endif /* !defined(__SQLITESESSION_H_) && defined(SQLITE_ENABLE_SESSION) */ +#endif /* !defined(__SQLITESESSION_H_) && defined(SQLITE_ENABLE_SESSION) */ /******** End of sqlite3session.h *********/ /******** Begin file fts5.h *********/ @@ -12243,558 +12100,552 @@ SQLITE_API int sqlite3session_config(int op, void *pArg); ** * custom auxiliary functions. */ - #ifndef _FTS5_H #define _FTS5_H - #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/************************************************************************* -** CUSTOM AUXILIARY FUNCTIONS -** -** Virtual table implementations may overload SQL functions by implementing -** the sqlite3_module.xFindFunction() method. -*/ - -typedef struct Fts5ExtensionApi Fts5ExtensionApi; -typedef struct Fts5Context Fts5Context; -typedef struct Fts5PhraseIter Fts5PhraseIter; - -typedef void (*fts5_extension_function)( - const Fts5ExtensionApi *pApi, /* API offered by current FTS version */ - Fts5Context *pFts, /* First arg to pass to pApi functions */ - sqlite3_context *pCtx, /* Context for returning result/error */ - int nVal, /* Number of values in apVal[] array */ - sqlite3_value **apVal /* Array of trailing arguments */ -); - -struct Fts5PhraseIter { - const unsigned char *a; - const unsigned char *b; -}; - -/* -** EXTENSION API FUNCTIONS -** -** xUserData(pFts): -** Return a copy of the context pointer the extension function was -** registered with. -** -** xColumnTotalSize(pFts, iCol, pnToken): -** If parameter iCol is less than zero, set output variable *pnToken -** to the total number of tokens in the FTS5 table. Or, if iCol is -** non-negative but less than the number of columns in the table, return -** the total number of tokens in column iCol, considering all rows in -** the FTS5 table. -** -** If parameter iCol is greater than or equal to the number of columns -** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g. -** an OOM condition or IO error), an appropriate SQLite error code is -** returned. -** -** xColumnCount(pFts): -** Return the number of columns in the table. -** -** xColumnSize(pFts, iCol, pnToken): -** If parameter iCol is less than zero, set output variable *pnToken -** to the total number of tokens in the current row. Or, if iCol is -** non-negative but less than the number of columns in the table, set -** *pnToken to the number of tokens in column iCol of the current row. -** -** If parameter iCol is greater than or equal to the number of columns -** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g. -** an OOM condition or IO error), an appropriate SQLite error code is -** returned. -** -** This function may be quite inefficient if used with an FTS5 table -** created with the "columnsize=0" option. -** -** xColumnText: -** This function attempts to retrieve the text of column iCol of the -** current document. If successful, (*pz) is set to point to a buffer -** containing the text in utf-8 encoding, (*pn) is set to the size in bytes -** (not characters) of the buffer and SQLITE_OK is returned. Otherwise, -** if an error occurs, an SQLite error code is returned and the final values -** of (*pz) and (*pn) are undefined. -** -** xPhraseCount: -** Returns the number of phrases in the current query expression. -** -** xPhraseSize: -** Returns the number of tokens in phrase iPhrase of the query. Phrases -** are numbered starting from zero. -** -** xInstCount: -** Set *pnInst to the total number of occurrences of all phrases within -** the query within the current row. Return SQLITE_OK if successful, or -** an error code (i.e. SQLITE_NOMEM) if an error occurs. -** -** This API can be quite slow if used with an FTS5 table created with the -** "detail=none" or "detail=column" option. If the FTS5 table is created -** with either "detail=none" or "detail=column" and "content=" option -** (i.e. if it is a contentless table), then this API always returns 0. -** -** xInst: -** Query for the details of phrase match iIdx within the current row. -** Phrase matches are numbered starting from zero, so the iIdx argument -** should be greater than or equal to zero and smaller than the value -** output by xInstCount(). -** -** Usually, output parameter *piPhrase is set to the phrase number, *piCol -** to the column in which it occurs and *piOff the token offset of the -** first token of the phrase. Returns SQLITE_OK if successful, or an error -** code (i.e. SQLITE_NOMEM) if an error occurs. -** -** This API can be quite slow if used with an FTS5 table created with the -** "detail=none" or "detail=column" option. -** -** xRowid: -** Returns the rowid of the current row. -** -** xTokenize: -** Tokenize text using the tokenizer belonging to the FTS5 table. -** -** xQueryPhrase(pFts5, iPhrase, pUserData, xCallback): -** This API function is used to query the FTS table for phrase iPhrase -** of the current query. Specifically, a query equivalent to: -** -** ... FROM ftstable WHERE ftstable MATCH $p ORDER BY rowid -** -** with $p set to a phrase equivalent to the phrase iPhrase of the -** current query is executed. Any column filter that applies to -** phrase iPhrase of the current query is included in $p. For each -** row visited, the callback function passed as the fourth argument -** is invoked. The context and API objects passed to the callback -** function may be used to access the properties of each matched row. -** Invoking Api.xUserData() returns a copy of the pointer passed as -** the third argument to pUserData. -** -** If the callback function returns any value other than SQLITE_OK, the -** query is abandoned and the xQueryPhrase function returns immediately. -** If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK. -** Otherwise, the error code is propagated upwards. -** -** If the query runs to completion without incident, SQLITE_OK is returned. -** Or, if some error occurs before the query completes or is aborted by -** the callback, an SQLite error code is returned. -** -** -** xSetAuxdata(pFts5, pAux, xDelete) -** -** Save the pointer passed as the second argument as the extension function's -** "auxiliary data". The pointer may then be retrieved by the current or any -** future invocation of the same fts5 extension function made as part of -** the same MATCH query using the xGetAuxdata() API. -** -** Each extension function is allocated a single auxiliary data slot for -** each FTS query (MATCH expression). If the extension function is invoked -** more than once for a single FTS query, then all invocations share a -** single auxiliary data context. -** -** If there is already an auxiliary data pointer when this function is -** invoked, then it is replaced by the new pointer. If an xDelete callback -** was specified along with the original pointer, it is invoked at this -** point. -** -** The xDelete callback, if one is specified, is also invoked on the -** auxiliary data pointer after the FTS5 query has finished. -** -** If an error (e.g. an OOM condition) occurs within this function, -** the auxiliary data is set to NULL and an error code returned. If the -** xDelete parameter was not NULL, it is invoked on the auxiliary data -** pointer before returning. -** -** -** xGetAuxdata(pFts5, bClear) -** -** Returns the current auxiliary data pointer for the fts5 extension -** function. See the xSetAuxdata() method for details. -** -** If the bClear argument is non-zero, then the auxiliary data is cleared -** (set to NULL) before this function returns. In this case the xDelete, -** if any, is not invoked. -** -** -** xRowCount(pFts5, pnRow) -** -** This function is used to retrieve the total number of rows in the table. -** In other words, the same value that would be returned by: -** -** SELECT count(*) FROM ftstable; -** -** xPhraseFirst() -** This function is used, along with type Fts5PhraseIter and the xPhraseNext -** method, to iterate through all instances of a single query phrase within -** the current row. This is the same information as is accessible via the -** xInstCount/xInst APIs. While the xInstCount/xInst APIs are more convenient -** to use, this API may be faster under some circumstances. To iterate -** through instances of phrase iPhrase, use the following code: -** -** Fts5PhraseIter iter; -** int iCol, iOff; -** for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff); -** iCol>=0; -** pApi->xPhraseNext(pFts, &iter, &iCol, &iOff) -** ){ -** // An instance of phrase iPhrase at offset iOff of column iCol -** } -** -** The Fts5PhraseIter structure is defined above. Applications should not -** modify this structure directly - it should only be used as shown above -** with the xPhraseFirst() and xPhraseNext() API methods (and by -** xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below). -** -** This API can be quite slow if used with an FTS5 table created with the -** "detail=none" or "detail=column" option. If the FTS5 table is created -** with either "detail=none" or "detail=column" and "content=" option -** (i.e. if it is a contentless table), then this API always iterates -** through an empty set (all calls to xPhraseFirst() set iCol to -1). -** -** xPhraseNext() -** See xPhraseFirst above. -** -** xPhraseFirstColumn() -** This function and xPhraseNextColumn() are similar to the xPhraseFirst() -** and xPhraseNext() APIs described above. The difference is that instead -** of iterating through all instances of a phrase in the current row, these -** APIs are used to iterate through the set of columns in the current row -** that contain one or more instances of a specified phrase. For example: -** -** Fts5PhraseIter iter; -** int iCol; -** for(pApi->xPhraseFirstColumn(pFts, iPhrase, &iter, &iCol); -** iCol>=0; -** pApi->xPhraseNextColumn(pFts, &iter, &iCol) -** ){ -** // Column iCol contains at least one instance of phrase iPhrase -** } -** -** This API can be quite slow if used with an FTS5 table created with the -** "detail=none" option. If the FTS5 table is created with either -** "detail=none" "content=" option (i.e. if it is a contentless table), -** then this API always iterates through an empty set (all calls to -** xPhraseFirstColumn() set iCol to -1). -** -** The information accessed using this API and its companion -** xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext -** (or xInst/xInstCount). The chief advantage of this API is that it is -** significantly more efficient than those alternatives when used with -** "detail=column" tables. -** -** xPhraseNextColumn() -** See xPhraseFirstColumn above. -*/ -struct Fts5ExtensionApi { - int iVersion; /* Currently always set to 3 */ - - void *(*xUserData)(Fts5Context*); - - int (*xColumnCount)(Fts5Context*); - int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow); - int (*xColumnTotalSize)(Fts5Context*, int iCol, sqlite3_int64 *pnToken); - - int (*xTokenize)(Fts5Context*, - const char *pText, int nText, /* Text to tokenize */ - void *pCtx, /* Context passed to xToken() */ - int (*xToken)(void*, int, const char*, int, int, int) /* Callback */ - ); - - int (*xPhraseCount)(Fts5Context*); - int (*xPhraseSize)(Fts5Context*, int iPhrase); - - int (*xInstCount)(Fts5Context*, int *pnInst); - int (*xInst)(Fts5Context*, int iIdx, int *piPhrase, int *piCol, int *piOff); - - sqlite3_int64 (*xRowid)(Fts5Context*); - int (*xColumnText)(Fts5Context*, int iCol, const char **pz, int *pn); - int (*xColumnSize)(Fts5Context*, int iCol, int *pnToken); - - int (*xQueryPhrase)(Fts5Context*, int iPhrase, void *pUserData, - int(*)(const Fts5ExtensionApi*,Fts5Context*,void*) - ); - int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*)); - void *(*xGetAuxdata)(Fts5Context*, int bClear); - - int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*); - void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff); - - int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*); - void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol); -}; - -/* -** CUSTOM AUXILIARY FUNCTIONS -*************************************************************************/ - -/************************************************************************* -** CUSTOM TOKENIZERS -** -** Applications may also register custom tokenizer types. A tokenizer -** is registered by providing fts5 with a populated instance of the -** following structure. All structure methods must be defined, setting -** any member of the fts5_tokenizer struct to NULL leads to undefined -** behaviour. The structure methods are expected to function as follows: -** -** xCreate: -** This function is used to allocate and initialize a tokenizer instance. -** A tokenizer instance is required to actually tokenize text. -** -** The first argument passed to this function is a copy of the (void*) -** pointer provided by the application when the fts5_tokenizer object -** was registered with FTS5 (the third argument to xCreateTokenizer()). -** The second and third arguments are an array of nul-terminated strings -** containing the tokenizer arguments, if any, specified following the -** tokenizer name as part of the CREATE VIRTUAL TABLE statement used -** to create the FTS5 table. -** -** The final argument is an output variable. If successful, (*ppOut) -** should be set to point to the new tokenizer handle and SQLITE_OK -** returned. If an error occurs, some value other than SQLITE_OK should -** be returned. In this case, fts5 assumes that the final value of *ppOut -** is undefined. -** -** xDelete: -** This function is invoked to delete a tokenizer handle previously -** allocated using xCreate(). Fts5 guarantees that this function will -** be invoked exactly once for each successful call to xCreate(). -** -** xTokenize: -** This function is expected to tokenize the nText byte string indicated -** by argument pText. pText may or may not be nul-terminated. The first -** argument passed to this function is a pointer to an Fts5Tokenizer object -** returned by an earlier call to xCreate(). -** -** The second argument indicates the reason that FTS5 is requesting -** tokenization of the supplied text. This is always one of the following -** four values: -** -**
  • FTS5_TOKENIZE_DOCUMENT - A document is being inserted into -** or removed from the FTS table. The tokenizer is being invoked to -** determine the set of tokens to add to (or delete from) the -** FTS index. -** -**
  • FTS5_TOKENIZE_QUERY - A MATCH query is being executed -** against the FTS index. The tokenizer is being called to tokenize -** a bareword or quoted string specified as part of the query. -** -**
  • (FTS5_TOKENIZE_QUERY | FTS5_TOKENIZE_PREFIX) - Same as -** FTS5_TOKENIZE_QUERY, except that the bareword or quoted string is -** followed by a "*" character, indicating that the last token -** returned by the tokenizer will be treated as a token prefix. -** -**
  • FTS5_TOKENIZE_AUX - The tokenizer is being invoked to -** satisfy an fts5_api.xTokenize() request made by an auxiliary -** function. Or an fts5_api.xColumnSize() request made by the same -** on a columnsize=0 database. -**
-** -** For each token in the input string, the supplied callback xToken() must -** be invoked. The first argument to it should be a copy of the pointer -** passed as the second argument to xTokenize(). The third and fourth -** arguments are a pointer to a buffer containing the token text, and the -** size of the token in bytes. The 4th and 5th arguments are the byte offsets -** of the first byte of and first byte immediately following the text from -** which the token is derived within the input. -** -** The second argument passed to the xToken() callback ("tflags") should -** normally be set to 0. The exception is if the tokenizer supports -** synonyms. In this case see the discussion below for details. -** -** FTS5 assumes the xToken() callback is invoked for each token in the -** order that they occur within the input text. -** -** If an xToken() callback returns any value other than SQLITE_OK, then -** the tokenization should be abandoned and the xTokenize() method should -** immediately return a copy of the xToken() return value. Or, if the -** input buffer is exhausted, xTokenize() should return SQLITE_OK. Finally, -** if an error occurs with the xTokenize() implementation itself, it -** may abandon the tokenization and return any error code other than -** SQLITE_OK or SQLITE_DONE. -** -** SYNONYM SUPPORT -** -** Custom tokenizers may also support synonyms. Consider a case in which a -** user wishes to query for a phrase such as "first place". Using the -** built-in tokenizers, the FTS5 query 'first + place' will match instances -** of "first place" within the document set, but not alternative forms -** such as "1st place". In some applications, it would be better to match -** all instances of "first place" or "1st place" regardless of which form -** the user specified in the MATCH query text. -** -** There are several ways to approach this in FTS5: -** -**
  1. By mapping all synonyms to a single token. In this case, using -** the above example, this means that the tokenizer returns the -** same token for inputs "first" and "1st". Say that token is in -** fact "first", so that when the user inserts the document "I won -** 1st place" entries are added to the index for tokens "i", "won", -** "first" and "place". If the user then queries for '1st + place', -** the tokenizer substitutes "first" for "1st" and the query works -** as expected. -** -**
  2. By querying the index for all synonyms of each query term -** separately. In this case, when tokenizing query text, the -** tokenizer may provide multiple synonyms for a single term -** within the document. FTS5 then queries the index for each -** synonym individually. For example, faced with the query: -** -** -** ... MATCH 'first place' -** -** the tokenizer offers both "1st" and "first" as synonyms for the -** first token in the MATCH query and FTS5 effectively runs a query -** similar to: -** -** -** ... MATCH '(first OR 1st) place' -** -** except that, for the purposes of auxiliary functions, the query -** still appears to contain just two phrases - "(first OR 1st)" -** being treated as a single phrase. -** -**
  3. By adding multiple synonyms for a single term to the FTS index. -** Using this method, when tokenizing document text, the tokenizer -** provides multiple synonyms for each token. So that when a -** document such as "I won first place" is tokenized, entries are -** added to the FTS index for "i", "won", "first", "1st" and -** "place". -** -** This way, even if the tokenizer does not provide synonyms -** when tokenizing query text (it should not - to do so would be -** inefficient), it doesn't matter if the user queries for -** 'first + place' or '1st + place', as there are entries in the -** FTS index corresponding to both forms of the first token. -**
-** -** Whether it is parsing document or query text, any call to xToken that -** specifies a tflags argument with the FTS5_TOKEN_COLOCATED bit -** is considered to supply a synonym for the previous token. For example, -** when parsing the document "I won first place", a tokenizer that supports -** synonyms would call xToken() 5 times, as follows: -** -** -** xToken(pCtx, 0, "i", 1, 0, 1); -** xToken(pCtx, 0, "won", 3, 2, 5); -** xToken(pCtx, 0, "first", 5, 6, 11); -** xToken(pCtx, FTS5_TOKEN_COLOCATED, "1st", 3, 6, 11); -** xToken(pCtx, 0, "place", 5, 12, 17); -** -** -** It is an error to specify the FTS5_TOKEN_COLOCATED flag the first time -** xToken() is called. Multiple synonyms may be specified for a single token -** by making multiple calls to xToken(FTS5_TOKEN_COLOCATED) in sequence. -** There is no limit to the number of synonyms that may be provided for a -** single token. -** -** In many cases, method (1) above is the best approach. It does not add -** extra data to the FTS index or require FTS5 to query for multiple terms, -** so it is efficient in terms of disk space and query speed. However, it -** does not support prefix queries very well. If, as suggested above, the -** token "first" is substituted for "1st" by the tokenizer, then the query: -** -** -** ... MATCH '1s*' -** -** will not match documents that contain the token "1st" (as the tokenizer -** will probably not map "1s" to any prefix of "first"). -** -** For full prefix support, method (3) may be preferred. In this case, -** because the index contains entries for both "first" and "1st", prefix -** queries such as 'fi*' or '1s*' will match correctly. However, because -** extra entries are added to the FTS index, this method uses more space -** within the database. -** -** Method (2) offers a midpoint between (1) and (3). Using this method, -** a query such as '1s*' will match documents that contain the literal -** token "1st", but not "first" (assuming the tokenizer is not able to -** provide synonyms for prefixes). However, a non-prefix query like '1st' -** will match against "1st" and "first". This method does not require -** extra disk space, as no extra entries are added to the FTS index. -** On the other hand, it may require more CPU cycles to run MATCH queries, -** as separate queries of the FTS index are required for each synonym. -** -** When using methods (2) or (3), it is important that the tokenizer only -** provide synonyms when tokenizing document text (method (2)) or query -** text (method (3)), not both. Doing so will not cause any errors, but is -** inefficient. -*/ -typedef struct Fts5Tokenizer Fts5Tokenizer; -typedef struct fts5_tokenizer fts5_tokenizer; -struct fts5_tokenizer { - int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut); - void (*xDelete)(Fts5Tokenizer*); - int (*xTokenize)(Fts5Tokenizer*, - void *pCtx, - int flags, /* Mask of FTS5_TOKENIZE_* flags */ - const char *pText, int nText, - int (*xToken)( - void *pCtx, /* Copy of 2nd argument to xTokenize() */ - int tflags, /* Mask of FTS5_TOKEN_* flags */ - const char *pToken, /* Pointer to buffer containing token */ - int nToken, /* Size of token in bytes */ - int iStart, /* Byte offset of token within input text */ - int iEnd /* Byte offset of end of token within input text */ - ) - ); -}; + /************************************************************************* + ** CUSTOM AUXILIARY FUNCTIONS + ** + ** Virtual table implementations may overload SQL functions by implementing + ** the sqlite3_module.xFindFunction() method. + */ + + typedef struct Fts5ExtensionApi Fts5ExtensionApi; + typedef struct Fts5Context Fts5Context; + typedef struct Fts5PhraseIter Fts5PhraseIter; + + typedef void (*fts5_extension_function)(const Fts5ExtensionApi* pApi, /* API offered by current FTS version */ + Fts5Context* pFts, /* First arg to pass to pApi functions */ + sqlite3_context* pCtx, /* Context for returning result/error */ + int nVal, /* Number of values in apVal[] array */ + sqlite3_value** apVal /* Array of trailing arguments */ + ); + + struct Fts5PhraseIter + { + const unsigned char* a; + const unsigned char* b; + }; + + /* + ** EXTENSION API FUNCTIONS + ** + ** xUserData(pFts): + ** Return a copy of the context pointer the extension function was + ** registered with. + ** + ** xColumnTotalSize(pFts, iCol, pnToken): + ** If parameter iCol is less than zero, set output variable *pnToken + ** to the total number of tokens in the FTS5 table. Or, if iCol is + ** non-negative but less than the number of columns in the table, return + ** the total number of tokens in column iCol, considering all rows in + ** the FTS5 table. + ** + ** If parameter iCol is greater than or equal to the number of columns + ** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g. + ** an OOM condition or IO error), an appropriate SQLite error code is + ** returned. + ** + ** xColumnCount(pFts): + ** Return the number of columns in the table. + ** + ** xColumnSize(pFts, iCol, pnToken): + ** If parameter iCol is less than zero, set output variable *pnToken + ** to the total number of tokens in the current row. Or, if iCol is + ** non-negative but less than the number of columns in the table, set + ** *pnToken to the number of tokens in column iCol of the current row. + ** + ** If parameter iCol is greater than or equal to the number of columns + ** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g. + ** an OOM condition or IO error), an appropriate SQLite error code is + ** returned. + ** + ** This function may be quite inefficient if used with an FTS5 table + ** created with the "columnsize=0" option. + ** + ** xColumnText: + ** This function attempts to retrieve the text of column iCol of the + ** current document. If successful, (*pz) is set to point to a buffer + ** containing the text in utf-8 encoding, (*pn) is set to the size in bytes + ** (not characters) of the buffer and SQLITE_OK is returned. Otherwise, + ** if an error occurs, an SQLite error code is returned and the final values + ** of (*pz) and (*pn) are undefined. + ** + ** xPhraseCount: + ** Returns the number of phrases in the current query expression. + ** + ** xPhraseSize: + ** Returns the number of tokens in phrase iPhrase of the query. Phrases + ** are numbered starting from zero. + ** + ** xInstCount: + ** Set *pnInst to the total number of occurrences of all phrases within + ** the query within the current row. Return SQLITE_OK if successful, or + ** an error code (i.e. SQLITE_NOMEM) if an error occurs. + ** + ** This API can be quite slow if used with an FTS5 table created with the + ** "detail=none" or "detail=column" option. If the FTS5 table is created + ** with either "detail=none" or "detail=column" and "content=" option + ** (i.e. if it is a contentless table), then this API always returns 0. + ** + ** xInst: + ** Query for the details of phrase match iIdx within the current row. + ** Phrase matches are numbered starting from zero, so the iIdx argument + ** should be greater than or equal to zero and smaller than the value + ** output by xInstCount(). + ** + ** Usually, output parameter *piPhrase is set to the phrase number, *piCol + ** to the column in which it occurs and *piOff the token offset of the + ** first token of the phrase. Returns SQLITE_OK if successful, or an error + ** code (i.e. SQLITE_NOMEM) if an error occurs. + ** + ** This API can be quite slow if used with an FTS5 table created with the + ** "detail=none" or "detail=column" option. + ** + ** xRowid: + ** Returns the rowid of the current row. + ** + ** xTokenize: + ** Tokenize text using the tokenizer belonging to the FTS5 table. + ** + ** xQueryPhrase(pFts5, iPhrase, pUserData, xCallback): + ** This API function is used to query the FTS table for phrase iPhrase + ** of the current query. Specifically, a query equivalent to: + ** + ** ... FROM ftstable WHERE ftstable MATCH $p ORDER BY rowid + ** + ** with $p set to a phrase equivalent to the phrase iPhrase of the + ** current query is executed. Any column filter that applies to + ** phrase iPhrase of the current query is included in $p. For each + ** row visited, the callback function passed as the fourth argument + ** is invoked. The context and API objects passed to the callback + ** function may be used to access the properties of each matched row. + ** Invoking Api.xUserData() returns a copy of the pointer passed as + ** the third argument to pUserData. + ** + ** If the callback function returns any value other than SQLITE_OK, the + ** query is abandoned and the xQueryPhrase function returns immediately. + ** If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK. + ** Otherwise, the error code is propagated upwards. + ** + ** If the query runs to completion without incident, SQLITE_OK is returned. + ** Or, if some error occurs before the query completes or is aborted by + ** the callback, an SQLite error code is returned. + ** + ** + ** xSetAuxdata(pFts5, pAux, xDelete) + ** + ** Save the pointer passed as the second argument as the extension function's + ** "auxiliary data". The pointer may then be retrieved by the current or any + ** future invocation of the same fts5 extension function made as part of + ** the same MATCH query using the xGetAuxdata() API. + ** + ** Each extension function is allocated a single auxiliary data slot for + ** each FTS query (MATCH expression). If the extension function is invoked + ** more than once for a single FTS query, then all invocations share a + ** single auxiliary data context. + ** + ** If there is already an auxiliary data pointer when this function is + ** invoked, then it is replaced by the new pointer. If an xDelete callback + ** was specified along with the original pointer, it is invoked at this + ** point. + ** + ** The xDelete callback, if one is specified, is also invoked on the + ** auxiliary data pointer after the FTS5 query has finished. + ** + ** If an error (e.g. an OOM condition) occurs within this function, + ** the auxiliary data is set to NULL and an error code returned. If the + ** xDelete parameter was not NULL, it is invoked on the auxiliary data + ** pointer before returning. + ** + ** + ** xGetAuxdata(pFts5, bClear) + ** + ** Returns the current auxiliary data pointer for the fts5 extension + ** function. See the xSetAuxdata() method for details. + ** + ** If the bClear argument is non-zero, then the auxiliary data is cleared + ** (set to NULL) before this function returns. In this case the xDelete, + ** if any, is not invoked. + ** + ** + ** xRowCount(pFts5, pnRow) + ** + ** This function is used to retrieve the total number of rows in the table. + ** In other words, the same value that would be returned by: + ** + ** SELECT count(*) FROM ftstable; + ** + ** xPhraseFirst() + ** This function is used, along with type Fts5PhraseIter and the xPhraseNext + ** method, to iterate through all instances of a single query phrase within + ** the current row. This is the same information as is accessible via the + ** xInstCount/xInst APIs. While the xInstCount/xInst APIs are more convenient + ** to use, this API may be faster under some circumstances. To iterate + ** through instances of phrase iPhrase, use the following code: + ** + ** Fts5PhraseIter iter; + ** int iCol, iOff; + ** for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff); + ** iCol>=0; + ** pApi->xPhraseNext(pFts, &iter, &iCol, &iOff) + ** ){ + ** // An instance of phrase iPhrase at offset iOff of column iCol + ** } + ** + ** The Fts5PhraseIter structure is defined above. Applications should not + ** modify this structure directly - it should only be used as shown above + ** with the xPhraseFirst() and xPhraseNext() API methods (and by + ** xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below). + ** + ** This API can be quite slow if used with an FTS5 table created with the + ** "detail=none" or "detail=column" option. If the FTS5 table is created + ** with either "detail=none" or "detail=column" and "content=" option + ** (i.e. if it is a contentless table), then this API always iterates + ** through an empty set (all calls to xPhraseFirst() set iCol to -1). + ** + ** xPhraseNext() + ** See xPhraseFirst above. + ** + ** xPhraseFirstColumn() + ** This function and xPhraseNextColumn() are similar to the xPhraseFirst() + ** and xPhraseNext() APIs described above. The difference is that instead + ** of iterating through all instances of a phrase in the current row, these + ** APIs are used to iterate through the set of columns in the current row + ** that contain one or more instances of a specified phrase. For example: + ** + ** Fts5PhraseIter iter; + ** int iCol; + ** for(pApi->xPhraseFirstColumn(pFts, iPhrase, &iter, &iCol); + ** iCol>=0; + ** pApi->xPhraseNextColumn(pFts, &iter, &iCol) + ** ){ + ** // Column iCol contains at least one instance of phrase iPhrase + ** } + ** + ** This API can be quite slow if used with an FTS5 table created with the + ** "detail=none" option. If the FTS5 table is created with either + ** "detail=none" "content=" option (i.e. if it is a contentless table), + ** then this API always iterates through an empty set (all calls to + ** xPhraseFirstColumn() set iCol to -1). + ** + ** The information accessed using this API and its companion + ** xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext + ** (or xInst/xInstCount). The chief advantage of this API is that it is + ** significantly more efficient than those alternatives when used with + ** "detail=column" tables. + ** + ** xPhraseNextColumn() + ** See xPhraseFirstColumn above. + */ + struct Fts5ExtensionApi + { + int iVersion; /* Currently always set to 3 */ + + void* (*xUserData)(Fts5Context*); + + int (*xColumnCount)(Fts5Context*); + int (*xRowCount)(Fts5Context*, sqlite3_int64* pnRow); + int (*xColumnTotalSize)(Fts5Context*, int iCol, sqlite3_int64* pnToken); + + int (*xTokenize)(Fts5Context*, + const char* pText, + int nText, /* Text to tokenize */ + void* pCtx, /* Context passed to xToken() */ + int (*xToken)(void*, int, const char*, int, int, int) /* Callback */ + ); + + int (*xPhraseCount)(Fts5Context*); + int (*xPhraseSize)(Fts5Context*, int iPhrase); + + int (*xInstCount)(Fts5Context*, int* pnInst); + int (*xInst)(Fts5Context*, int iIdx, int* piPhrase, int* piCol, int* piOff); + + sqlite3_int64 (*xRowid)(Fts5Context*); + int (*xColumnText)(Fts5Context*, int iCol, const char** pz, int* pn); + int (*xColumnSize)(Fts5Context*, int iCol, int* pnToken); + + int (*xQueryPhrase)(Fts5Context*, + int iPhrase, + void* pUserData, + int (*)(const Fts5ExtensionApi*, Fts5Context*, void*)); + int (*xSetAuxdata)(Fts5Context*, void* pAux, void (*xDelete)(void*)); + void* (*xGetAuxdata)(Fts5Context*, int bClear); + + int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*); + void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int* piCol, int* piOff); + + int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*); + void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int* piCol); + }; + + /* + ** CUSTOM AUXILIARY FUNCTIONS + *************************************************************************/ + + /************************************************************************* + ** CUSTOM TOKENIZERS + ** + ** Applications may also register custom tokenizer types. A tokenizer + ** is registered by providing fts5 with a populated instance of the + ** following structure. All structure methods must be defined, setting + ** any member of the fts5_tokenizer struct to NULL leads to undefined + ** behaviour. The structure methods are expected to function as follows: + ** + ** xCreate: + ** This function is used to allocate and initialize a tokenizer instance. + ** A tokenizer instance is required to actually tokenize text. + ** + ** The first argument passed to this function is a copy of the (void*) + ** pointer provided by the application when the fts5_tokenizer object + ** was registered with FTS5 (the third argument to xCreateTokenizer()). + ** The second and third arguments are an array of nul-terminated strings + ** containing the tokenizer arguments, if any, specified following the + ** tokenizer name as part of the CREATE VIRTUAL TABLE statement used + ** to create the FTS5 table. + ** + ** The final argument is an output variable. If successful, (*ppOut) + ** should be set to point to the new tokenizer handle and SQLITE_OK + ** returned. If an error occurs, some value other than SQLITE_OK should + ** be returned. In this case, fts5 assumes that the final value of *ppOut + ** is undefined. + ** + ** xDelete: + ** This function is invoked to delete a tokenizer handle previously + ** allocated using xCreate(). Fts5 guarantees that this function will + ** be invoked exactly once for each successful call to xCreate(). + ** + ** xTokenize: + ** This function is expected to tokenize the nText byte string indicated + ** by argument pText. pText may or may not be nul-terminated. The first + ** argument passed to this function is a pointer to an Fts5Tokenizer object + ** returned by an earlier call to xCreate(). + ** + ** The second argument indicates the reason that FTS5 is requesting + ** tokenization of the supplied text. This is always one of the following + ** four values: + ** + **
  • FTS5_TOKENIZE_DOCUMENT - A document is being inserted into + ** or removed from the FTS table. The tokenizer is being invoked to + ** determine the set of tokens to add to (or delete from) the + ** FTS index. + ** + **
  • FTS5_TOKENIZE_QUERY - A MATCH query is being executed + ** against the FTS index. The tokenizer is being called to tokenize + ** a bareword or quoted string specified as part of the query. + ** + **
  • (FTS5_TOKENIZE_QUERY | FTS5_TOKENIZE_PREFIX) - Same as + ** FTS5_TOKENIZE_QUERY, except that the bareword or quoted string is + ** followed by a "*" character, indicating that the last token + ** returned by the tokenizer will be treated as a token prefix. + ** + **
  • FTS5_TOKENIZE_AUX - The tokenizer is being invoked to + ** satisfy an fts5_api.xTokenize() request made by an auxiliary + ** function. Or an fts5_api.xColumnSize() request made by the same + ** on a columnsize=0 database. + **
+ ** + ** For each token in the input string, the supplied callback xToken() must + ** be invoked. The first argument to it should be a copy of the pointer + ** passed as the second argument to xTokenize(). The third and fourth + ** arguments are a pointer to a buffer containing the token text, and the + ** size of the token in bytes. The 4th and 5th arguments are the byte offsets + ** of the first byte of and first byte immediately following the text from + ** which the token is derived within the input. + ** + ** The second argument passed to the xToken() callback ("tflags") should + ** normally be set to 0. The exception is if the tokenizer supports + ** synonyms. In this case see the discussion below for details. + ** + ** FTS5 assumes the xToken() callback is invoked for each token in the + ** order that they occur within the input text. + ** + ** If an xToken() callback returns any value other than SQLITE_OK, then + ** the tokenization should be abandoned and the xTokenize() method should + ** immediately return a copy of the xToken() return value. Or, if the + ** input buffer is exhausted, xTokenize() should return SQLITE_OK. Finally, + ** if an error occurs with the xTokenize() implementation itself, it + ** may abandon the tokenization and return any error code other than + ** SQLITE_OK or SQLITE_DONE. + ** + ** SYNONYM SUPPORT + ** + ** Custom tokenizers may also support synonyms. Consider a case in which a + ** user wishes to query for a phrase such as "first place". Using the + ** built-in tokenizers, the FTS5 query 'first + place' will match instances + ** of "first place" within the document set, but not alternative forms + ** such as "1st place". In some applications, it would be better to match + ** all instances of "first place" or "1st place" regardless of which form + ** the user specified in the MATCH query text. + ** + ** There are several ways to approach this in FTS5: + ** + **
  1. By mapping all synonyms to a single token. In this case, using + ** the above example, this means that the tokenizer returns the + ** same token for inputs "first" and "1st". Say that token is in + ** fact "first", so that when the user inserts the document "I won + ** 1st place" entries are added to the index for tokens "i", "won", + ** "first" and "place". If the user then queries for '1st + place', + ** the tokenizer substitutes "first" for "1st" and the query works + ** as expected. + ** + **
  2. By querying the index for all synonyms of each query term + ** separately. In this case, when tokenizing query text, the + ** tokenizer may provide multiple synonyms for a single term + ** within the document. FTS5 then queries the index for each + ** synonym individually. For example, faced with the query: + ** + ** + ** ... MATCH 'first place' + ** + ** the tokenizer offers both "1st" and "first" as synonyms for the + ** first token in the MATCH query and FTS5 effectively runs a query + ** similar to: + ** + ** + ** ... MATCH '(first OR 1st) place' + ** + ** except that, for the purposes of auxiliary functions, the query + ** still appears to contain just two phrases - "(first OR 1st)" + ** being treated as a single phrase. + ** + **
  3. By adding multiple synonyms for a single term to the FTS index. + ** Using this method, when tokenizing document text, the tokenizer + ** provides multiple synonyms for each token. So that when a + ** document such as "I won first place" is tokenized, entries are + ** added to the FTS index for "i", "won", "first", "1st" and + ** "place". + ** + ** This way, even if the tokenizer does not provide synonyms + ** when tokenizing query text (it should not - to do so would be + ** inefficient), it doesn't matter if the user queries for + ** 'first + place' or '1st + place', as there are entries in the + ** FTS index corresponding to both forms of the first token. + **
+ ** + ** Whether it is parsing document or query text, any call to xToken that + ** specifies a tflags argument with the FTS5_TOKEN_COLOCATED bit + ** is considered to supply a synonym for the previous token. For example, + ** when parsing the document "I won first place", a tokenizer that supports + ** synonyms would call xToken() 5 times, as follows: + ** + ** + ** xToken(pCtx, 0, "i", 1, 0, 1); + ** xToken(pCtx, 0, "won", 3, 2, 5); + ** xToken(pCtx, 0, "first", 5, 6, 11); + ** xToken(pCtx, FTS5_TOKEN_COLOCATED, "1st", 3, 6, 11); + ** xToken(pCtx, 0, "place", 5, 12, 17); + ** + ** + ** It is an error to specify the FTS5_TOKEN_COLOCATED flag the first time + ** xToken() is called. Multiple synonyms may be specified for a single token + ** by making multiple calls to xToken(FTS5_TOKEN_COLOCATED) in sequence. + ** There is no limit to the number of synonyms that may be provided for a + ** single token. + ** + ** In many cases, method (1) above is the best approach. It does not add + ** extra data to the FTS index or require FTS5 to query for multiple terms, + ** so it is efficient in terms of disk space and query speed. However, it + ** does not support prefix queries very well. If, as suggested above, the + ** token "first" is substituted for "1st" by the tokenizer, then the query: + ** + ** + ** ... MATCH '1s*' + ** + ** will not match documents that contain the token "1st" (as the tokenizer + ** will probably not map "1s" to any prefix of "first"). + ** + ** For full prefix support, method (3) may be preferred. In this case, + ** because the index contains entries for both "first" and "1st", prefix + ** queries such as 'fi*' or '1s*' will match correctly. However, because + ** extra entries are added to the FTS index, this method uses more space + ** within the database. + ** + ** Method (2) offers a midpoint between (1) and (3). Using this method, + ** a query such as '1s*' will match documents that contain the literal + ** token "1st", but not "first" (assuming the tokenizer is not able to + ** provide synonyms for prefixes). However, a non-prefix query like '1st' + ** will match against "1st" and "first". This method does not require + ** extra disk space, as no extra entries are added to the FTS index. + ** On the other hand, it may require more CPU cycles to run MATCH queries, + ** as separate queries of the FTS index are required for each synonym. + ** + ** When using methods (2) or (3), it is important that the tokenizer only + ** provide synonyms when tokenizing document text (method (2)) or query + ** text (method (3)), not both. Doing so will not cause any errors, but is + ** inefficient. + */ + typedef struct Fts5Tokenizer Fts5Tokenizer; + typedef struct fts5_tokenizer fts5_tokenizer; + struct fts5_tokenizer + { + int (*xCreate)(void*, const char** azArg, int nArg, Fts5Tokenizer** ppOut); + void (*xDelete)(Fts5Tokenizer*); + int (*xTokenize)(Fts5Tokenizer*, + void* pCtx, + int flags, /* Mask of FTS5_TOKENIZE_* flags */ + const char* pText, + int nText, + int (*xToken)(void* pCtx, /* Copy of 2nd argument to xTokenize() */ + int tflags, /* Mask of FTS5_TOKEN_* flags */ + const char* pToken, /* Pointer to buffer containing token */ + int nToken, /* Size of token in bytes */ + int iStart, /* Byte offset of token within input text */ + int iEnd /* Byte offset of end of token within input text */ + )); + }; /* Flags that may be passed as the third argument to xTokenize() */ -#define FTS5_TOKENIZE_QUERY 0x0001 -#define FTS5_TOKENIZE_PREFIX 0x0002 -#define FTS5_TOKENIZE_DOCUMENT 0x0004 -#define FTS5_TOKENIZE_AUX 0x0008 +#define FTS5_TOKENIZE_QUERY 0x0001 +#define FTS5_TOKENIZE_PREFIX 0x0002 +#define FTS5_TOKENIZE_DOCUMENT 0x0004 +#define FTS5_TOKENIZE_AUX 0x0008 /* Flags that may be passed by the tokenizer implementation back to FTS5 ** as the third argument to the supplied xToken callback. */ -#define FTS5_TOKEN_COLOCATED 0x0001 /* Same position as prev. token */ - -/* -** END OF CUSTOM TOKENIZERS -*************************************************************************/ - -/************************************************************************* -** FTS5 EXTENSION REGISTRATION API -*/ -typedef struct fts5_api fts5_api; -struct fts5_api { - int iVersion; /* Currently always set to 2 */ - - /* Create a new tokenizer */ - int (*xCreateTokenizer)( - fts5_api *pApi, - const char *zName, - void *pContext, - fts5_tokenizer *pTokenizer, - void (*xDestroy)(void*) - ); - - /* Find an existing tokenizer */ - int (*xFindTokenizer)( - fts5_api *pApi, - const char *zName, - void **ppContext, - fts5_tokenizer *pTokenizer - ); - - /* Create a new auxiliary function */ - int (*xCreateFunction)( - fts5_api *pApi, - const char *zName, - void *pContext, - fts5_extension_function xFunction, - void (*xDestroy)(void*) - ); -}; - -/* -** END OF REGISTRATION API -*************************************************************************/ +#define FTS5_TOKEN_COLOCATED 0x0001 /* Same position as prev. token */ + + /* + ** END OF CUSTOM TOKENIZERS + *************************************************************************/ + + /************************************************************************* + ** FTS5 EXTENSION REGISTRATION API + */ + typedef struct fts5_api fts5_api; + struct fts5_api + { + int iVersion; /* Currently always set to 2 */ + + /* Create a new tokenizer */ + int (*xCreateTokenizer)(fts5_api* pApi, + const char* zName, + void* pContext, + fts5_tokenizer* pTokenizer, + void (*xDestroy)(void*)); + + /* Find an existing tokenizer */ + int (*xFindTokenizer)(fts5_api* pApi, const char* zName, void** ppContext, fts5_tokenizer* pTokenizer); + + /* Create a new auxiliary function */ + int (*xCreateFunction)(fts5_api* pApi, + const char* zName, + void* pContext, + fts5_extension_function xFunction, + void (*xDestroy)(void*)); + }; + + /* + ** END OF REGISTRATION API + *************************************************************************/ #ifdef __cplusplus -} /* end of the 'extern "C"' block */ +} /* end of the 'extern "C"' block */ #endif #endif /* _FTS5_H */ diff --git a/flint/cmd_line_parser.cpp b/flint/cmd_line_parser.cpp index 7c3932a4..62bd9b37 100644 --- a/flint/cmd_line_parser.cpp +++ b/flint/cmd_line_parser.cpp @@ -45,31 +45,34 @@ #include "mlxfwops/lib/flint_io.h" #ifndef FLINT_NAME - #ifdef __GNUC__ - #define FLINT_NAME "flint" - #else - #define FLINT_NAME "flint" - #endif +#ifdef __GNUC__ +#define FLINT_NAME "flint" +#else +#define FLINT_NAME "flint" +#endif #endif using namespace std; /****************************** -* Data structures containing -* Meta data about subcommands -* and flags -******************************/ -class SubCmdMetaData { + * Data structures containing + * Meta data about subcommands + * and flags + ******************************/ +class SubCmdMetaData +{ private: - class SubCmd { -public: - SubCmd(string s, string l, sub_cmd_t n) : shortf(s), longf(l), cmdNum(n) {} - ~SubCmd(){} + class SubCmd + { + public: + SubCmd(string s, string l, sub_cmd_t n) : shortf(s), longf(l), cmdNum(n) {} + ~SubCmd() {} string shortf; string longf; sub_cmd_t cmdNum; }; vector _sCmds; + public: SubCmdMetaData(); ~SubCmdMetaData(); @@ -127,33 +130,38 @@ SubCmdMetaData::SubCmdMetaData() SubCmdMetaData::~SubCmdMetaData() { - for (vector::iterator it = _sCmds.begin(); it != _sCmds.end(); ++it) { + for (vector::iterator it = _sCmds.begin(); it != _sCmds.end(); ++it) + { delete *it; } } sub_cmd_t SubCmdMetaData::getCmdNum(string flag) { - for (vector::iterator it = _sCmds.begin(); it != _sCmds.end(); ++it) { - if (((*it)->shortf == flag) || ((*it)->longf == flag)) { + for (vector::iterator it = _sCmds.begin(); it != _sCmds.end(); ++it) + { + if (((*it)->shortf == flag) || ((*it)->longf == flag)) + { return (*it)->cmdNum; } } return SC_No_Cmd; } - -class FlagMetaData { +class FlagMetaData +{ private: - class Flag { -public: - Flag(string s, string l, int n) : shortf(s), longf(l), argNum(n) {} - ~Flag(){} + class Flag + { + public: + Flag(string s, string l, int n) : shortf(s), longf(l), argNum(n) {} + ~Flag() {} string shortf; string longf; int argNum; }; vector _flags; + public: FlagMetaData(); ~FlagMetaData(); @@ -195,7 +203,8 @@ FlagMetaData::FlagMetaData() _flags.push_back(new Flag("", "striped_image", 0)); _flags.push_back(new Flag("", "banks", 1)); _flags.push_back(new Flag("", "log", 1)); - _flags.push_back(new Flag("", "flash_params", 1)); //its actually 3 but separated by comma so we refer to them as one + _flags.push_back(new Flag("", "flash_params", 1)); // its actually 3 but separated by comma so we refer to them as + // one _flags.push_back(new Flag("v", "version", 0)); _flags.push_back(new Flag("", "no_devid_check", 0)); _flags.push_back(new Flag("", "use_fw", 0)); @@ -228,10 +237,10 @@ FlagMetaData::FlagMetaData() _flags.push_back(new Flag("", "public_key_label", 1)); _flags.push_back(new Flag("", "hsm", 0)); #endif - _flags.push_back(new Flag("", "openssl_engine", 1)); - _flags.push_back(new Flag("", "openssl_key_id", 1)); + _flags.push_back(new Flag("", "openssl_engine", 1)); + _flags.push_back(new Flag("", "openssl_key_id", 1)); #ifdef __WIN__ - _flags.push_back(new Flag("", "cpu_util", 1)); + _flags.push_back(new Flag("", "cpu_util", 1)); #endif _flags.push_back(new Flag("", "output_file", 1)); _flags.push_back(new Flag("", "user_password", 1)); @@ -240,15 +249,18 @@ FlagMetaData::FlagMetaData() FlagMetaData::~FlagMetaData() { - for (vector::iterator it = _flags.begin(); it != _flags.end(); ++it) { + for (vector::iterator it = _flags.begin(); it != _flags.end(); ++it) + { delete *it; } } int FlagMetaData::getNumOfArgs(string flag) { - for (vector::iterator it = _flags.begin(); it != _flags.end(); ++it) { - if (((*it)->shortf == flag) || ((*it)->longf == flag)) { + for (vector::iterator it = _flags.begin(); it != _flags.end(); ++it) + { + if (((*it)->shortf == flag) || ((*it)->longf == flag)) + { return (*it)->argNum; } } @@ -260,16 +272,18 @@ int FlagMetaData::getNumOfArgs(string flag) *******************/ // NOTE : number of parameters extracted in the container should be checked. -static void splitByDelimiters(std::vector& container, string str, const char *delimiters ) +static void splitByDelimiters(std::vector& container, string str, const char* delimiters) { - if (str.size() == 0) { + if (str.size() == 0) + { return; } - char *cStr = strcpy(new char[str.size() + 1], str.c_str()); - char *ptr; + char* cStr = strcpy(new char[str.size() + 1], str.c_str()); + char* ptr; ptr = strtok(cStr, delimiters); - while (ptr != NULL) { + while (ptr != NULL) + { container.push_back(ptr); ptr = strtok(NULL, delimiters); } @@ -277,16 +291,19 @@ static void splitByDelimiters(std::vector& container, string str, const return; } -char* stripFlag(char *flag) +char* stripFlag(char* flag) { - char *strippedFlagStart = NULL; - if (flag[0] != '-') { // not a flag + char* strippedFlagStart = NULL; + if (flag[0] != '-') + { // not a flag return flag; - } - ; - if ((flag[0] == '-') && (flag[1] == '-')) { + }; + if ((flag[0] == '-') && (flag[1] == '-')) + { strippedFlagStart = &flag[2]; - } else { + } + else + { strippedFlagStart = &flag[1]; } return strippedFlagStart; @@ -294,12 +311,15 @@ char* stripFlag(char *flag) int countArgs(string args) { - if (args.size() == 0) { + if (args.size() == 0) + { return 0; } int count = 1; - for (string::iterator it = args.begin(); it < args.end(); ++it) { - if (*it == ',') { + for (string::iterator it = args.begin(); it < args.end(); ++it) + { + if (*it == ',') + { count++; } } @@ -308,45 +328,56 @@ int countArgs(string args) bool verifyNumOfArgs(string name, string value) { - //HACK : we don't check device numOfArgs because image device format might contain "," - if ((name == "device") || (name == "d") ) { + // HACK : we don't check device numOfArgs because image device format might contain "," + if ((name == "device") || (name == "d")) + { return true; } - if ((name == "image") || (name == "i") ) { + if ((name == "image") || (name == "i")) + { return true; } // Hack : VSD can be empty or contain "," so we shouldnt count its args - if (name == "vsd") { + if (name == "vsd") + { return true; } - if (name == "output_file") { + if (name == "output_file") + { return true; } int expected = FlagMetaData().getNumOfArgs(name); - if (expected < 0) { + if (expected < 0) + { printf(FLINT_INVALID_FLAG_ERROR, name.c_str()); return false; } - //HACK : flash_params is 3 argument but given with comma separated instead of spaces like the rest + // HACK : flash_params is 3 argument but given with comma separated instead of spaces like the rest // so flag_arg_num gives a wrong value - if (name == "flash_params") { + if (name == "flash_params") + { expected = 3; } int actual = countArgs(value); - if (name == "downstream_device_ids") { - if (actual < 1) { + if (name == "downstream_device_ids") + { + if (actual < 1) + { printf(FLINT_TOO_FEW_MINIMUM_ARGS_ERROR, 1, actual); return false; } return true; } - if (actual < expected) { + if (actual < expected) + { printf(FLINT_TOO_FEW_ARGS_ERROR, expected, actual); return false; - } else if (actual > expected) { + } + else if (actual > expected) + { printf(FLINT_TOO_MANY_ARGS_ERROR, expected, actual); return false; } @@ -355,10 +386,11 @@ bool verifyNumOfArgs(string name, string value) bool strToInt(string str, int& num, int base = 0) { - char *endp; - char *numStr = strcpy(new char[str.size() + 1], str.c_str()); + char* endp; + char* numStr = strcpy(new char[str.size() + 1], str.c_str()); num = strtol(numStr, &endp, base); - if (*endp) { + if (*endp) + { delete[] numStr; return false; } @@ -366,13 +398,13 @@ bool strToInt(string str, int& num, int base = 0) return true; } - bool strToNum(string str, u_int64_t& num, int base = 0) { - char *endp; - char *numStr = strcpy(new char[str.size() + 1], str.c_str()); + char* endp; + char* numStr = strcpy(new char[str.size() + 1], str.c_str()); num = strtoul(numStr, &endp, base); - if (*endp) { + if (*endp) + { delete[] numStr; return false; } @@ -380,16 +412,20 @@ bool strToNum(string str, u_int64_t& num, int base = 0) return true; } -//this function is used in extracting both guids and macs from user +// this function is used in extracting both guids and macs from user bool getGUIDFromStr(string str, guid_t& guid, string prefixErr = "") { - char *endp; + char* endp; u_int64_t g; g = strtoull(str.c_str(), &endp, 16); - if (*endp || (g == 0xffffffffffffffffULL && errno == ERANGE)) { - if (prefixErr.size() == 0) { - printf("-E- Invalid Guid/Mac/Uid syntax (%s) %s \n", str.c_str(), errno ? strerror(errno) : "" ); - } else { + if (*endp || (g == 0xffffffffffffffffULL && errno == ERANGE)) + { + if (prefixErr.size() == 0) + { + printf("-E- Invalid Guid/Mac/Uid syntax (%s) %s \n", str.c_str(), errno ? strerror(errno) : ""); + } + else + { printf("%s\n", prefixErr.c_str()); } return false; @@ -401,37 +437,46 @@ bool getGUIDFromStr(string str, guid_t& guid, string prefixErr = "") bool isElementPresent(vector strv, string str) //* should be renamed to isStrPresent, since it's not generic { - for (vector::iterator it = strv.begin(); it < strv.end(); it++) { - if (*it == str) { + for (vector::iterator it = strv.begin(); it < strv.end(); it++) + { + if (*it == str) + { return true; } } return false; } -bool stringsCommaSplit(string str, std::vector &deviceIds) //* Should be renamed to something like +bool stringsCommaSplit(string str, std::vector& deviceIds) //* Should be renamed to something like { //* getIntsFromCommaSplitString size_t pos; std::vector strv; bool res = true; - while ((pos = str.find(',')) != string::npos) { + while ((pos = str.find(',')) != string::npos) + { string tmp = str.substr(0, pos); - if (!isElementPresent(strv, tmp)) { //* Can be changed to: std::find(strv.begin(), strv.end(), tmp) != strv.end() - strv.push_back((string)tmp); //* So we can remove isElementPresent function + if (!isElementPresent(strv, tmp)) + { //* Can be changed to: std::find(strv.begin(), strv.end(), tmp) != strv.end() + strv.push_back((string)tmp); //* So we can remove isElementPresent function } str = str.substr(pos + 1); } - if (str != "") { - if (!isElementPresent(strv, str)) { //* Same as above + if (str != "") + { + if (!isElementPresent(strv, str)) + { //* Same as above strv.push_back((string)str); } } - for (std::vector::iterator it = strv.begin(); it < strv.end(); it++) { + for (std::vector::iterator it = strv.begin(); it < strv.end(); it++) + { int num; - if (false == strToInt((*it).c_str(), num)) { + if (false == strToInt((*it).c_str(), num)) + { return false; } - if (num < 0 || num > 255) { + if (num < 0 || num > 255) + { printf("Index value should be between 0 and 255.\n"); return false; } @@ -440,7 +485,6 @@ bool stringsCommaSplit(string str, std::vector &deviceIds) //* Should be re return res; } - guid_t incrGuid(guid_t baseGuid, unsigned int incrVal) { u_int64_t g = baseGuid.h; @@ -465,7 +509,8 @@ bool parseFlashParams(string params, flash_params_t& fp) // Step 1 split by "," std::vector paramVec; splitByDelimiters(paramVec, params, ","); - if (paramVec.size() != 3) { + if (paramVec.size() != 3) + { return false; } // Step 2 extract params @@ -474,11 +519,13 @@ bool parseFlashParams(string params, flash_params_t& fp) memset(fp.type_name, 0, MAX_FLASH_NAME); strncpy(fp.type_name, paramStr, length); u_int64_t tmp; - if (!strToNum(paramVec[1], tmp)) { + if (!strToNum(paramVec[1], tmp)) + { return false; } fp.log2size = (int)tmp; - if (!strToNum(paramVec[2], tmp)) { + if (!strToNum(paramVec[2], tmp)) + { return false; } fp.num_of_flashes = (int)tmp; @@ -486,9 +533,9 @@ bool parseFlashParams(string params, flash_params_t& fp) } /************************************ -* Implementation of the Command line -* Parsing part of the Flint class -************************************/ + * Implementation of the Command line + * Parsing part of the Flint class + ************************************/ #define FLASH_LIST_SZ 256 @@ -513,25 +560,13 @@ void Flint::initCmdParser() "Binary image file.\n" "Commands affected: burn, verify"); - AddOptions("latest_fw", - ' ', - "", - "Commands affected: burn"); + AddOptions("latest_fw", ' ', "", "Commands affected: burn"); - AddOptions("ir", - ' ', - "", - "Commands affected: burn"); + AddOptions("ir", ' ', "", "Commands affected: burn"); - AddOptions("help", - 'h', - "", - "Prints this message and exits"); + AddOptions("help", 'h', "", "Prints this message and exits"); - AddOptions("hh", - ' ', - "", - "Prints extended command help"); + AddOptions("hh", ' ', "", "Prints extended command help"); AddOptions("yes", 'y', @@ -631,16 +666,12 @@ void Flint::initCmdParser() "When specified, only flashed fw version is fetched\n" "Commands affected: query"); - AddOptions("nofs", - ' ', - "", - "Burn image in a non failsafe manner."); + AddOptions("nofs", ' ', "", "Burn image in a non failsafe manner."); - AddOptions("allow_psid_change", - ' ', - "", + AddOptions("allow_psid_change", ' ', "", "Allow burning a FW image with a different PSID (Parameter Set ID)than the one currently on flash. Note" - " that changing a PSID may cause the device to malfunction. Use only if you know what you are doing", isExternal); + " that changing a PSID may cause the device to malfunction. Use only if you know what you are doing", + isExternal); AddOptions("allow_rom_change", ' ', @@ -656,15 +687,9 @@ void Flint::initCmdParser() "NOTE: This flag is intended for advanced users only.\n" "Running in this mode may cause the firmware to hang.\n"); - AddOptions("no_flash_verify", - ' ', - "", - "Do not verify each write on the flash."); + AddOptions("no_flash_verify", ' ', "", "Do not verify each write on the flash."); - AddOptions("use_fw", - ' ', - "", - "Flash access will be done using FW (ConnectX-3/ConnectX-3Pro only)."); + AddOptions("use_fw", ' ', "", "Flash access will be done using FW (ConnectX-3/ConnectX-3Pro only)."); AddOptions("silent", 's', @@ -672,10 +697,7 @@ void Flint::initCmdParser() "Do not print burn progress flyer.\n" "Commands affected: burn"); - AddOptions("vsd", - ' ', - "", - "Write this string, of up to 208 characters, to VSD when burn."); + AddOptions("vsd", ' ', "", "Write this string, of up to 208 characters, to VSD when burn."); AddOptions("use_image_ps", ' ', @@ -708,28 +730,19 @@ void Flint::initCmdParser() " Only).\n" "Commands affected: burn"); - AddOptions("no_fw_ctrl", - ' ', - "", - "Do not attempt to work with the FW Ctrl update commands"); + AddOptions("no_fw_ctrl", ' ', "", "Do not attempt to work with the FW Ctrl update commands"); AddOptions("use_dev_img_info", ' ', "", "preserve select image info fields from the device upon FW update (FS3 Only).\n" "Commands affected: burn", - true); + true); - AddOptions("ignore_crc_check", - ' ', - "", - "Prevents flint from failing due to CRC check", + AddOptions("ignore_crc_check", ' ', "", "Prevents flint from failing due to CRC check", true); // hidden - AddOptions("hexdump_format", - ' ', - "", - "Prints rb command output in hexdump format", + AddOptions("hexdump_format", ' ', "", "Prints rb command output in hexdump format", true); // hidden AddOptions("dual_image", @@ -745,193 +758,128 @@ void Flint::initCmdParser() "Use this flag to indicate that the given image file is in a \"striped image\" format.\n" "Commands affected: query verify"); - AddOptions("banks", - ' ', - "", - "Set the number of attached flash devices (banks)"); + AddOptions("banks", ' ', "", "Set the number of attached flash devices (banks)"); - AddOptions("log", - ' ', - "", - "Print the burning status to the specified log file"); - - + AddOptions("log", ' ', "", "Print the burning status to the specified log file"); char flashList[FLASH_LIST_SZ] = {0}; char flashParDesc[FLASH_LIST_SZ * 2]; Flash::get_flash_list(flashList, FLASH_LIST_SZ); - snprintf(flashParDesc, FLASH_LIST_SZ * 2, "Use the given parameters to access the flash instead of reading them from " - "the flash.\n" \ - "Supported parameters:\n" \ - "Type: The type of the flash, such as:%s.\n" \ - "log2size: The log2 of the flash size." \ + snprintf(flashParDesc, FLASH_LIST_SZ * 2, + "Use the given parameters to access the flash instead of reading them from " + "the flash.\n" + "Supported parameters:\n" + "Type: The type of the flash, such as:%s.\n" + "log2size: The log2 of the flash size." "num_of_flashes: the number of the flashes connected to the device.", flashList); + AddOptions("flash_params", ' ', "", flashParDesc); - AddOptions("flash_params", - ' ', - "", flashParDesc); + AddOptions("version", 'v', "", "Version info."); - AddOptions("version", - 'v', - "", - "Version info."); + AddOptions("no_devid_check", ' ', "", "ignore device_id checks", true); - AddOptions("no_devid_check", - ' ', - "", - "ignore device_id checks", - true); + AddOptions("skip_ci_req", ' ', "", "skip sending cache image request to driver(windows)", true); - AddOptions("skip_ci_req", - ' ', - "", - "skip sending cache image request to driver(windows)", - true); + AddOptions("ocr", ' ', "", "another flag for override cache replacement", true); - AddOptions("ocr", - ' ', - "", - "another flag for override cache replacement", - true); + AddOptions("hsm", ' ', "", "flag for the sign command", true); - AddOptions("hsm", - ' ', - "", - "flag for the sign command", - true); + AddOptions("private_key", ' ', "", "path to PEM formatted private key to be used by the sign command"); - AddOptions("private_key", - ' ', - "", - "path to PEM formatted private key to be used by the sign command"); - - AddOptions("public_key", - ' ', - "", - "path to PEM formatted public key to be used by the sign command"); - AddOptions("key_uuid", - ' ', - "", - "UUID matching the given private key to be used by the sign command"); - AddOptions("private_key2", - ' ', - "", - "path to PEM formatted private key to be used by the sign command"); - AddOptions("hmac_key", - ' ', - "", - "path to file containing key (For FS4 image only)."); + AddOptions("public_key", ' ', "", "path to PEM formatted public key to be used by the sign command"); + AddOptions("key_uuid", ' ', "", "UUID matching the given private key to be used by the sign command"); + AddOptions("private_key2", ' ', "", "path to PEM formatted private key to be used by the sign command"); + AddOptions("hmac_key", ' ', "", "path to file containing key (For FS4 image only)."); - AddOptions("key_uuid2", - ' ', - "", - "UUID matching the given private key to be used by the sign command"); + AddOptions("key_uuid2", ' ', "", "UUID matching the given private key to be used by the sign command"); - AddOptions("psid", - ' ', - "", - "Use this PSID while burning livefish device using MFA2 archive"); + AddOptions("psid", ' ', "", "Use this PSID while burning livefish device using MFA2 archive"); - AddOptions("cc", - ' ', - "", - "Use this flag while burning to device a Congestion Control Component"); + AddOptions("cc", ' ', "", + "Use this flag while burning to device a Congestion Control Component"); - AddOptions("linkx", - ' ', - "", - "Use this flag while burning to device a LinkX Component"); + AddOptions("linkx", ' ', "", "Use this flag while burning to device a LinkX Component"); AddOptions("downstream_device_id_start_index", - ' ', - "", - "Use this flag while burning to device a LinkX Component. Begin from 0", - false, - false, - 1); + ' ', + "", + "Use this flag while burning to device a LinkX Component. Begin from 0", + false, + false, + 1); AddOptions("num_of_downstream_devices", - ' ', - "", - "Use this flag while burning to device a LinkX Component to specify the number of devices to burn", - false, - false, - 1); - - AddOptions("linkx_auto_update", - ' ', - "", - "Use this flag while burning all cable devices connected to host.", - false, - false, - 1); - - AddOptions("activate", - ' ', - "", - "Use this flag to apply the activation of all cable devices connected to host. By default, the activation is not performed.", - false, - false, - 1); - - AddOptions("activate_delay_sec", - ' ', - "", - "Use this flag to activate all cable devices connected to host with delay, acceptable values are between 0 and 255 (default - 1). Important: 'activate' flag must be set. This flag is relevant only for cable components.", - false, - false, - 1); - - AddOptions("download_transfer", - ' ', - "", - "Use this flag to perform the download and transfer of all cable data for cables. By default, the download and transfer are not performed . This flag is relevant only for cable components.", - false, - false, - 1); - - AddOptions("downstream_device_ids", - ' ', - "", - "Use this flag to specify the LNKX ports to perform query. List must be only comma-separated numbers, without spaces.", - false, - false, - 1); + ' ', + "", + "Use this flag while burning to device a LinkX Component to specify the number of devices to burn", + false, + false, + 1); + + AddOptions("linkx_auto_update", ' ', "", "Use this flag while burning all cable devices connected to host.", false, + false, 1); + + AddOptions( + "activate", + ' ', + "", + "Use this flag to apply the activation of all cable devices connected to host. By default, the activation is not performed.", + false, + false, + 1); + + AddOptions( + "activate_delay_sec", + ' ', + "", + "Use this flag to activate all cable devices connected to host with delay, acceptable values are between 0 and 255 (default - 1). Important: 'activate' flag must be set. This flag is relevant only for cable components.", + false, + false, + 1); + + AddOptions( + "download_transfer", + ' ', + "", + "Use this flag to perform the download and transfer of all cable data for cables. By default, the download and transfer are not performed . This flag is relevant only for cable components.", + false, + false, + 1); + + AddOptions( + "downstream_device_ids", + ' ', + "", + "Use this flag to specify the LNKX ports to perform query. List must be only comma-separated numbers, without spaces.", + false, + false, + 1); #ifndef __WIN__ - AddOptions("public_key_label", - ' ', - "", - "public key label to be used by the sign --hsm command"); - - AddOptions("private_key_label", - ' ', - "", - "private key label to be used by the sign --hsm command"); + AddOptions("public_key_label", ' ', "", "public key label to be used by the sign --hsm command"); + + AddOptions("private_key_label", ' ', "", "private key label to be used by the sign --hsm command"); #endif - AddOptions("openssl_engine", - ' ', - "", - "Name of the OpenSSL engine to used by the sign/rsa_sign commands to work with the HSM hardware via OpenSSL API"); - AddOptions("openssl_key_id", - ' ', - "", - "Key identification string to be used by the sign/rsa_sign commands to work with the HSM hardware via OpenSSL API"); - AddOptions("output_file", - ' ', - "", - "output file name for exporting the public key from PEM/BIN"); - AddOptions("user_password", - ' ', - "", - "the HSM user password string in order to work with HSM device"); + AddOptions( + "openssl_engine", + ' ', + "", + "Name of the OpenSSL engine to used by the sign/rsa_sign commands to work with the HSM hardware via OpenSSL API"); + AddOptions( + "openssl_key_id", + ' ', + "", + "Key identification string to be used by the sign/rsa_sign commands to work with the HSM hardware via OpenSSL API"); + AddOptions("output_file", ' ', "", "output file name for exporting the public key from PEM/BIN"); + AddOptions("user_password", ' ', "", "the HSM user password string in order to work with HSM device"); #ifdef __WIN__ - AddOptions("cpu_util", - ' ', - "", - "Use this flag to reduce CPU utilization while burning, Windows only. Legal values are from 1 (lowest CPU) to 5 (highest CPU)"); + AddOptions( + "cpu_util", + ' ', + "", + "Use this flag to reduce CPU utilization while burning, Windows only. Legal values are from 1 (lowest CPU) to 5 (highest CPU)"); #endif AddOptions( "cert_chain_index", @@ -942,14 +890,15 @@ void Flint::initCmdParser() "section according to given index.\n" "This flag is relevant only for set_attestation_cert_chain command."); - for (map_sub_cmd_t_to_subcommand::iterator it = _subcommands.begin(); it != _subcommands.end(); it++) { - if (it->first == SC_ResetCfg) { + for (map_sub_cmd_t_to_subcommand::iterator it = _subcommands.begin(); it != _subcommands.end(); it++) + { + if (it->first == SC_ResetCfg) + { // hidden command so "forget" mentioning it continue; } - string str1 = it->second->getFlagL() + ((it->second->getFlagS() == "") ? (" ") : - ("|")) + it->second->getFlagS() \ - + " " + it->second->getParam(); + string str1 = it->second->getFlagL() + ((it->second->getFlagS() == "") ? (" ") : ("|")) + + it->second->getFlagS() + " " + it->second->getParam(); string str2 = it->second->getDesc(); AddOptionalSectionData("COMMANDS SUMMARY", str1, str2); @@ -957,307 +906,467 @@ void Flint::initCmdParser() AddOptionalSectionData("RETURN VALUES", "0", "Successful completion."); AddOptionalSectionData("RETURN VALUES", "1", "An error has occurred."); - AddOptionalSectionData("RETURN VALUES", "7", "For burn command - burning new firmware option was not chosen by the user when prompted, thus the firmware burning process was aborted."); - + AddOptionalSectionData( + "RETURN VALUES", "7", + "For burn command - burning new firmware option was not chosen by the user when prompted, thus the firmware burning process was aborted."); - for (map_sub_cmd_t_to_subcommand::iterator it = _subcommands.begin(); it != _subcommands.end(); it++) { - if (it->first == SC_ResetCfg) { + for (map_sub_cmd_t_to_subcommand::iterator it = _subcommands.begin(); it != _subcommands.end(); it++) + { + if (it->first == SC_ResetCfg) + { // hidden command so "forget" mentioning it continue; } - string str = "Name:\n" - "\t" + it->second->getName() + "\n" - + "Description:\n" - "\t" + it->second->getExtDesc() + "\n" - + "Command:\n" - "\t" + it->second->getFlagL() + - ((it->second->getFlagS() == "") ? (" ") : ("|")) + it->second->getFlagS() - + " " + it->second->getParam() + "\n" - + "Parameters:\n" - "\t" + it->second->getParamExp() + "\n" - + "Examples:\n" - "\t" + it->second->getExample() + "\n\n\n"; + string str = "Name:\n" + "\t" + + it->second->getName() + "\n" + + "Description:\n" + "\t" + + it->second->getExtDesc() + "\n" + + "Command:\n" + "\t" + + it->second->getFlagL() + ((it->second->getFlagS() == "") ? (" ") : ("|")) + + it->second->getFlagS() + " " + it->second->getParam() + "\n" + + "Parameters:\n" + "\t" + + it->second->getParamExp() + "\n" + + "Examples:\n" + "\t" + + it->second->getExample() + "\n\n\n"; AddOptionalSectionData("COMMANDS DESCRIPTION", str); } - _cmdParser.AddRequester(this); } ParseStatus Flint::HandleOption(string name, string value) { - //TODO: consider verifying num of args inside each if statements that needs its arg num verified + // TODO: consider verifying num of args inside each if statements that needs its arg num verified // thus we will be able to get rid of the hacks inside the function in the expense of a longer code. - if (!(verifyNumOfArgs(name, value))) { + if (!(verifyNumOfArgs(name, value))) + { return PARSE_ERROR; } int delta = 1; - if (name == "device" || name == "d") { + if (name == "device" || name == "d") + { _flintParams.device_specified = true; _flintParams.device = value; - } else if (name == "help" || name == "h") { + } + else if (name == "help" || name == "h") + { vector excluded_sections; excluded_sections.push_back("COMMANDS DESCRIPTION"); cout << _cmdParser.GetUsage(false, excluded_sections); return PARSE_OK_WITH_EXIT; - } else if (name == "version" || name == "v") { + } + else if (name == "version" || name == "v") + { #ifdef EXTERNAL print_version_string(FLINT_NAME, ""); #else print_version_string(FLINT_NAME "(oem)", ""); #endif return PARSE_OK_WITH_EXIT; - } else if (name == "hh") { + } + else if (name == "hh") + { cout << _cmdParser.GetUsage(); return PARSE_OK_WITH_EXIT; - } else if (name == "no_devid_check") { + } + else if (name == "no_devid_check") + { _flintParams.no_devid_check = true; - } else if (name == "skip_ci_req") { + } + else if (name == "skip_ci_req") + { _flintParams.skip_ci_req = true; - } else if (name == "guid") { + } + else if (name == "guid") + { _flintParams.guid_specified = true; guid_t g; - if (!getGUIDFromStr(value, g)) { + if (!getGUIDFromStr(value, g)) + { return PARSE_ERROR; } - for (int i = 0; i < GUIDS; i++) { + for (int i = 0; i < GUIDS; i++) + { _flintParams.user_guids.push_back(incrGuid(g, i)); } - // for (std::vector::iterator it=_flintParams.user_guids.begin();it != _flintParams.user_guids.end(); it++){ + // for (std::vector::iterator it=_flintParams.user_guids.begin();it != _flintParams.user_guids.end(); + // it++){ // printf("%8.8x%8.8x\n",it->h,it->l); // } - } else if (name == "guids") { + } + else if (name == "guids") + { _flintParams.guids_specified = true; std::vector strs; splitByDelimiters(strs, value, ","); - if (strs.size() != GUIDS) { + if (strs.size() != GUIDS) + { return PARSE_ERROR; } - for (int i = 0; i < GUIDS; i++) { + for (int i = 0; i < GUIDS; i++) + { guid_t g; - if (!getGUIDFromStr(strs[i], g)) { + if (!getGUIDFromStr(strs[i], g)) + { return PARSE_ERROR; - } else { + } + else + { _flintParams.user_guids.push_back(g); } } - } else if (name == "mac") { + } + else if (name == "mac") + { _flintParams.mac_specified = true; guid_t m; - if (!getGUIDFromStr(value, m)) { + if (!getGUIDFromStr(value, m)) + { return PARSE_ERROR; } - for (int i = 0; i < MACS; i++) { + for (int i = 0; i < MACS; i++) + { _flintParams.user_macs.push_back(incrGuid(m, i)); } - } else if (name == "macs") { + } + else if (name == "macs") + { _flintParams.macs_specified = true; std::vector strs; splitByDelimiters(strs, value, ","); - if (strs.size() != MACS) { + if (strs.size() != MACS) + { return PARSE_ERROR; } - for (int i = 0; i < MACS; i++) { + for (int i = 0; i < MACS; i++) + { guid_t m; - if (!getGUIDFromStr(strs[i], m)) { + if (!getGUIDFromStr(strs[i], m)) + { return PARSE_ERROR; - } else { + } + else + { _flintParams.user_macs.push_back(m); } } - } else if (name == "uid") { + } + else if (name == "uid") + { _flintParams.uid_specified = true; - if (!getGUIDFromStr(value, _flintParams.baseUid)) { + if (!getGUIDFromStr(value, _flintParams.baseUid)) + { return PARSE_ERROR; } - } else if (name == "blank_guids") { + } + else if (name == "blank_guids") + { _flintParams.blank_guids = true; - } else if (name == "clear_semaphore") { + } + else if (name == "clear_semaphore") + { _flintParams.clear_semaphore = true; - } else if (name == "image" || name == "i") { + } + else if (name == "image" || name == "i") + { _flintParams.image_specified = true; _flintParams.image = value; - } else if (name == "qq") { + } + else if (name == "qq") + { _flintParams.quick_query = true; _flintParams.skip_rom_query = true; delta = 2; - } else if (name == "low_cpu") { + } + else if (name == "low_cpu") + { _flintParams.low_cpu = true; - } else if (name == "next_boot_fw_ver" || name == "flashed_version") { + } + else if (name == "next_boot_fw_ver" || name == "flashed_version") + { _flintParams.next_boot_fw_ver = true; - } else if (name == "nofs") { + } + else if (name == "nofs") + { _flintParams.nofs = true; - } else if (name == "allow_psid_change") { + } + else if (name == "allow_psid_change") + { _flintParams.allow_psid_change = true; - } else if (name == "allow_rom_change") { + } + else if (name == "allow_rom_change") + { _flintParams.allow_rom_change = true; - } else if (name == "override_cache_replacement" || name == "ocr") { + } + else if (name == "override_cache_replacement" || name == "ocr") + { _flintParams.override_cache_replacement = true; - } else if (name == "use_fw") { + } + else if (name == "use_fw") + { _flintParams.use_fw = true; - } else if (name == "no_flash_verify") { + } + else if (name == "no_flash_verify") + { _flintParams.no_flash_verify = true; - } else if (name == "silent" || name == "s") { + } + else if (name == "silent" || name == "s") + { _flintParams.silent = true; - } else if (name == "yes" || name == "y") { + } + else if (name == "yes" || name == "y") + { _flintParams.yes = true; - } else if (name == "no") { + } + else if (name == "no") + { _flintParams.no = true; - } else if (name == "vsd") { + } + else if (name == "vsd") + { _flintParams.vsd_specified = true; _flintParams.vsd = value; - } else if (name == "use_image_ps") { + } + else if (name == "use_image_ps") + { _flintParams.use_image_ps = true; - } else if (name == "use_image_guids") { + } + else if (name == "use_image_guids") + { _flintParams.use_image_guids = true; - } else if (name == "use_image_rom") { + } + else if (name == "use_image_rom") + { _flintParams.use_image_rom = true; - } else if (name == "use_dev_rom") { + } + else if (name == "use_dev_rom") + { _flintParams.use_dev_rom = true; - } else if (name == "ignore_dev_data") { + } + else if (name == "ignore_dev_data") + { _flintParams.ignore_dev_data = true; - } else if (name == "no_fw_ctrl") { + } + else if (name == "no_fw_ctrl") + { _flintParams.no_fw_ctrl = true; - } else if (name == "dual_image") { + } + else if (name == "dual_image") + { _flintParams.dual_image = true; - } else if (name == "striped_image") { + } + else if (name == "striped_image") + { _flintParams.striped_image = true; - } else if (name == "use_dev_img_info") { + } + else if (name == "use_dev_img_info") + { _flintParams.use_dev_img_info = true; - } else if (name == "ignore_crc_check") { + } + else if (name == "ignore_crc_check") + { _flintParams.ignore_crc_check = true; - } else if (name == "hexdump_format") { + } + else if (name == "hexdump_format") + { _flintParams.hexdump_format = true; - } else if (name == "ir") { + } + else if (name == "ir") + { _flintParams.image_reactivation = true; - } else if (name == "banks") { + } + else if (name == "banks") + { _flintParams.banks_specified = true; u_int64_t banksNum; - if (!strToNum(value, banksNum)) { + if (!strToNum(value, banksNum)) + { return PARSE_ERROR; } _flintParams.banks = (int)banksNum; - } else if (name == "log") { + } + else if (name == "log") + { _flintParams.log_specified = true; _flintParams.log = value; - } else if (name == "flash_params") { + } + else if (name == "flash_params") + { _flintParams.flash_params_specified = true; - if (!parseFlashParams(value, _flintParams.flash_params)) { + if (!parseFlashParams(value, _flintParams.flash_params)) + { return PARSE_ERROR; } - //printf("-D- flashType=%s , log2size = %d , numOfBanks = %d\n", _flintParams.flash_params.type_name, _flintParams.flash_params.log2size, _flintParams.flash_params.num_of_flashes); - } else if (name == "private_key") { + // printf("-D- flashType=%s , log2size = %d , numOfBanks = %d\n", _flintParams.flash_params.type_name, + // _flintParams.flash_params.log2size, _flintParams.flash_params.num_of_flashes); + } + else if (name == "private_key") + { _flintParams.privkey_specified = true; _flintParams.privkey_file = value; - } else if (name == "public_key") { + } + else if (name == "public_key") + { _flintParams.pubkey_specified = true; _flintParams.pubkey_file = value; - } else if (name == "key_uuid") { + } + else if (name == "key_uuid") + { _flintParams.uuid_specified = true; _flintParams.privkey_uuid = value; - } else if (name == "hmac_key") { + } + else if (name == "hmac_key") + { _flintParams.key_specified = true; _flintParams.key = value; - } else if (name == "private_key2") { + } + else if (name == "private_key2") + { _flintParams.privkey2_specified = true; _flintParams.privkey2_file = value; - } else if (name == "key_uuid2") { + } + else if (name == "key_uuid2") + { _flintParams.uuid2_specified = true; _flintParams.privkey2_uuid = value; - } else if (name == "latest_fw") { + } + else if (name == "latest_fw") + { _flintParams.use_latest_fw_version = true; - } else if (name == "psid") { + } + else if (name == "psid") + { _flintParams.use_psid = true; _flintParams.psid = value; } - else if (name == "cc") { + else if (name == "cc") + { _flintParams.congestion_control = true; _flintParams.congestion_control_param = value; } - else if (name == "linkx") { + else if (name == "linkx") + { _flintParams.linkx_control = true; } - else if (name == "cpu_util") { - _flintParams.use_cpu_utilization = true; - u_int64_t cpu_percent = 0; - if (!strToNum(value, cpu_percent)) { - return PARSE_ERROR; - } - _flintParams.cpu_percent = (int)cpu_percent; - } else if (name == "hsm") { + else if (name == "cpu_util") + { + _flintParams.use_cpu_utilization = true; + u_int64_t cpu_percent = 0; + if (!strToNum(value, cpu_percent)) + { + return PARSE_ERROR; + } + _flintParams.cpu_percent = (int)cpu_percent; + } + else if (name == "hsm") + { _flintParams.hsm_specified = true; - } else if (name == "openssl_engine") { - _flintParams.openssl_engine_usage_specified = true; - _flintParams.openssl_engine = value; - } else if (name == "openssl_key_id") { - _flintParams.openssl_engine_usage_specified = true; - _flintParams.openssl_key_id = value; - } else if (name == "private_key_label") { + } + else if (name == "openssl_engine") + { + _flintParams.openssl_engine_usage_specified = true; + _flintParams.openssl_engine = value; + } + else if (name == "openssl_key_id") + { + _flintParams.openssl_engine_usage_specified = true; + _flintParams.openssl_key_id = value; + } + else if (name == "private_key_label") + { _flintParams.private_key_label_specified = true; _flintParams.private_key_label = value; - } else if (name == "public_key_label") { + } + else if (name == "public_key_label") + { _flintParams.public_key_label_specified = true; _flintParams.public_key_label = value; - } else if (name == "output_file") { + } + else if (name == "output_file") + { _flintParams.output_file_specified = true; _flintParams.output_file = value; - } else if (name == "user_password") { + } + else if (name == "user_password") + { _flintParams.hsm_password_specified = true; _flintParams.hsm_password = value; - } else if (name == "downstream_device_id_start_index") { + } + else if (name == "downstream_device_id_start_index") + { _flintParams.cable_device_index_specified = true; int device_index = 0; - if (!strToInt(value, device_index)) { + if (!strToInt(value, device_index)) + { return PARSE_ERROR; } - if (device_index < 0) { + if (device_index < 0) + { return PARSE_ERROR; } _flintParams.cableDeviceIndex = device_index; - } - - else if (name == "activate") { - _flintParams.activate = true; } - else if (name == "activate_delay_sec") { + else if (name == "activate") + { + _flintParams.activate = true; + } + + else if (name == "activate_delay_sec") + { u_int64_t activate_delay_sec = 0; - if (!strToNum(value, activate_delay_sec)) { + if (!strToNum(value, activate_delay_sec)) + { return PARSE_ERROR; } - if (activate_delay_sec > 255) { + if (activate_delay_sec > 255) + { printf("Activation_delay_sec should be between 0 and 255.\n"); return PARSE_ERROR; } _flintParams.activate_delay_sec = activate_delay_sec; } - else if (name == "linkx_auto_update") { + else if (name == "linkx_auto_update") + { _flintParams.linkx_auto_update = true; - } + } - else if (name == "download_transfer") { - _flintParams.download_transfer = true; + else if (name == "download_transfer") + { + _flintParams.download_transfer = true; } - - else if (name == "downstream_device_ids") { - if (value == "all") { + + else if (name == "downstream_device_ids") + { + if (value == "all") + { _flintParams.linkx_auto_update = true; } - else { + else + { _flintParams.downstream_device_ids_specified = true; std::vector deviceIds; - if (!stringsCommaSplit(value, deviceIds)) { + if (!stringsCommaSplit(value, deviceIds)) + { return PARSE_ERROR; } _flintParams.downstream_device_ids = deviceIds; } } - else if (name == "num_of_downstream_devices") { + else if (name == "num_of_downstream_devices") + { int cableDeviceSize = 0; - if (!strToInt(value, cableDeviceSize)) { + if (!strToInt(value, cableDeviceSize)) + { return PARSE_ERROR; } - if (cableDeviceSize <= 0 || cableDeviceSize > 255) { + if (cableDeviceSize <= 0 || cableDeviceSize > 255) + { printf("Cable size should be between 1 and 255.\n"); return PARSE_ERROR; } @@ -1278,7 +1387,8 @@ ParseStatus Flint::HandleOption(string name, string value) } _flintParams.cert_chain_index = cert_chain_index; } - else { + else + { cout << "Unknown Flag: " << name; cout << _cmdParser.GetSynopsis(); return PARSE_ERROR; @@ -1289,23 +1399,26 @@ ParseStatus Flint::HandleOption(string name, string value) #define IS_NUM(cha) (((cha) >= '0') && ((cha) <= '9')) -ParseStatus Flint::parseCmdLine(int argc, char *argv[]) +ParseStatus Flint::parseCmdLine(int argc, char* argv[]) { - //Step1 separate between option section and cmd section + // Step1 separate between option section and cmd section SubCmdMetaData subCmds; FlagMetaData flags; - char **argvCmd = NULL; - char **argvOpt = NULL; + char** argvCmd = NULL; + char** argvOpt = NULL; int argcCmd = 0, argcOpt = 0; bool foundOptionWhenLookingForCmd = false; ParseStatus rc; - char **newArgv = NULL; + char** newArgv = NULL; int newArgc = 0; int i = 1, j = 1, argStart = 1, argEnd = 1; - for (int k = (argc - 1); k > 0; k--) { // Parsing command line from end to start - if ((subCmds.getCmdNum(argv[k])) != SC_No_Cmd) { // i.e we found a subcommand - if (foundOptionWhenLookingForCmd) { + for (int k = (argc - 1); k > 0; k--) + { // Parsing command line from end to start + if ((subCmds.getCmdNum(argv[k])) != SC_No_Cmd) + { // i.e we found a subcommand + if (foundOptionWhenLookingForCmd) + { cout << "Specifying options flags after command is not allowed.\n\n"; rc = PARSE_ERROR_SHOW_USAGE; goto clean_up; @@ -1314,45 +1427,56 @@ ParseStatus Flint::parseCmdLine(int argc, char *argv[]) argvOpt = argv; argcCmd = argc - k; argvCmd = &argv[k]; - } else if (argv[k][0] == '-' && !IS_NUM(argv[k][1])) { + } + else if (argv[k][0] == '-' && !IS_NUM(argv[k][1])) + { foundOptionWhenLookingForCmd = true; } } - if (argcCmd == 0) { - //no subcommand found + if (argcCmd == 0) + { + // no subcommand found argcOpt = argc; argvOpt = argv; } - //printf("-D- argcOpt:%d argvOpt:%s argcCmd:%d argvCmd:%s\n", argcOpt, argvOpt[0], argcCmd, argvCmd[0]); + // printf("-D- argcOpt:%d argvOpt:%s argcCmd:%d argvCmd:%s\n", argcOpt, argvOpt[0], argcCmd, argvCmd[0]); //_cmdparser should deal with the case of no arguments in argv except the program. - //Step2 unite with comma multiple args in the options section + // Step2 unite with comma multiple args in the options section newArgv = new char*[argcOpt]; - //first arg is the flint command we can copy as is + // first arg is the flint command we can copy as is newArgv[0] = strcpy(new char[strlen(argvOpt[0]) + 1], argvOpt[0]); - while (i < argcOpt) { - if (argvOpt[i][0] == '-' && !IS_NUM(argvOpt[i][1])) { //its a flag (and not a number) so we copy to new_argv as is - newArgv[j] = strcpy(new char[strlen(argvOpt[i]) + 1], - argvOpt[i]); + while (i < argcOpt) + { + if (argvOpt[i][0] == '-' && !IS_NUM(argvOpt[i][1])) + { // its a flag (and not a number) so we copy to new_argv as is + newArgv[j] = strcpy(new char[strlen(argvOpt[i]) + 1], argvOpt[i]); i++; j++; - } else { //its an argument - //find next flag if exsists + } + else + { // its an argument + // find next flag if exsists argStart = i; argEnd = i; int argsSize = 0; - while (argEnd < argcOpt && (argvOpt[argEnd][0] != '-' || IS_NUM(argvOpt[argEnd][1]))) { - argsSize += strlen(argvOpt[argEnd]) + 1; //for the comma + while (argEnd < argcOpt && (argvOpt[argEnd][0] != '-' || IS_NUM(argvOpt[argEnd][1]))) + { + argsSize += strlen(argvOpt[argEnd]) + 1; // for the comma argEnd++; } i = argEnd; - //concatenate all the args with comma between them to a single string + // concatenate all the args with comma between them to a single string newArgv[j] = new char[argsSize + 1]; newArgv[j][0] = '\0'; - while (argStart < argEnd) { - if (argStart == argEnd - 1) { - //no need to add comma to the last arg + while (argStart < argEnd) + { + if (argStart == argEnd - 1) + { + // no need to add comma to the last arg strcat(newArgv[j], argvOpt[argStart]); - } else { + } + else + { strcat(newArgv[j], argvOpt[argStart]); strcat(newArgv[j], ","); } @@ -1363,44 +1487,55 @@ ParseStatus Flint::parseCmdLine(int argc, char *argv[]) } newArgc = j; - //Step3 set the command and its args in the FlintParams struct if present - if (argcCmd > 0) { + // Step3 set the command and its args in the FlintParams struct if present + if (argcCmd > 0) + { this->_flintParams.cmd = subCmds.getCmdNum(argvCmd[0]); - for (int i = 1; i < argcCmd; ++i) { + for (int i = 1; i < argcCmd; ++i) + { this->_flintParams.cmd_params.push_back(string(argvCmd[i])); } - } else { //no command found deal with either missing/invalid command - //find last flag + } + else + { // no command found deal with either missing/invalid command + // find last flag int lastFlagPos; - char *strippedFlag; - for (lastFlagPos = argc - 1; lastFlagPos > 0; lastFlagPos--) { - if (argv[lastFlagPos][0] == '-' && !IS_NUM(argv[lastFlagPos][1])) { + char* strippedFlag; + for (lastFlagPos = argc - 1; lastFlagPos > 0; lastFlagPos--) + { + if (argv[lastFlagPos][0] == '-' && !IS_NUM(argv[lastFlagPos][1])) + { break; } } - if (lastFlagPos == 0) { + if (lastFlagPos == 0) + { cout << FLINT_NO_OPTIONS_FOUND_ERROR << endl; rc = PARSE_ERROR; goto clean_up; } strippedFlag = stripFlag(argv[lastFlagPos]); - //check how many args it needs + // check how many args it needs int numOfArgs = flags.getNumOfArgs(strippedFlag); - //if too many args return arg in pos num_of_args+1 as the invalid command. - if ((argc - 1 - lastFlagPos) > numOfArgs) { + // if too many args return arg in pos num_of_args+1 as the invalid command. + if ((argc - 1 - lastFlagPos) > numOfArgs) + { printf(FLINT_INVALID_COMMAD_ERROR, argv[argc - 1]); rc = PARSE_ERROR_SHOW_USAGE; goto clean_up; } } - //Step5 parse option section using _cmdParser + // Step5 parse option section using _cmdParser rc = this->_cmdParser.ParseOptions(newArgc, newArgv); // Step 6 Delete allocated memory -clean_up: for (int i = 0; i < newArgc; i++) { +clean_up: + for (int i = 0; i < newArgc; i++) + { delete[] newArgv[i]; } delete[] newArgv; - if (rc == PARSE_ERROR_SHOW_USAGE) { + if (rc == PARSE_ERROR_SHOW_USAGE) + { cout << _cmdParser.GetSynopsis(); } return rc; diff --git a/flint/err_msgs.h b/flint/err_msgs.h index f5e92e33..f2555922 100644 --- a/flint/err_msgs.h +++ b/flint/err_msgs.h @@ -37,7 +37,6 @@ * */ - #ifndef __ERR_MSGS_H__ #define __ERR_MSGS_H__ @@ -45,7 +44,8 @@ * Flint Status Code *********************/ -typedef enum { +typedef enum +{ FLINT_SUCCESS = 0, FLINT_FAILED = 1, FLINT_QUERY_ERROR = 2, @@ -56,142 +56,150 @@ typedef enum { * Flint Error Messages **********************/ -#define FLINT_CLEAR_SEM_CMD_ERROR "No command is allowed when -clear_semaphore flag is given.\n" -#define FLINT_COMMAND_FLAGS_ERROR "For %s command, Please specify %s.\n" -#define FLINT_COMMAND_INCORRECT_FLAGS_ERROR "For %s command, %s.\n" -#define FLINT_PARSE_MEM_ERROR "Failed to allocate memory for parsing.\n " -#define FLINT_NO_OPTIONS_FOUND_ERROR "No options found. " -#define FLINT_INVALID_COMMAD_ERROR "Invalid command: %s\n" -#define FLINT_TOO_MANY_ARGS_ERROR "Too many arguments. Expected: %d , Received: %d\n" -#define FLINT_TOO_FEW_ARGS_ERROR "Too few arguments. Expected: %d , Received: %d\n" -#define FLINT_TOO_FEW_MINIMUM_ARGS_ERROR "Too few arguments. Expected at least: %d , Received: %d\n" -#define FLINT_NO_COMMAND_ERROR "No command found." -#define FLINT_OPEN_FWOPS_DEVICE_ERROR "Cannot open Device: %s. %s\n" -#define FLINT_OPEN_FWOPS_DEVICE_ERROR_1 "Cannot open Device: %s.\n" -#define FLINT_OPEN_FWOPS_IMAGE_ERROR "Cannot open Image: %s. %s\n" -#define FLINT_DEVICE_AND_IMAGE_ERROR "Please specify either Device or Image.\n" -#define FLINT_NO_DEVICE_ERROR "Please specify Device.\n" -#define FLINT_NO_IMAGE_ERROR "Please specify Image file.\n" -#define FLINT_MISSED_ARG_ERROR "Missed %s parameter after \"%s\" command.\n" -#define FLINT_CMD_ARGS_ERROR "Command \"%s\" requires %d arguments, but %d arguments were given\n" -#define FLINT_CMD_ARGS_ERROR2 "Command \"%s\" requires at most %d arguments, but %d arguments were given\n" -#define FLINT_CMD_ARGS_ERROR3 "Command \"%s\" requires at least %d arguments, but %d arguments were given\n" -#define FLINT_CMD_ARGS_ERROR4 "Command \"%s\" requires %d or %d arguments, but %d arguments were given\n" -#define FLINT_CMD_ARGS_ERROR5 "Command \"%s\" does not require arguments\n" -#define FLINT_INVALID_OPTION_ERROR "Unknown option \"%s\" for the \"%s\" command. you can use %s.\n" -#define FLINT_INVALID_FLAG_ERROR "Invalid switch \"%s\" is specified.\n" -#define FLINT_INVALID_FLAG_ERROR_5TH_GEN "Invalid switch \"%s\" is specified for 5th gen device.\n" -#define FLINT_INVALID_FLAG_WITH_FLAG_ERROR "Cannot specify \"%s\" flag with \"%s\" flag.\n" +#define FLINT_CLEAR_SEM_CMD_ERROR "No command is allowed when -clear_semaphore flag is given.\n" +#define FLINT_COMMAND_FLAGS_ERROR "For %s command, Please specify %s.\n" +#define FLINT_COMMAND_INCORRECT_FLAGS_ERROR "For %s command, %s.\n" +#define FLINT_PARSE_MEM_ERROR "Failed to allocate memory for parsing.\n " +#define FLINT_NO_OPTIONS_FOUND_ERROR "No options found. " +#define FLINT_INVALID_COMMAD_ERROR "Invalid command: %s\n" +#define FLINT_TOO_MANY_ARGS_ERROR "Too many arguments. Expected: %d , Received: %d\n" +#define FLINT_TOO_FEW_ARGS_ERROR "Too few arguments. Expected: %d , Received: %d\n" +#define FLINT_TOO_FEW_MINIMUM_ARGS_ERROR "Too few arguments. Expected at least: %d , Received: %d\n" +#define FLINT_NO_COMMAND_ERROR "No command found." +#define FLINT_OPEN_FWOPS_DEVICE_ERROR "Cannot open Device: %s. %s\n" +#define FLINT_OPEN_FWOPS_DEVICE_ERROR_1 "Cannot open Device: %s.\n" +#define FLINT_OPEN_FWOPS_IMAGE_ERROR "Cannot open Image: %s. %s\n" +#define FLINT_DEVICE_AND_IMAGE_ERROR "Please specify either Device or Image.\n" +#define FLINT_NO_DEVICE_ERROR "Please specify Device.\n" +#define FLINT_NO_IMAGE_ERROR "Please specify Image file.\n" +#define FLINT_MISSED_ARG_ERROR "Missed %s parameter after \"%s\" command.\n" +#define FLINT_CMD_ARGS_ERROR "Command \"%s\" requires %d arguments, but %d arguments were given\n" +#define FLINT_CMD_ARGS_ERROR2 "Command \"%s\" requires at most %d arguments, but %d arguments were given\n" +#define FLINT_CMD_ARGS_ERROR3 "Command \"%s\" requires at least %d arguments, but %d arguments were given\n" +#define FLINT_CMD_ARGS_ERROR4 "Command \"%s\" requires %d or %d arguments, but %d arguments were given\n" +#define FLINT_CMD_ARGS_ERROR5 "Command \"%s\" does not require arguments\n" +#define FLINT_INVALID_OPTION_ERROR "Unknown option \"%s\" for the \"%s\" command. you can use %s.\n" +#define FLINT_INVALID_FLAG_ERROR "Invalid switch \"%s\" is specified.\n" +#define FLINT_INVALID_FLAG_ERROR_5TH_GEN "Invalid switch \"%s\" is specified for 5th gen device.\n" +#define FLINT_INVALID_FLAG_WITH_FLAG_ERROR "Cannot specify \"%s\" flag with \"%s\" flag.\n" #define FLINT_INVALID_FLAG_WITHOUT_FLAG_ERROR "\"%s\" flag must be specified with \"%s\" flag.\n" -#define FLINT_INVALID_FLAG_WITH_CMD_ERROR "Cannot specify flag: %s with Command: %s\n" -#define FLINT_CMD_VERIFY_ERROR "FW image verification failed: %s. AN HCA DEVICE CAN NOT BOOT FROM THIS IMAGE.\n" -#define FLINT_CMD_VERIFY_ERROR_1 "FW image verification failed: No valid FS4 image found.Check the flash parameters, if specified..AN HCA DEVICE CAN NOT BOOT FROM THIS IMAGE" -#define FLINT_FAILED_QUERY_ERROR "Failed to query %s: %s. %s\n" -#define FLINT_COMMAND_DEVICE_IMAGE_ERROR "Command \"%s\" requires both image and device to be specified.\n" -#define FLINT_COMMAND_DEVICE_ERROR "Command \"%s\" requires device, but an image file was given.\n" -#define FLINT_COMMAND_IMAGE_ERROR "Command \"%s\" requires an image file, but device was given.\n" -#define FLINT_COMMAND_DEVICE_ERROR2 "Command \"%s\" requires device, but both an image file and a device are given.\n" -#define FLINT_COMMAND_IMAGE_ERROR2 "Command \"%s\" requires an image, but both an image file and a device are given.\n" -#define FLINT_HW_SET_ARGS_ERROR "bad argument of hw set command : %s, it should be in the format PARAM_NAME=VALUE\n" -#define FLINT_HW_COMMAND_ERROR "HW %s failed. %s\n" -#define FLINT_SWRESET_ERROR "Software reset failed. %s\n" -#define FLINT_ERASE_SEC_ERROR "Erase sector failed. %s\n" -#define FLINT_INVALID_ADDR_ERROR "Invalid address \"%s\"\n" -#define FLINT_FLASH_READ_ERROR "Flash read failed. %s\n" -#define FLINT_FLASH_WRITE_ERROR "Flash write failed. %s\n" -#define FLINT_INVALID_DATA_ERROR "Invalid data \"%s\"\n" -#define FLINT_INVALID_SIZE_ERROR "Invalid size \"%s\", Length should be 4-bytes aligned.\n" -#define FLINT_INVALID_ARG_ERROR "Invalid argument \"%s\"\n" -#define FLINT_OPEN_FILE_ERROR "Cannot open %s: %s\n" -#define FLINT_WRITE_FILE_ERROR "Failed to write to %s: %s\n" -#define FLINT_IO_OPEN_ERROR "Failed to open %s: %s\n" -#define FLINT_IMAGE_READ_ERROR "Failed to read image. %s\n" -#define FLINT_READ_ERROR "Failed to read from %s. %s\n" -#define FLINT_READ_FILE_ERROR "Failed to read from %s.\n" -#define FLINT_WIN_NOT_SUPP_ERROR "Command \"%s\" is not supported in windows.\n" -#define FLINT_WIN_ONLY_SUPP_ERROR "Command \"%s\" is supported only in windows.\n" -#define FLINT_GEN_COMMAND_ERROR "Failed to execute command %s. %s\n" -#define FLINT_FS3_BB_ERROR "bb command is not supported anymore in FS3/FS4 images, please use b for burning FS3/FS4 images.\n" -#define FLINT_FSX_BURN_ERROR "Burning %s image failed: %s\n" -#define FLINT_FS2_BURN_ERROR "Burning FS2 image failed: %s\n" -#define FLINT_PSID_ERROR "PSID mismatch. The PSID on flash (%s) differs from the PSID in the given image (%s).\n" -#define FLINT_FS2_STRIPED_ERROR "The -striped_image cannot be used with the burn command\n" -#define FLINT_IMG_DEV_COMPAT_ERROR "The given device requires an %s image type, but the given image file does not contain an %s FW image\n" -#define FLINT_UNKNOWN_FW_TYPE_ERROR "Unknown Firmware Type.\n" -#define FLINT_READ_ROM_ERROR "Read ROM failed. %s\n" -#define FLINT_SG_GUID_ERROR "Cannot set GUIDs: %s\n" -#define FLINT_SG_UID_ERROR "Failed to set UID: %s\n" -#define FLINT_MFG_ERROR "Failed to set manufacture guids: %s\n" -#define FLINT_VSD_ERROR "Failed to set the VSD: %s\n" -#define FLINT_VPD_ERROR "Failed to set VPD: %s\n" -#define FLINT_CERT_CHAIN_ERROR "Failed to set attestation certificate chain: %s\n" -#define FLINT_SET_KEY_ERROR "Failed to set the HW access key: %s\n" -#define FLINT_RESET_CFG_ERROR "Failed to reset Configuration: %s\n" -#define FLINT_FIX_IMG_ERROR "Failed to fix device image: %s\n" -#define FLINT_DROM_ERROR "Remove ROM failed: %s\n" -#define FLINT_BROM_ERROR "Burn ROM failed: %s\n" -#define FLINT_DUMP_ERROR "Failed dumping %s : %s\n" -#define FLINT_ROM_QUERY_ERROR "Image file rom (%s) query failed. %s\n" -#define FLINT_WB_FILE_ERROR "failed to open file: %s. %s\n" -#define FLINT_WB_ERROR "write Block Failed. %s\n" -#define FLINT_NO_ZLIB_ERROR "Executable was compiled with \"dump files\" option disabled.\n" -#define FLINT_FLAG_WITH_FLAG_ERROR "\"%s\" flag must be specified with \"%s\" flag.\n" -#define FLINT_INVALID_PASSWORD "Invalid Password.\n" -#define FLINT_NO_GUID_MAC_FLAGS_ERROR "Can not set GUIDs/MACs: please run with -uid/-guid/-mac flag.\n" -#define FLINT_NOT_SUPP_UID_FLAG_ERROR "Can not set GUIDs/MACs: %s flag is not supported for this device.\nPlease run with -uid/-guid/-mac flag.\n" -#define FLINT_NO_UID_FLAG_ERROR "Can not set GUIDs/MACs: uid is not specified, please run with -uid flag.\n" -#define FLINT_CHECKSUM_ERROR "Failed to calculate checksum on %s: %s\n" -#define FLINT_CHECKSUM_MISMATCH_ERROR "Given checksum: %s does not match the checksum calculated on device FW: %s.\n" -#define FLINT_CHECKSUM_PARSE_ERROR "Failed to parse given checksum.\n" -#define FLINT_CHECKSUM_LEN_ERROR "MD5 checksum should be exactly 16 bytes long.\n" -#define FLINT_CHECKSUM_HEX_ERROR "MD5 checksum should contain only hexadecimal digits.\n" -#define FLINT_CACHE_IMAGE_ERROR "Failed to issue image cache request to driver. %s. make sure Mellanox driver is loaded and working properly.\n" -#define FLINT_SET_PUBLIC_KEYS_ERROR "Failed to set the public keys: %s\n" -#define FLINT_SET_FORBIDDEN_VERSIONS_ERROR "Failed to set the forbidden versions: %s\n" -#define FLINT_SIGN_ERROR "Failed to sign the image: %s\n" -#define FLINT_HMAC_ERROR "Failed to add HMAC: %s\n" +#define FLINT_INVALID_FLAG_WITH_CMD_ERROR "Cannot specify flag: %s with Command: %s\n" +#define FLINT_CMD_VERIFY_ERROR "FW image verification failed: %s. AN HCA DEVICE CAN NOT BOOT FROM THIS IMAGE.\n" +#define FLINT_CMD_VERIFY_ERROR_1 \ + "FW image verification failed: No valid FS4 image found.Check the flash parameters, if specified..AN HCA DEVICE CAN NOT BOOT FROM THIS IMAGE" +#define FLINT_FAILED_QUERY_ERROR "Failed to query %s: %s. %s\n" +#define FLINT_COMMAND_DEVICE_IMAGE_ERROR "Command \"%s\" requires both image and device to be specified.\n" +#define FLINT_COMMAND_DEVICE_ERROR "Command \"%s\" requires device, but an image file was given.\n" +#define FLINT_COMMAND_IMAGE_ERROR "Command \"%s\" requires an image file, but device was given.\n" +#define FLINT_COMMAND_DEVICE_ERROR2 "Command \"%s\" requires device, but both an image file and a device are given.\n" +#define FLINT_COMMAND_IMAGE_ERROR2 "Command \"%s\" requires an image, but both an image file and a device are given.\n" +#define FLINT_HW_SET_ARGS_ERROR "bad argument of hw set command : %s, it should be in the format PARAM_NAME=VALUE\n" +#define FLINT_HW_COMMAND_ERROR "HW %s failed. %s\n" +#define FLINT_SWRESET_ERROR "Software reset failed. %s\n" +#define FLINT_ERASE_SEC_ERROR "Erase sector failed. %s\n" +#define FLINT_INVALID_ADDR_ERROR "Invalid address \"%s\"\n" +#define FLINT_FLASH_READ_ERROR "Flash read failed. %s\n" +#define FLINT_FLASH_WRITE_ERROR "Flash write failed. %s\n" +#define FLINT_INVALID_DATA_ERROR "Invalid data \"%s\"\n" +#define FLINT_INVALID_SIZE_ERROR "Invalid size \"%s\", Length should be 4-bytes aligned.\n" +#define FLINT_INVALID_ARG_ERROR "Invalid argument \"%s\"\n" +#define FLINT_OPEN_FILE_ERROR "Cannot open %s: %s\n" +#define FLINT_WRITE_FILE_ERROR "Failed to write to %s: %s\n" +#define FLINT_IO_OPEN_ERROR "Failed to open %s: %s\n" +#define FLINT_IMAGE_READ_ERROR "Failed to read image. %s\n" +#define FLINT_READ_ERROR "Failed to read from %s. %s\n" +#define FLINT_READ_FILE_ERROR "Failed to read from %s.\n" +#define FLINT_WIN_NOT_SUPP_ERROR "Command \"%s\" is not supported in windows.\n" +#define FLINT_WIN_ONLY_SUPP_ERROR "Command \"%s\" is supported only in windows.\n" +#define FLINT_GEN_COMMAND_ERROR "Failed to execute command %s. %s\n" +#define FLINT_FS3_BB_ERROR \ + "bb command is not supported anymore in FS3/FS4 images, please use b for burning FS3/FS4 images.\n" +#define FLINT_FSX_BURN_ERROR "Burning %s image failed: %s\n" +#define FLINT_FS2_BURN_ERROR "Burning FS2 image failed: %s\n" +#define FLINT_PSID_ERROR "PSID mismatch. The PSID on flash (%s) differs from the PSID in the given image (%s).\n" +#define FLINT_FS2_STRIPED_ERROR "The -striped_image cannot be used with the burn command\n" +#define FLINT_IMG_DEV_COMPAT_ERROR \ + "The given device requires an %s image type, but the given image file does not contain an %s FW image\n" +#define FLINT_UNKNOWN_FW_TYPE_ERROR "Unknown Firmware Type.\n" +#define FLINT_READ_ROM_ERROR "Read ROM failed. %s\n" +#define FLINT_SG_GUID_ERROR "Cannot set GUIDs: %s\n" +#define FLINT_SG_UID_ERROR "Failed to set UID: %s\n" +#define FLINT_MFG_ERROR "Failed to set manufacture guids: %s\n" +#define FLINT_VSD_ERROR "Failed to set the VSD: %s\n" +#define FLINT_VPD_ERROR "Failed to set VPD: %s\n" +#define FLINT_CERT_CHAIN_ERROR "Failed to set attestation certificate chain: %s\n" +#define FLINT_SET_KEY_ERROR "Failed to set the HW access key: %s\n" +#define FLINT_RESET_CFG_ERROR "Failed to reset Configuration: %s\n" +#define FLINT_FIX_IMG_ERROR "Failed to fix device image: %s\n" +#define FLINT_DROM_ERROR "Remove ROM failed: %s\n" +#define FLINT_BROM_ERROR "Burn ROM failed: %s\n" +#define FLINT_DUMP_ERROR "Failed dumping %s : %s\n" +#define FLINT_ROM_QUERY_ERROR "Image file rom (%s) query failed. %s\n" +#define FLINT_WB_FILE_ERROR "failed to open file: %s. %s\n" +#define FLINT_WB_ERROR "write Block Failed. %s\n" +#define FLINT_NO_ZLIB_ERROR "Executable was compiled with \"dump files\" option disabled.\n" +#define FLINT_FLAG_WITH_FLAG_ERROR "\"%s\" flag must be specified with \"%s\" flag.\n" +#define FLINT_INVALID_PASSWORD "Invalid Password.\n" +#define FLINT_NO_GUID_MAC_FLAGS_ERROR "Can not set GUIDs/MACs: please run with -uid/-guid/-mac flag.\n" +#define FLINT_NOT_SUPP_UID_FLAG_ERROR \ + "Can not set GUIDs/MACs: %s flag is not supported for this device.\nPlease run with -uid/-guid/-mac flag.\n" +#define FLINT_NO_UID_FLAG_ERROR "Can not set GUIDs/MACs: uid is not specified, please run with -uid flag.\n" +#define FLINT_CHECKSUM_ERROR "Failed to calculate checksum on %s: %s\n" +#define FLINT_CHECKSUM_MISMATCH_ERROR "Given checksum: %s does not match the checksum calculated on device FW: %s.\n" +#define FLINT_CHECKSUM_PARSE_ERROR "Failed to parse given checksum.\n" +#define FLINT_CHECKSUM_LEN_ERROR "MD5 checksum should be exactly 16 bytes long.\n" +#define FLINT_CHECKSUM_HEX_ERROR "MD5 checksum should contain only hexadecimal digits.\n" +#define FLINT_CACHE_IMAGE_ERROR \ + "Failed to issue image cache request to driver. %s. make sure Mellanox driver is loaded and working properly.\n" +#define FLINT_SET_PUBLIC_KEYS_ERROR "Failed to set the public keys: %s\n" +#define FLINT_SET_FORBIDDEN_VERSIONS_ERROR "Failed to set the forbidden versions: %s\n" +#define FLINT_SIGN_ERROR "Failed to sign the image: %s\n" +#define FLINT_HMAC_ERROR "Failed to add HMAC: %s\n" #define FLINT_FAILED_IMAGE_REACTIVATION_ERROR "Failed to execute image reactivation on device %s. Error: %s.\n" -#define FLINT_NO_MFA2 "MFA2 funcionality is not supported" -#define FLINT_NO_HSM "HSM funcionality is not supported" -#define FLINT_ILLEGAL_CPU_VALUE "Illegal value for CPU utilization. Values must be between 1 (low CPU) and 5 (high CPU).\n" -#define FLINT_FILE_SIZE_ERROR "Can not get file size for \"%s\".\n" -#define FAILED_TO_VERIFY_PARAMS "Failed to verify params(internal error)." -#define INVALID_GUID_SYNTAX "Invalid GUID syntax (%s) %s\n" -#define FAILED_GET_CONSOLE_MODE "Failed to get console mode.\n" -#define USER_ABORT "Aborted by user\n" -#define SECTION_NOT_FOUNT "%s section not found in the given image." -#define UNCOMPRESSS_ERROR "Failed uncompressing FW configuration section. uncompress returns %d" -#define OPEN_WRITE_FILE_ERROR "Can not open file %s for write: %s." -#define IMAGE_SIGN_TYPE_ERROR "Image signing is applicable only for selected FW images. Please check your image type.\n" -#define HSM_INIT_ERROR "HSM init has failed! Please check if the HSM card installed and configured properly.\n" -#define HSM_PRIVATE_KEY_DUPLICATE "Creating HSM signature has failed - the private key label is duplicated.\n" -#define HSM_PUBLIC_KEY_DUPLICATE "Creating HSM signature has failed - the public key label is duplicated.\n" -#define HSM_SIGNATURE_CREATION_FAILED "Creating HSM signature has failed\n" -#define HSM_UUID_MISSING "To Sign the image with RSA you must provide UUID with HSM sign.\n" -#define HSM_PRIVATE_KEY_LABEL_MISSING "Must supply private key label for sign with HSM sign.\n" -#define HSM_PASSWORD_MISSING "Must supply HSM user password for sign with HSM sign.\n" -#define SIGN_PRIVATE_KEY_NOT_FOUND "Can't find private key file %s \n" -#define SIGN_PUBLIC_KEY_NOT_FOUND "Can't find public key file %s \n" -#define HSM_BOOT_SIGNATURE_CREATION_FAILED "Creating HSM BOOT signature has failed\n" +#define FLINT_NO_MFA2 "MFA2 funcionality is not supported" +#define FLINT_NO_HSM "HSM funcionality is not supported" +#define FLINT_ILLEGAL_CPU_VALUE \ + "Illegal value for CPU utilization. Values must be between 1 (low CPU) and 5 (high CPU).\n" +#define FLINT_FILE_SIZE_ERROR "Can not get file size for \"%s\".\n" +#define FAILED_TO_VERIFY_PARAMS "Failed to verify params(internal error)." +#define INVALID_GUID_SYNTAX "Invalid GUID syntax (%s) %s\n" +#define FAILED_GET_CONSOLE_MODE "Failed to get console mode.\n" +#define USER_ABORT "Aborted by user\n" +#define SECTION_NOT_FOUNT "%s section not found in the given image." +#define UNCOMPRESSS_ERROR "Failed uncompressing FW configuration section. uncompress returns %d" +#define OPEN_WRITE_FILE_ERROR "Can not open file %s for write: %s." +#define IMAGE_SIGN_TYPE_ERROR "Image signing is applicable only for selected FW images. Please check your image type.\n" +#define HSM_INIT_ERROR "HSM init has failed! Please check if the HSM card installed and configured properly.\n" +#define HSM_PRIVATE_KEY_DUPLICATE "Creating HSM signature has failed - the private key label is duplicated.\n" +#define HSM_PUBLIC_KEY_DUPLICATE "Creating HSM signature has failed - the public key label is duplicated.\n" +#define HSM_SIGNATURE_CREATION_FAILED "Creating HSM signature has failed\n" +#define HSM_UUID_MISSING "To Sign the image with RSA you must provide UUID with HSM sign.\n" +#define HSM_PRIVATE_KEY_LABEL_MISSING "Must supply private key label for sign with HSM sign.\n" +#define HSM_PASSWORD_MISSING "Must supply HSM user password for sign with HSM sign.\n" +#define SIGN_PRIVATE_KEY_NOT_FOUND "Can't find private key file %s \n" +#define SIGN_PUBLIC_KEY_NOT_FOUND "Can't find public key file %s \n" +#define HSM_BOOT_SIGNATURE_CREATION_FAILED "Creating HSM BOOT signature has failed\n" #define HSM_CRITICAL_SIGNATURE_CREATION_FAILED "Creating HSM critical signature has failed\n" #define HSM_NON_CRITICAL_SIGNATURE_CREATION_FAILED "Creating HSM non-critical signature has failed\n" -#define HSM_SECURE_BOOT_SIGNATURE_FAILED "Inserting secure BOOT signatures has failed : %s.\n" -#define HSM_SECURE_FW_SIGNATURE_FAILED "Creation secured FW signatures has failed.\n" -#define LINKX_QUERY_DEVICE_NOT_SUPPORTED "Linkx query for device %s is not supported.\n" -#define LINKX_BURN_DEVICE_NOT_SUPPORTED "Linkx burn for device %s is not supported.\n" +#define HSM_SECURE_BOOT_SIGNATURE_FAILED "Inserting secure BOOT signatures has failed : %s.\n" +#define HSM_SECURE_FW_SIGNATURE_FAILED "Creation secured FW signatures has failed.\n" +#define LINKX_QUERY_DEVICE_NOT_SUPPORTED "Linkx query for device %s is not supported.\n" +#define LINKX_BURN_DEVICE_NOT_SUPPORTED "Linkx burn for device %s is not supported.\n" /************************** * Flint Warning Messages *************************/ -#define FLINT_QQ_WARRNING "-W- Running quick query - Skipping full image integrity checks.\n" -#define FLINT_NOT_MLNX_FW_WARNING "-W- Not a Mellanox FW image (vendor_id = 0x%04x). VSD and PSID are not displayed.\n" -#define FLINT_BLANK_GUIDS_WARNING "-W- GUIDs/MACs values and their CRC are not set.\n" -#define FLINT_MULTI_BIT_WARNING "Multicast bit (bit 40) is set." -#define FLINT_MORE_48_BITS_WARNING "More than 48 bits are used." -#define FLINT_BAD_MAC_ADRESS_WARNING "\n-W- Bad mac address ( %4.4x%8.8x ): %s\n" -#define FLINT_MAC_ENTRIES_WARNING "-W- Cannot get MAC address: Expecting %d entries in guid section, got %d. Probably an old FW image. Please update.\n" -#define FLINT_INTERRUPT_WARRNING "\n-W- An internal error occurred. This program cannot be interrupted.\n" -#define FLINT_SET_GUIDS_WARRNING "-W- GUIDs are already set, re-burning image with the new GUIDs ...\n" -#define FLINT_OCR_WARRNING "\n-W- Firmware flash cache access is enabled. Running in this mode may cause the firmware to hang.\n" -#define FLINT_OPEN_LOG_FILE_WARNING "-W- Failed to open log file \"%s\": %s. No logs will be saved\n" +#define FLINT_QQ_WARRNING "-W- Running quick query - Skipping full image integrity checks.\n" +#define FLINT_NOT_MLNX_FW_WARNING "-W- Not a Mellanox FW image (vendor_id = 0x%04x). VSD and PSID are not displayed.\n" +#define FLINT_BLANK_GUIDS_WARNING "-W- GUIDs/MACs values and their CRC are not set.\n" +#define FLINT_MULTI_BIT_WARNING "Multicast bit (bit 40) is set." +#define FLINT_MORE_48_BITS_WARNING "More than 48 bits are used." +#define FLINT_BAD_MAC_ADRESS_WARNING "\n-W- Bad mac address ( %4.4x%8.8x ): %s\n" +#define FLINT_MAC_ENTRIES_WARNING \ + "-W- Cannot get MAC address: Expecting %d entries in guid section, got %d. Probably an old FW image. Please update.\n" +#define FLINT_INTERRUPT_WARRNING "\n-W- An internal error occurred. This program cannot be interrupted.\n" +#define FLINT_SET_GUIDS_WARRNING "-W- GUIDs are already set, re-burning image with the new GUIDs ...\n" +#define FLINT_OCR_WARRNING \ + "\n-W- Firmware flash cache access is enabled. Running in this mode may cause the firmware to hang.\n" +#define FLINT_OPEN_LOG_FILE_WARNING "-W- Failed to open log file \"%s\": %s. No logs will be saved\n" #endif diff --git a/flint/flint.cpp b/flint/flint.cpp index a4bffbe5..503c25be 100644 --- a/flint/flint.cpp +++ b/flint/flint.cpp @@ -42,10 +42,10 @@ #include "flint.h" -//Globals: -Flint *gFlint = NULL; -extern FILE *flint_log_fh; -//signal handler section +// Globals: +Flint* gFlint = NULL; +extern FILE* flint_log_fh; +// signal handler section #define BURN_INTERRUPTED 0x1234 @@ -54,44 +54,45 @@ void TerminationHandler(int signum); #ifdef __WIN__ #include -static BOOL CtrlHandler( DWORD fdwCtrlType ) +static BOOL CtrlHandler(DWORD fdwCtrlType) { switch (fdwCtrlType) { - // Handle the CTRL-C signal. - case CTRL_C_EVENT: - // CTRL-CLOSE: confirm that the user wants to exit. - case CTRL_CLOSE_EVENT: - // Pass other signals to the next handler. - case CTRL_BREAK_EVENT: - case CTRL_LOGOFF_EVENT: - case CTRL_SHUTDOWN_EVENT: - TerminationHandler(SIGINT); - return TRUE; + // Handle the CTRL-C signal. + case CTRL_C_EVENT: + // CTRL-CLOSE: confirm that the user wants to exit. + case CTRL_CLOSE_EVENT: + // Pass other signals to the next handler. + case CTRL_BREAK_EVENT: + case CTRL_LOGOFF_EVENT: + case CTRL_SHUTDOWN_EVENT: + TerminationHandler(SIGINT); + return TRUE; - default: - return FALSE; + default: + return FALSE; } } #endif - void TerminationHandler(int signum) { static volatile sig_atomic_t fatal_error_in_progress = 0; - if (fatal_error_in_progress) { + if (fatal_error_in_progress) + { raise(signum); } fatal_error_in_progress = 1; write_result_to_log(BURN_INTERRUPTED, ""); close_log(); - if (gFlint != NULL) { + if (gFlint != NULL) + { printf("\n Received signal %d. Cleaning up ...\n", signum); fflush(stdout); - //sleep(1); // Legacy from the Old Flint + // sleep(1); // Legacy from the Old Flint gFlint->GetSubCommands()[gFlint->GetFlintParams().cmd]->cleanInterruptedCommand(); delete gFlint; gFlint = NULL; @@ -111,30 +112,32 @@ static int signalList[SIGNAL_NUM] = {SIGINT, SIGTERM, SIGPIPE, SIGHUP}; void initHandler() { - #ifdef __WIN__ - SetConsoleCtrlHandler( (PHANDLER_ROUTINE) CtrlHandler, true ); + SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, true); #endif - //set the signal handler - for (int i = 0; i < SIGNAL_NUM; i++) { + // set the signal handler + for (int i = 0; i < SIGNAL_NUM; i++) + { void (*prevFunc)(int); prevFunc = signal(signalList[i], TerminationHandler); - if (prevFunc == SIG_ERR) { + if (prevFunc == SIG_ERR) + { printf("-E- failed to set signal Handler."); exit(FLINT_FAILED); } } } -void ignoreSignals() { - for (int i = 0; i < SIGNAL_NUM; i++) { +void ignoreSignals() +{ + for (int i = 0; i < SIGNAL_NUM; i++) + { signal(signalList[i], SIG_IGN); } } -//End of signal handler section. - +// End of signal handler section. map_sub_cmd_t_to_subcommand Flint::initSubcommandMap() { @@ -181,8 +184,8 @@ map_sub_cmd_t_to_subcommand Flint::initSubcommandMap() cmdMap[SC_Set_Forbidden_Versions] = new SetForbiddenVersionsSubCommand(); cmdMap[SC_Image_Reactivation] = new ImageReactivationSubCommand(); cmdMap[SC_RSA_Sign] = new SignRSASubCommand(); - cmdMap[SC_Binary_Compare] = new BinaryCompareSubCommand(); - cmdMap[SC_Import_Hsm_Key] = new ImportHsmKeySubCommand(); + cmdMap[SC_Binary_Compare] = new BinaryCompareSubCommand(); + cmdMap[SC_Import_Hsm_Key] = new ImportHsmKeySubCommand(); #ifndef NO_OPEN_SSL cmdMap[SC_Export_Public_Key] = new ExportPublicSubCommand(); #endif @@ -195,7 +198,6 @@ void Flint::deInitSubcommandMap(map_sub_cmd_t_to_subcommand cmdMap) delete it->second; } - Flint::Flint() : CommandLineRequester(FLINT_DISPLAY_NAME " [OPTIONS] [Parameters]"), _flintParams(), @@ -210,51 +212,64 @@ Flint::~Flint() deInitSubcommandMap(_subcommands); } -FlintStatus Flint::run(int argc, char *argv[]) +FlintStatus Flint::run(int argc, char* argv[]) { - //Step1 parse input - //There are some memory allocations parseCmdLine + // Step1 parse input + // There are some memory allocations parseCmdLine ParseStatus status; - try { + try + { status = this->parseCmdLine(argc, argv); - } catch (exception& e) { + } + catch (exception& e) + { cout << "-E- " << e.what() << endl; return FLINT_FAILED; } - if (status == PARSE_OK_WITH_EXIT) { + if (status == PARSE_OK_WITH_EXIT) + { return FLINT_SUCCESS; - } else if (status == PARSE_ERROR || status == PARSE_ERROR_SHOW_USAGE) { - if (string(_cmdParser.GetErrDesc()).length() > 0) { + } + else if (status == PARSE_ERROR || status == PARSE_ERROR_SHOW_USAGE) + { + if (string(_cmdParser.GetErrDesc()).length() > 0) + { cout << "-E- " << this->_cmdParser.GetErrDesc() << endl; } return FLINT_FAILED; } - if (_flintParams.cmd == SC_No_Cmd && !_flintParams.clear_semaphore) { + if (_flintParams.cmd == SC_No_Cmd && !_flintParams.clear_semaphore) + { cout << FLINT_NO_COMMAND_ERROR << endl; return FLINT_FAILED; } - if (_flintParams.clear_semaphore) { - if (_flintParams.cmd != SC_No_Cmd) { + if (_flintParams.clear_semaphore) + { + if (_flintParams.cmd != SC_No_Cmd) + { printf(FLINT_CLEAR_SEM_CMD_ERROR); return FLINT_FAILED; } _flintParams.cmd = SC_Clear_Sem; } - //TODO: adrianc: remove use_fw flag and this condition before MFT-4.1.0 - if (_flintParams.use_fw && _flintParams.override_cache_replacement) { + // TODO: adrianc: remove use_fw flag and this condition before MFT-4.1.0 + if (_flintParams.use_fw && _flintParams.override_cache_replacement) + { printf("-E- flags --use_fw and --override_cache_replacement/-ocr cannot be specified simultaneously"); return FLINT_FAILED; } // Step 2 save argv as a single cmd string in flint params for the log functionality - for (int i = 0; i < argc; i++) { + for (int i = 0; i < argc; i++) + { _flintParams.fullCmd = _flintParams.fullCmd + argv[i] + " "; } - //TODO: Step 3 check flintParams for contradictions? - //Step 4 execute command from the correct subcommand class - if (_subcommands.count(_flintParams.cmd) == 0) { + // TODO: Step 3 check flintParams for contradictions? + // Step 4 execute command from the correct subcommand class + if (_subcommands.count(_flintParams.cmd) == 0) + { // should not be reached printf("-E- FATAL: command object not found."); return FLINT_FAILED; @@ -263,15 +278,15 @@ FlintStatus Flint::run(int argc, char *argv[]) return _subcommands[_flintParams.cmd]->executeCommand(); } - -int main(int argc, char *argv[]) +int main(int argc, char* argv[]) { initHandler(); try { gFlint = new Flint(); FlintStatus rc = gFlint->run(argc, argv); - if (gFlint) { + if (gFlint) + { ignoreSignals(); // clean-up should be signal free, prevent possible clean-up re-entry delete gFlint; gFlint = NULL; diff --git a/flint/flint.h b/flint/flint.h index cfd1fb0a..e77b682f 100644 --- a/flint/flint.h +++ b/flint/flint.h @@ -48,9 +48,9 @@ using namespace std; -typedef map map_sub_cmd_t_to_subcommand; -typedef map map_string_to_string; -typedef map map_string_to_int; +typedef map map_sub_cmd_t_to_subcommand; +typedef map map_string_to_string; +typedef map map_string_to_int; map_string_to_string initShortToLongFlagMap(); map_string_to_int initLongFlagToNumOfArgsMap(); @@ -64,7 +64,7 @@ class Flint : public CommandLineRequester CommandLineParser _cmdParser; map_sub_cmd_t_to_subcommand _subcommands; - //methods + // methods map_sub_cmd_t_to_subcommand initSubcommandMap(); void deInitSubcommandMap(map_sub_cmd_t_to_subcommand cmdMap); @@ -73,8 +73,8 @@ class Flint : public CommandLineRequester ~Flint(); void initCmdParser(); virtual ParseStatus HandleOption(string name, string value); - ParseStatus parseCmdLine(int argc, char *argv[]); - FlintStatus run(int argc, char *argv[]); + ParseStatus parseCmdLine(int argc, char* argv[]); + FlintStatus run(int argc, char* argv[]); FlintParams& GetFlintParams() { return _flintParams; } map_sub_cmd_t_to_subcommand& GetSubCommands() { return _subcommands; } }; diff --git a/flint/flint_params.cpp b/flint/flint_params.cpp index 1d769313..5795eceb 100644 --- a/flint/flint_params.cpp +++ b/flint/flint_params.cpp @@ -53,7 +53,7 @@ FlintParams::FlintParams() device_specified = false; blank_guids = false; clear_semaphore = false; - quick_query = true; //should now be true by default + quick_query = true; // should now be true by default next_boot_fw_ver = false; low_cpu = false; skip_rom_query = false; @@ -118,11 +118,8 @@ FlintParams::FlintParams() downstream_device_ids_specified = false; download_transfer = false; // if no delay specified, use minimal delay to avoid disconnection in case of activating the connect port - activate_delay_sec = 1; + activate_delay_sec = 1; openssl_engine_usage_specified = false; } -FlintParams::~FlintParams() -{ - -} +FlintParams::~FlintParams() {} diff --git a/flint/flint_params.h b/flint/flint_params.h index b28f237a..28ff3caa 100644 --- a/flint/flint_params.h +++ b/flint/flint_params.h @@ -47,7 +47,8 @@ using namespace std; -typedef enum { +typedef enum +{ SC_No_Cmd = 0, SC_Burn, SC_Query, @@ -94,9 +95,10 @@ typedef enum { SC_Export_Public_Key } sub_cmd_t; -class FlintParams { +class FlintParams +{ public: - //add more params + // add more params FlintParams(); ~FlintParams(); bool device_specified; @@ -188,7 +190,7 @@ class FlintParams { bool hsm_password_specified; string hsm_password; bool linkx_control; - int cableDeviceIndex; + int cableDeviceIndex; int cableDeviceSize; bool cable_device_index_specified; bool cable_device_size_specified; @@ -196,7 +198,7 @@ class FlintParams { bool activate; bool download_downstream_specified; bool downstream_device_ids_specified; - std::vector downstream_device_ids; + std::vector downstream_device_ids; bool download_transfer; u_int8_t activate_delay_sec; string openssl_engine; diff --git a/flint/subcommands.cpp b/flint/subcommands.cpp index 46399f61..8e52009a 100644 --- a/flint/subcommands.cpp +++ b/flint/subcommands.cpp @@ -84,14 +84,14 @@ using namespace mfa2; * Log file writing implementation ************************************/ -//global log file header -FILE *flint_log_fh = NULL; +// global log file header +FILE* flint_log_fh = NULL; #define BURN_INTERRUPTED 0x1234 static int is_arm() { -#if defined (MST_CPU_arm64) +#if defined(MST_CPU_arm64) return 1; #else return 0; @@ -100,37 +100,22 @@ static int is_arm() void close_log() { - if (flint_log_fh != NULL) { + if (flint_log_fh != NULL) + { fclose(flint_log_fh); flint_log_fh = NULL; } return; } -static const char* life_cycle_strings[NUM_OF_LIFE_CYCLES] = { - "PRODUCTION", - "GA SECURED", - "GA NON SECURED", - "RMA" -}; +static const char* life_cycle_strings[NUM_OF_LIFE_CYCLES] = {"PRODUCTION", "GA SECURED", "GA NON SECURED", "RMA"}; #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) -const char* month_2monstr(int month) -{ - static const char *month_2monstr_arr[] = { - "Jan", - "Feb", - "Mar", - "Apr", - "May", - "Jun", - "Jul", - "Aug", - "Sep", - "Oct", - "Nov", - "Dec", +const char* month_2monstr(int month) +{ + static const char* month_2monstr_arr[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", }; int arr_size = (int)ARRAY_SIZE(month_2monstr_arr); return month < arr_size ? month_2monstr_arr[month] : "???"; @@ -139,14 +124,16 @@ const char* month_2monstr(int month) void print_time_to_log() { time_t rawtime; - struct tm *timeinfo; + struct tm* timeinfo; - if (flint_log_fh == NULL) { + if (flint_log_fh == NULL) + { return; } time(&rawtime); timeinfo = localtime(&rawtime); - if (!timeinfo) { + if (!timeinfo) + { printf("localtime returned NULL. Can't print time.\n"); return; } @@ -156,10 +143,11 @@ void print_time_to_log() return; } -int print_line_to_log(const char *format, ...) +int print_line_to_log(const char* format, ...) { va_list args; - if (flint_log_fh == NULL) { + if (flint_log_fh == NULL) + { return 0; } print_time_to_log(); @@ -171,16 +159,21 @@ int print_line_to_log(const char *format, ...) int write_cmd_to_log(string fullCmd, sub_cmd_t cmd, bool write) { - if (!write) { + if (!write) + { return 0; } char pre_str[50]; - if (flint_log_fh == NULL) { + if (flint_log_fh == NULL) + { return 0; } - if (cmd == SC_Brom) { + if (cmd == SC_Brom) + { snprintf(pre_str, 50, "ROM"); - } else { + } + else + { snprintf(pre_str, 50, "FW"); } print_time_to_log(); @@ -190,25 +183,36 @@ int write_cmd_to_log(string fullCmd, sub_cmd_t cmd, bool write) return 0; } -int write_result_to_log(int is_failed, const char *err_msg, bool write) +int write_result_to_log(int is_failed, const char* err_msg, bool write) { - if (!write) { + if (!write) + { return 0; } - char msg[MAX_ERR_STR_LEN + 1] = { 0 }; + char msg[MAX_ERR_STR_LEN + 1] = {0}; strncpy(msg, err_msg, MAX_ERR_STR_LEN); - if (is_failed == 0) { + if (is_failed == 0) + { print_line_to_log("Burn completed successfully\n"); - } else if (is_failed == BURN_INTERRUPTED) { + } + else if (is_failed == BURN_INTERRUPTED) + { print_line_to_log("Burn interrupted by user\n"); - } else { + } + else + { int msg_len = strlen(msg); // cleanup the msg - for (int i = 0; i < msg_len; i++) { - if (msg[i] == '\n') { - if (i == msg_len - 1) { + for (int i = 0; i < msg_len; i++) + { + if (msg[i] == '\n') + { + if (i == msg_len - 1) + { msg[i] = '\0'; - } else { + } + else + { msg[i] = ' '; } } @@ -222,26 +226,30 @@ bool is_file_exists(const string filename) { /* Check for existence */ #ifdef __WIN__ - if (_access(filename.c_str(), F_OK) != -1) { + if (_access(filename.c_str(), F_OK) != -1) + { return true; } #else - if (access(filename.c_str(), F_OK) != -1) { + if (access(filename.c_str(), F_OK) != -1) + { return true; } #endif return false; } -bool is_file_exists (const char *filename) +bool is_file_exists(const char* filename) { /* Check for existence */ #ifdef __WIN__ - if(_access(filename, F_OK) != -1) { + if (_access(filename, F_OK) != -1) + { return true; } #else - if(access(filename, F_OK) != -1) { + if (access(filename, F_OK) != -1) + { return true; } #endif @@ -252,16 +260,18 @@ bool is_file_exists (const char *filename) * Static functions ******************/ -static bool str2Num(const char *str, u_int32_t& num) +static bool str2Num(const char* str, u_int32_t& num) { - char *endp; + char* endp; u_int32_t tempNum; - if (!str) { + if (!str) + { return false; } tempNum = strtoul(str, &endp, 0); - if (*endp) { + if (*endp) + { return false; } num = tempNum; @@ -272,7 +282,6 @@ static bool str2Num(const char *str, u_int32_t& num) * Class: Subcommand ******************/ - #define MAX_ERR_STR_LEN 1024 #define PRE_ERR_MSG "-E-" @@ -282,29 +291,32 @@ bool SubCommand::isCmdSupportLog() // A. it is either Burn, Burn Block or Burn ROM. // B. log flag was given in the cmd line. - switch (_cmdType) { - case SC_Burn: - case SC_Bb: - case SC_Brom: - return _flintParams.log_specified; + switch (_cmdType) + { + case SC_Burn: + case SC_Bb: + case SC_Brom: + return _flintParams.log_specified; - default: - return false; + default: + return false; } return false; } -void SubCommand::reportErr(bool shouldPrint, const char *format, ...) +void SubCommand::reportErr(bool shouldPrint, const char* format, ...) { va_list args; va_start(args, format); - if (vsnprintf(_errBuff, FLINT_ERR_LEN, format, args) >= FLINT_ERR_LEN) { + if (vsnprintf(_errBuff, FLINT_ERR_LEN, format, args) >= FLINT_ERR_LEN) + { strcpy(&_errBuff[FLINT_ERR_LEN - 5], "...\n"); } - //print to the user and to the log if needed - if (shouldPrint) { + // print to the user and to the log if needed + if (shouldPrint) + { fprintf(stdout, PRE_ERR_MSG " %s", _errBuff); } write_result_to_log(FLINT_FAILED, _errBuff, isCmdSupportLog()); @@ -315,18 +327,21 @@ void SubCommand::reportErr(bool shouldPrint, const char *format, ...) bool SubCommand::getFileSize(const string& filePath, long& fileSize) { - FILE *fd = fopen(filePath.c_str(), "rb"); - if (fd == NULL) { + FILE* fd = fopen(filePath.c_str(), "rb"); + if (fd == NULL) + { reportErr(true, FLINT_OPEN_FILE_ERROR, filePath.c_str(), strerror(errno)); return false; } - if (fseek(fd, 0, SEEK_END) < 0) { + if (fseek(fd, 0, SEEK_END) < 0) + { fclose(fd); reportErr(true, FLINT_FILE_SIZE_ERROR, filePath.c_str()); return false; } long FileSize = ftell(fd); - if (FileSize < 0) { + if (FileSize < 0) + { fclose(fd); reportErr(true, FLINT_FILE_SIZE_ERROR, filePath.c_str()); return false; @@ -338,28 +353,32 @@ bool SubCommand::getFileSize(const string& filePath, long& fileSize) bool SubCommand::readFromFile(const string& filePath, std::vector& buff) { - FILE *fd = fopen(filePath.c_str(), "rb"); - if (fd == NULL) { + FILE* fd = fopen(filePath.c_str(), "rb"); + if (fd == NULL) + { reportErr(true, FLINT_OPEN_FILE_ERROR, filePath.c_str(), strerror(errno)); return false; } - if (fseek(fd, 0, SEEK_END) < 0) { + if (fseek(fd, 0, SEEK_END) < 0) + { fclose(fd); reportErr(true, FLINT_FILE_SIZE_ERROR, filePath.c_str()); return false; } long fileSize = ftell(fd); - if (fileSize < 0) { + if (fileSize < 0) + { fclose(fd); reportErr(true, FLINT_FILE_SIZE_ERROR, filePath.c_str()); return false; } rewind(fd); - int currentSize = buff.size();//default 0 + int currentSize = buff.size(); // default 0 buff.resize(currentSize + fileSize, 0xff); // Read long read_res = (long)fread(&buff[currentSize], 1, fileSize, fd); - if (read_res < 0) { + if (read_res < 0) + { fclose(fd); reportErr(true, FLINT_READ_FILE_ERROR, filePath.c_str()); return false; @@ -369,13 +388,15 @@ bool SubCommand::readFromFile(const string& filePath, std::vector& buf } bool SubCommand::writeToFile(string filePath, const std::vector& buff) { - FILE *fh = fopen(filePath.c_str(), "wb"); - if (fh == NULL) { + FILE* fh = fopen(filePath.c_str(), "wb"); + if (fh == NULL) + { reportErr(true, FLINT_OPEN_FILE_ERROR, filePath.c_str(), strerror(errno)); return false; } // Write - if (fwrite(&buff[0], 1, buff.size(), fh) != buff.size()) { + if (fwrite(&buff[0], 1, buff.size(), fh) != buff.size()) + { fclose(fh); reportErr(true, FLINT_WRITE_FILE_ERROR, filePath.c_str(), strerror(errno)); return false; @@ -384,16 +405,18 @@ bool SubCommand::writeToFile(string filePath, const std::vector& buff) return true; } -FlintStatus SubCommand::writeImageToFile(const char *file_name, u_int8_t *data, u_int32_t length) +FlintStatus SubCommand::writeImageToFile(const char* file_name, u_int8_t* data, u_int32_t length) { - FILE *fh = fopen(file_name, "wb"); - if (fh == NULL) { + FILE* fh = fopen(file_name, "wb"); + if (fh == NULL) + { reportErr(true, FLINT_OPEN_FILE_ERROR, file_name, strerror(errno)); return FLINT_FAILED; } // Write output - if (fwrite(data, 1, length, fh) != length) { + if (fwrite(data, 1, length, fh) != length) + { fclose(fh); reportErr(true, FLINT_WRITE_FILE_ERROR, file_name, strerror(errno)); return FLINT_FAILED; @@ -404,31 +427,37 @@ FlintStatus SubCommand::writeImageToFile(const char *file_name, u_int8_t *data, void SubCommand::openLog() { - if (isCmdSupportLog()) { + if (isCmdSupportLog()) + { flint_log_fh = fopen(_flintParams.log.c_str(), "a+"); - if (flint_log_fh == NULL) { - printf(FLINT_OPEN_LOG_FILE_WARNING, _flintParams.log.c_str() - , strerror(errno)); + if (flint_log_fh == NULL) + { + printf(FLINT_OPEN_LOG_FILE_WARNING, _flintParams.log.c_str(), strerror(errno)); } write_cmd_to_log(_flintParams.fullCmd, _flintParams.cmd, _flintParams.log_specified); } } -int SubCommand::verifyCbFunc(char *str) +int SubCommand::verifyCbFunc(char* str) { printf("%s", str); return 0; } - -int SubCommand::CbCommon(int completion, char *preStr, char *endStr) +int SubCommand::CbCommon(int completion, char* preStr, char* endStr) { - if (completion < 100) { + if (completion < 100) + { printf("\r%s%3d%%", preStr, completion); - } else if (completion == 100) { + } + else if (completion == 100) + { printf("\r%sOK \n", preStr); - } else { // printing endStr - if (endStr) { + } + else + { // printing endStr + if (endStr) + { printf("\r%s\n", endStr); } } @@ -440,34 +469,37 @@ int SubCommand::CbCommon(int completion, char *preStr, char *endStr) // output. thus in subcommands that use these callbacks you will see we manually call them at the end with the 101 arg int SubCommand::burnCbFs3Func(int completion) { - char *message = (char*)"Burning FW image without signatures - "; - char *endStr = (char*)"Restoring signature - OK"; + char* message = (char*)"Burning FW image without signatures - "; + char* endStr = (char*)"Restoring signature - OK"; return CbCommon(completion, message, endStr); } -int SubCommand::advProgressFunc(int completion, const char *stage, prog_t type, int *unknownProgress) +int SubCommand::advProgressFunc(int completion, const char* stage, prog_t type, int* unknownProgress) { - switch (type) { - case PROG_WITH_PRECENTAGE: - printf("\r%s - %3d%%", stage, completion); - break; + switch (type) + { + case PROG_WITH_PRECENTAGE: + printf("\r%s - %3d%%", stage, completion); + break; - case PROG_OK: - printf("\r%s - OK\n", stage); - break; + case PROG_OK: + printf("\r%s - OK\n", stage); + break; - case PROG_STRING_ONLY: - printf("%s\n", stage); - break; + case PROG_STRING_ONLY: + printf("%s\n", stage); + break; - case PROG_WITHOUT_PRECENTAGE: - if (unknownProgress) { - static const char *progStr[] = { "[. ]", "[.. ]", "[... ]", "[.... ]", "[.....]", "[ ....]", "[ ...]", "[ ..]", "[ .]", "[ ]" }; - int size = sizeof(progStr) / sizeof(progStr[0]); - printf("\r%s - %s", stage, progStr[(*unknownProgress) % size]); - (*unknownProgress)++; - } - break; + case PROG_WITHOUT_PRECENTAGE: + if (unknownProgress) + { + static const char* progStr[] = {"[. ]", "[.. ]", "[... ]", "[.... ]", "[.....]", + "[ ....]", "[ ...]", "[ ..]", "[ .]", "[ ]"}; + int size = sizeof(progStr) / sizeof(progStr[0]); + printf("\r%s - %s", stage, progStr[(*unknownProgress) % size]); + (*unknownProgress)++; + } + break; } fflush(stdout); return 0; @@ -475,9 +507,10 @@ int SubCommand::advProgressFunc(int completion, const char *stage, prog_t type, int SubCommand::burnCbFs2Func(int completion) { - char *message = (char*)"Burning FS2 FW image without signatures - "; - char *endStr = (char*)"Restoring signature - OK"; - if (completion == 102) { + char* message = (char*)"Burning FS2 FW image without signatures - "; + char* endStr = (char*)"Restoring signature - OK"; + if (completion == 102) + { endStr = (char*)"Image was successfully cached by driver."; } return CbCommon(completion, message, endStr); @@ -485,26 +518,25 @@ int SubCommand::burnCbFs2Func(int completion) int SubCommand::bromCbFunc(int completion) { - char *message = (char*)"Burning ROM image - "; - char *endStr = (char*)"Restoring signature - OK"; + char* message = (char*)"Burning ROM image - "; + char* endStr = (char*)"Restoring signature - OK"; return CbCommon(completion, message, endStr); } int SubCommand::dromCbFunc(int completion) { - char *message = (char*)"Removing ROM image - "; - char *endStr = (char*)"Restoring signature - OK"; + char* message = (char*)"Removing ROM image - "; + char* endStr = (char*)"Restoring signature - OK"; return CbCommon(completion, message, endStr); } int SubCommand::resetCfgCbFunc(int completion) { - char *message = (char*)"Resetting NV configuration - "; - char *endStr = (char*)"Restoring signature - OK"; + char* message = (char*)"Resetting NV configuration - "; + char* endStr = (char*)"Restoring signature - OK"; return CbCommon(completion, message, endStr); } - int SubCommand::burnBCbFunc(int completion) { return CbCommon(completion, (char*)""); @@ -512,27 +544,27 @@ int SubCommand::burnBCbFunc(int completion) int SubCommand::vsdCbFunc(int completion) { - char *message = (char*)"Setting the VSD - "; - char *endStr = (char*)"Restoring signature - OK"; + char* message = (char*)"Setting the VSD - "; + char* endStr = (char*)"Restoring signature - OK"; return CbCommon(completion, message, endStr); } int SubCommand::setKeyCbFunc(int completion) { - char *message = (char*)"Setting the HW Key - "; - char *endStr = (char*)"Restoring signature - OK"; + char* message = (char*)"Setting the HW Key - "; + char* endStr = (char*)"Restoring signature - OK"; return CbCommon(completion, message, endStr); } int SubCommand::wbCbFunc(int completion) { - char *message = (char*)"Writing Block: - "; + char* message = (char*)"Writing Block: - "; return CbCommon(completion, message, NULL); } #define ERR_BUFF_SIZE 1024 -void SubCommand::initDeviceFwParams(char *errBuff, FwOperations::fw_ops_params_t& fwParams) +void SubCommand::initDeviceFwParams(char* errBuff, FwOperations::fw_ops_params_t& fwParams) { memset(&fwParams, 0, sizeof(FwOperations::fw_ops_params_t)); fwParams.errBuff = errBuff; @@ -554,12 +586,14 @@ void SubCommand::initDeviceFwParams(char *errBuff, FwOperations::fw_ops_params_t FlintStatus SubCommand::openOps(bool ignoreSecurityAttributes, bool ignoreDToc) { DPRINTF(("SubCommand::openOps\n")); - char errBuff[ERR_BUFF_SIZE] = { 0 }; - if (_flintParams.device_specified) { + char errBuff[ERR_BUFF_SIZE] = {0}; + if (_flintParams.device_specified) + { // fillup the fw_ops_params_t struct FwOperations::fw_ops_params_t fwParams; initDeviceFwParams(errBuff, fwParams); - if (_flintParams.image_specified) { + if (_flintParams.image_specified) + { FwOperations::fw_ops_params_t imgFwParams; memset(&imgFwParams, 0, sizeof(imgFwParams)); imgFwParams.psid = NULL; @@ -569,28 +603,37 @@ FlintStatus SubCommand::openOps(bool ignoreSecurityAttributes, bool ignoreDToc) imgFwParams.shortErrors = true; imgFwParams.fileHndl = (char*)_flintParams.image.c_str(); imgFwParams.ignoreCrcCheck = _flintParams.ignore_crc_check; - if (!FwOperations::imageDevOperationsCreate(fwParams, imgFwParams, &_fwOps, &_imgOps, ignoreSecurityAttributes, ignoreDToc)) { + if (!FwOperations::imageDevOperationsCreate(fwParams, imgFwParams, &_fwOps, &_imgOps, + ignoreSecurityAttributes, ignoreDToc)) + { /* * Error are being handled after */ } - } else { + } + else + { _fwOps = FwOperations::FwOperationsCreate(fwParams); } delete[] fwParams.mstHndl; } - if (_flintParams.image_specified && !_flintParams.device_specified) { - _imgOps = FwOperations::FwOperationsCreate((void*)_flintParams.image.c_str(), NULL, NULL, \ - FHT_FW_FILE, errBuff, 1024); + if (_flintParams.image_specified && !_flintParams.device_specified) + { + _imgOps = + FwOperations::FwOperationsCreate((void*)_flintParams.image.c_str(), NULL, NULL, FHT_FW_FILE, errBuff, 1024); } - if (_flintParams.image_specified && _imgOps == NULL) { + if (_flintParams.image_specified && _imgOps == NULL) + { reportErr(true, FLINT_OPEN_FWOPS_IMAGE_ERROR, _flintParams.image.c_str(), strlen(errBuff) != 0 ? errBuff : ""); return FLINT_FAILED; } - if (_flintParams.device_specified && _fwOps == NULL) { - if (_flintParams.silent == false) { - reportErr(true, FLINT_OPEN_FWOPS_DEVICE_ERROR, _flintParams.device.c_str(), strlen(errBuff) != 0 ? errBuff : ""); + if (_flintParams.device_specified && _fwOps == NULL) + { + if (_flintParams.silent == false) + { + reportErr(true, FLINT_OPEN_FWOPS_DEVICE_ERROR, _flintParams.device.c_str(), + strlen(errBuff) != 0 ? errBuff : ""); } return FLINT_FAILED; } @@ -599,20 +642,26 @@ FlintStatus SubCommand::openOps(bool ignoreSecurityAttributes, bool ignoreDToc) FlintStatus SubCommand::openIo() { - //TODO: consider adding a parameter for when image/device will be opened as "readOnly" in the open routine. - if (_flintParams.device_specified && _flintParams.image_specified) { - //should not arrive here as we verify params at each subcommand. + // TODO: consider adding a parameter for when image/device will be opened as "readOnly" in the open routine. + if (_flintParams.device_specified && _flintParams.image_specified) + { + // should not arrive here as we verify params at each subcommand. reportErr(true, FLINT_DEVICE_AND_IMAGE_ERROR); return FLINT_FAILED; } - if (_flintParams.device_specified) { + if (_flintParams.device_specified) + { _io = new Flash; - if (!((Flash*)_io)->open(_flintParams.device.c_str(), _flintParams.clear_semaphore, false, _flintParams.banks, \ - _flintParams.flash_params_specified ? &_flintParams.flash_params : NULL, _flintParams.override_cache_replacement, true, _flintParams.use_fw)) { + if (!((Flash*)_io) + ->open(_flintParams.device.c_str(), _flintParams.clear_semaphore, false, _flintParams.banks, + _flintParams.flash_params_specified ? &_flintParams.flash_params : NULL, + _flintParams.override_cache_replacement, true, _flintParams.use_fw)) + { // if we have Hw_Access command we dont fail straght away u_int8_t lockedCrSpace = ((Flash*)_io)->get_cr_space_locked(); - if (lockedCrSpace && (_flintParams.cmd == SC_Hw_Access || - (_flintParams.cmd == SC_Set_Key && ((Flash*)_io)->is_fifth_gen()))) { + if (lockedCrSpace && + (_flintParams.cmd == SC_Hw_Access || (_flintParams.cmd == SC_Set_Key && ((Flash*)_io)->is_fifth_gen()))) + { return FLINT_SUCCESS; } reportErr(true, FLINT_IO_OPEN_ERROR, "Device", (_io)->err()); @@ -621,11 +670,14 @@ FlintStatus SubCommand::openIo() return FLINT_FAILED; } // we have successfully opened a Flash Obj - //set no flash verify if needed (default =false) + // set no flash verify if needed (default =false) ((Flash*)_io)->set_no_flash_verify(_flintParams.no_flash_verify); - } else if (_flintParams.image_specified) { + } + else if (_flintParams.image_specified) + { _io = new FImage; - if (!((FImage*)_io)->open(_flintParams.image.c_str())) { + if (!((FImage*)_io)->open(_flintParams.image.c_str())) + { reportErr(true, FLINT_IO_OPEN_ERROR, "Image", (_io)->err()); delete _io; _io = NULL; @@ -637,93 +689,115 @@ FlintStatus SubCommand::openIo() bool SubCommand::basicVerifyParams() { - if (!_flintParams.log_specified) { - char *logFile; + if (!_flintParams.log_specified) + { + char* logFile; logFile = getenv(FLINT_LOG_ENV); - if (logFile) { + if (logFile) + { _flintParams.log = logFile; _flintParams.log_specified = true; } } - //open log if needed + // open log if needed openLog(); - if (_maxCmdParamNum == _minCmdParamNum && _maxCmdParamNum != -1 && (int)_flintParams.cmd_params.size() != _maxCmdParamNum) { + if (_maxCmdParamNum == _minCmdParamNum && _maxCmdParamNum != -1 && + (int)_flintParams.cmd_params.size() != _maxCmdParamNum) + { reportErr(true, FLINT_CMD_ARGS_ERROR, _name.c_str(), _maxCmdParamNum, _flintParams.cmd_params.size()); return false; - } else if (_maxCmdParamNum != -1 && (int)_flintParams.cmd_params.size() > _maxCmdParamNum) { + } + else if (_maxCmdParamNum != -1 && (int)_flintParams.cmd_params.size() > _maxCmdParamNum) + { // _maxCmdParamNum == -1 means ignore this check - if (_maxCmdParamNum) { + if (_maxCmdParamNum) + { reportErr(true, FLINT_CMD_ARGS_ERROR2, _name.c_str(), _maxCmdParamNum, (int)_flintParams.cmd_params.size()); - } else { + } + else + { reportErr(true, FLINT_CMD_ARGS_ERROR5, _name.c_str()); } return false; - } else if (_minCmdParamNum != -1 && (int)_flintParams.cmd_params.size() < _minCmdParamNum) { + } + else if (_minCmdParamNum != -1 && (int)_flintParams.cmd_params.size() < _minCmdParamNum) + { // _minCmdParamNum == -1 means ignore this check reportErr(true, FLINT_CMD_ARGS_ERROR3, _name.c_str(), _minCmdParamNum, _flintParams.cmd_params.size()); return false; } - switch (_v) { - case Wtv_Img: - if (_flintParams.device_specified == true) { - _flintParams.image_specified ? reportErr(true, FLINT_COMMAND_IMAGE_ERROR2, _name.c_str()) : - reportErr(true, FLINT_COMMAND_IMAGE_ERROR, _name.c_str()); - return false; - } - if (_flintParams.image_specified == false) { - reportErr(true, FLINT_NO_IMAGE_ERROR); - return false; - } - break; - - case Wtv_Dev: - if (_flintParams.image_specified == true) { - _flintParams.device_specified ? reportErr(true, FLINT_COMMAND_DEVICE_ERROR2, _name.c_str()) : - reportErr(true, FLINT_COMMAND_DEVICE_ERROR, _name.c_str()); - return false; - } - if (_flintParams.device_specified == false) { - reportErr(true, FLINT_NO_DEVICE_ERROR); - return false; - } - break; + switch (_v) + { + case Wtv_Img: + if (_flintParams.device_specified == true) + { + _flintParams.image_specified ? reportErr(true, FLINT_COMMAND_IMAGE_ERROR2, _name.c_str()) : + reportErr(true, FLINT_COMMAND_IMAGE_ERROR, _name.c_str()); + return false; + } + if (_flintParams.image_specified == false) + { + reportErr(true, FLINT_NO_IMAGE_ERROR); + return false; + } + break; - case Wtv_Dev_And_Img: - if (_flintParams.linkx_control == false) { - if ((_flintParams.image_specified == false) || (_flintParams.device_specified == false)) { - reportErr(true, FLINT_COMMAND_DEVICE_IMAGE_ERROR, _name.c_str()); + case Wtv_Dev: + if (_flintParams.image_specified == true) + { + _flintParams.device_specified ? reportErr(true, FLINT_COMMAND_DEVICE_ERROR2, _name.c_str()) : + reportErr(true, FLINT_COMMAND_DEVICE_ERROR, _name.c_str()); return false; } - } - break; + if (_flintParams.device_specified == false) + { + reportErr(true, FLINT_NO_DEVICE_ERROR); + return false; + } + break; - case Wtv_Dev_Or_Img: - if (_flintParams.image_specified == true && _flintParams.device_specified == true) { - reportErr(true, FLINT_DEVICE_AND_IMAGE_ERROR); - return false; - } - if (_flintParams.device_specified == false && _flintParams.image_specified == false) { - reportErr(true, FLINT_DEVICE_AND_IMAGE_ERROR); - return false; - } - break; + case Wtv_Dev_And_Img: + if (_flintParams.linkx_control == false) + { + if ((_flintParams.image_specified == false) || (_flintParams.device_specified == false)) + { + reportErr(true, FLINT_COMMAND_DEVICE_IMAGE_ERROR, _name.c_str()); + return false; + } + } + break; - case Wtv_Uninitilized: + case Wtv_Dev_Or_Img: + if (_flintParams.image_specified == true && _flintParams.device_specified == true) + { + reportErr(true, FLINT_DEVICE_AND_IMAGE_ERROR); + return false; + } + if (_flintParams.device_specified == false && _flintParams.image_specified == false) + { + reportErr(true, FLINT_DEVICE_AND_IMAGE_ERROR); + return false; + } + break; - return true; - default: - reportErr(true, FAILED_TO_VERIFY_PARAMS); - return false; + case Wtv_Uninitilized: + + return true; + default: + reportErr(true, FAILED_TO_VERIFY_PARAMS); + return false; } - if (_flintParams.device_specified && _flintParams.striped_image) { + if (_flintParams.device_specified && _flintParams.striped_image) + { reportErr(true, FLINT_INVALID_FLAG_WITH_FLAG_ERROR, "-device", "-striped_image"); return false; } - if (_flintParams.override_cache_replacement) { + if (_flintParams.override_cache_replacement) + { printf(FLINT_OCR_WARRNING); } return true; @@ -732,32 +806,39 @@ bool SubCommand::basicVerifyParams() FlintStatus SubCommand::preFwOps(bool ignoreSecurityAttributes, bool ignoreDToc) { DPRINTF(("SubCommand::preFwOps\n")); - if (!basicVerifyParams()) { + if (!basicVerifyParams()) + { return FLINT_FAILED; } - if (_flintParams.linkx_control != true) { - if (!verifyParams()) { + if (_flintParams.linkx_control != true) + { + if (!verifyParams()) + { return FLINT_FAILED; } } - if (_flintParams.mfa2_specified || _flintParams.congestion_control || _flintParams.linkx_control == true) { + if (_flintParams.mfa2_specified || _flintParams.congestion_control || _flintParams.linkx_control == true) + { bool saved_value = _flintParams.image_specified; _flintParams.image_specified = false; FlintStatus result = openOps(true); _flintParams.image_specified = saved_value; return result; } - else { + else + { return openOps(ignoreSecurityAttributes, ignoreDToc); } } FlintStatus SubCommand::preFwAccess() { - if (!basicVerifyParams()) { + if (!basicVerifyParams()) + { return FLINT_FAILED; } - if (!verifyParams()) { + if (!verifyParams()) + { return FLINT_FAILED; } return openIo(); @@ -765,29 +846,31 @@ FlintStatus SubCommand::preFwAccess() SubCommand::~SubCommand() { - if (_fwOps != NULL) { + if (_fwOps != NULL) + { _fwOps->FwCleanUp(); delete _fwOps; } - if (_imgOps != NULL) { + if (_imgOps != NULL) + { _imgOps->FwCleanUp(); delete _imgOps; } - if (_io != NULL) { + if (_io != NULL) + { _io->close(); delete _io; } - - } // matanel - TODO: duplicated, use same function from fw_ops.cpp -bool SubCommand::getRomsInfo(FBase *io, roms_info_t& romsInfo) +bool SubCommand::getRomsInfo(FBase* io, roms_info_t& romsInfo) { std::vector romSector; romSector.clear(); romSector.resize(io->get_effective_size()); - if (!io->read(0, &romSector[0], io->get_effective_size())) { + if (!io->read(0, &romSector[0], io->get_effective_size())) + { reportErr(true, FLINT_READ_ERROR, _flintParams.image.c_str(), io->err()); return false; } @@ -799,13 +882,17 @@ bool SubCommand::getRomsInfo(FBase *io, roms_info_t& romsInfo) bool SubCommand::getGUIDFromStr(string str, guid_t& guid, string prefixErr) { - char *endp; + char* endp; u_int64_t g; g = strtoull(str.c_str(), &endp, 16); - if (*endp || (g == 0xffffffffffffffffULL && errno == ERANGE)) { - if (prefixErr.size() == 0) { + if (*endp || (g == 0xffffffffffffffffULL && errno == ERANGE)) + { + if (prefixErr.size() == 0) + { reportErr(true, INVALID_GUID_SYNTAX, str.c_str(), errno ? strerror(errno) : ""); - } else { + } + else + { reportErr(true, "%s\n", prefixErr.c_str()); } return false; @@ -815,7 +902,6 @@ bool SubCommand::getGUIDFromStr(string str, guid_t& guid, string prefixErr) return true; } - #if !defined(__WIN__) && !defined(__DJGPP__) && !defined(UEFI_BUILD) && defined(HAVE_TERMIOS_H) static int mygetch(void) { @@ -831,24 +917,27 @@ static int mygetch(void) return ch; } -bool SubCommand::getPasswordFromUser(const char *preStr, char buffer[MAX_PASSWORD_LEN + 1]) +bool SubCommand::getPasswordFromUser(const char* preStr, char buffer[MAX_PASSWORD_LEN + 1]) { char c; int pos = 0; printf("%s: ", preStr); - do { + do + { c = mygetch(); - if (((pos < MAX_PASSWORD_LEN)) && isprint(c)) { + if (((pos < MAX_PASSWORD_LEN)) && isprint(c)) + { buffer[pos++] = c; printf("%c", '*'); - } else if ((c == 8 || c == 127) && pos) { + } + else if ((c == 8 || c == 127) && pos) + { buffer[pos--] = '\0'; printf("%s", "\b \b"); } - } while (c != '\n'); printf("\n"); buffer[pos] = '\0'; @@ -856,7 +945,7 @@ bool SubCommand::getPasswordFromUser(const char *preStr, char buffer[MAX_PASSWOR } #else -bool SubCommand::getPasswordFromUser(const char *preStr, char buffer[MAX_PASSWORD_LEN + 1]) +bool SubCommand::getPasswordFromUser(const char* preStr, char buffer[MAX_PASSWORD_LEN + 1]) { static HANDLE stdinHndl = NULL; DWORD numOfBytesRead = 0; @@ -865,44 +954,54 @@ bool SubCommand::getPasswordFromUser(const char *preStr, char buffer[MAX_PASSWOR char ch; int i; - if (!stdinHndl) { + if (!stdinHndl) + { // adrianc: this might be problematic if called and stdout was alreading overridden use CIN$ instead stdinHndl = GetStdHandle(STD_INPUT_HANDLE); } printf("%s:", preStr); // disable console echoing - if (!GetConsoleMode(stdinHndl, &oldConsoleMode)) { + if (!GetConsoleMode(stdinHndl, &oldConsoleMode)) + { reportErr(true, FAILED_GET_CONSOLE_MODE); return false; } consoleMode = oldConsoleMode & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT); - if (!SetConsoleMode(stdinHndl, consoleMode)) { + if (!SetConsoleMode(stdinHndl, consoleMode)) + { reportErr(true, FAILED_GET_CONSOLE_MODE); return 1; } // read chars from stdin and print * to stdout using putchar - for (i = 0;;) { + for (i = 0;;) + { status = ReadFile(stdinHndl, &ch, sizeof(char), &numOfBytesRead, NULL); - if (!status || numOfBytesRead != sizeof(char) || ch == '\n' || ch == '\r' || i == (MAX_PASSWORD_LEN - 1)) { + if (!status || numOfBytesRead != sizeof(char) || ch == '\n' || ch == '\r' || i == (MAX_PASSWORD_LEN - 1)) + { // user finished giving the pw - if (!SetConsoleMode(stdinHndl, oldConsoleMode)) { + if (!SetConsoleMode(stdinHndl, oldConsoleMode)) + { reportErr(true, FAILED_GET_CONSOLE_MODE); return false; } - if (!status || numOfBytesRead != sizeof(char)) { + if (!status || numOfBytesRead != sizeof(char)) + { reportErr(true, FAILED_GET_CONSOLE_MODE); return false; } break; } - if (isalpha(ch) || isdigit(ch)) { + if (isalpha(ch) || isdigit(ch)) + { putchar('*'); buffer[i++] = ch; - } else if (ch == '\b' && i) { - //delete last astrix and set correct position + } + else if (ch == '\b' && i) + { + // delete last astrix and set correct position printf("\b \b"); i--; } @@ -919,19 +1018,25 @@ bool SubCommand::getPasswordFromUser(const char *preStr, char buffer[MAX_PASSWOR // Returns true if user chose Y, false if user chose N. // -bool SubCommand::askUser(const char *question, bool printAbrtMsg) +bool SubCommand::askUser(const char* question, bool printAbrtMsg) { - if (question == NULL) { + if (question == NULL) + { printf("\n Do you want to continue ? (y/n) [n] : "); - } else { + } + else + { printf("\n %s ? (y/n) [n] : ", question); - } - if (_flintParams.yes) { + if (_flintParams.yes) + { printf("y\n"); - } else { - if (_flintParams.no) { + } + else + { + if (_flintParams.no) + { printf("n\n"); reportErr(false, "-no flag is set\n"); return false; @@ -940,15 +1045,15 @@ bool SubCommand::askUser(const char *question, bool printAbrtMsg) fflush(stdout); std::string answer; std::getline(std::cin, answer); - //fgets(ansbuff, 30, stdin); - //if (!fscanf(stdin, "%[^\n]30s", ansbuff)) { + // fgets(ansbuff, 30, stdin); + // if (!fscanf(stdin, "%[^\n]30s", ansbuff)) { // return false; //} - if (strcasecmp(answer.c_str(), "y") && - strcasecmp(answer.c_str(), "yes")) { - - if (printAbrtMsg) { + if (strcasecmp(answer.c_str(), "y") && strcasecmp(answer.c_str(), "yes")) + { + if (printAbrtMsg) + { reportErr(true, USER_ABORT); } return false; @@ -961,49 +1066,50 @@ string SubCommand::getRomProtocolStr(u_int8_t proto) { string result; - switch (proto) { - case ER_IB: - result = "IB"; - break; + switch (proto) + { + case ER_IB: + result = "IB"; + break; - case ER_ETH: - result = "ETH"; - break; + case ER_ETH: + result = "ETH"; + break; - case ER_VPI: - result = "VPI"; - break; + case ER_VPI: + result = "VPI"; + break; - default: - result = "N/A"; + default: + result = "N/A"; } return result; } - string SubCommand::getRomSuppCpuStr(u_int8_t suppCpu) { string result; - switch (suppCpu) { - case ERC_AMD64: - result = "AMD64"; - break; + switch (suppCpu) + { + case ERC_AMD64: + result = "AMD64"; + break; - case ERC_AARCH64: - result = "AARCH64"; - break; + case ERC_AARCH64: + result = "AARCH64"; + break; - case ERC_AMD64_AARCH64: - result = "AMD64,AARCH64"; - break; + case ERC_AMD64_AARCH64: + result = "AMD64,AARCH64"; + break; - case ERC_IA32: - result = "IA32"; - break; + case ERC_IA32: + result = "IA32"; + break; - default: - result = "N/A"; + default: + result = "N/A"; } return result; } @@ -1011,10 +1117,13 @@ string SubCommand::getRomSuppCpuStr(u_int8_t suppCpu) string SubCommand::getExpRomVerStr(const rom_info_t& info) { stringstream verStream; - if (info.exp_rom_num_ver_fields) { - for (int i = 0; i < info.exp_rom_num_ver_fields; i++) { + if (info.exp_rom_num_ver_fields) + { + for (int i = 0; i < info.exp_rom_num_ver_fields; i++) + { verStream << info.exp_rom_ver[i]; - if (i + 1 < info.exp_rom_num_ver_fields) { + if (i + 1 < info.exp_rom_num_ver_fields) + { verStream << "."; } } @@ -1024,28 +1133,38 @@ string SubCommand::getExpRomVerStr(const rom_info_t& info) void SubCommand::displayOneExpRomInfo(const rom_info_t& info) { - const char *typeStr = FwOperations::expRomType2Str(info.exp_rom_product_id); - if (info.exp_rom_product_id == 0xf) { + const char* typeStr = FwOperations::expRomType2Str(info.exp_rom_product_id); + if (info.exp_rom_product_id == 0xf) + { // version id in this case is the freeStr that was moved to exp_rom_ver[0] in mlxfwops printf("version_id=%s type=%s ", getExpRomVerStr(info).c_str(), typeStr); - } else { - if (typeStr) { + } + else + { + if (typeStr) + { printf("type=%s ", typeStr); - } else { + } + else + { printf("0x%x - Unknown ROM product ID\n", info.exp_rom_product_id); return; } printf("version=%s", getExpRomVerStr(info).c_str()); - if (info.exp_rom_product_id >= 0x10) { - if (info.exp_rom_port) { + if (info.exp_rom_product_id >= 0x10) + { + if (info.exp_rom_port) + { // Do not display if 0 - port independent printf(" port=%d", info.exp_rom_port); } - if (info.exp_rom_product_id != 0x12 && info.exp_rom_proto != 0xff) { + if (info.exp_rom_product_id != 0x12 && info.exp_rom_proto != 0xff) + { // on CLP(0x12) there is no meaning to protocol printf(" proto=%s", getRomProtocolStr(info.exp_rom_proto).c_str()); } - if (info.exp_rom_supp_cpu_arch) { + if (info.exp_rom_supp_cpu_arch) + { printf(" cpu=%s", getRomSuppCpuStr(info.exp_rom_supp_cpu_arch).c_str()); } } @@ -1053,38 +1172,48 @@ void SubCommand::displayOneExpRomInfo(const rom_info_t& info) return; } - -void SubCommand::displayExpRomInfo(const roms_info_t& romsInfo, const char *preStr) +void SubCommand::displayExpRomInfo(const roms_info_t& romsInfo, const char* preStr) { int i; int strLen = strlen(preStr); - if (romsInfo.num_of_exp_rom > 0) { - for (i = 0; i < romsInfo.num_of_exp_rom; i++) { + if (romsInfo.num_of_exp_rom > 0) + { + for (i = 0; i < romsInfo.num_of_exp_rom; i++) + { // Print the pre string or spaces - if (i == 0) { + if (i == 0) + { printf("%s", preStr); - } else { + } + else + { int j; - for (j = 0; j < strLen; j++) { + for (j = 0; j < strLen; j++) + { printf("%s", " "); } } // Display a ROM info displayOneExpRomInfo(romsInfo.rom_info[i]); - if (i != romsInfo.num_of_exp_rom - 1) { + if (i != romsInfo.num_of_exp_rom - 1) + { // Don't print new line after the info of the last ROM printf("\n"); } } - if (romsInfo.exp_rom_warning) { + if (romsInfo.exp_rom_warning) + { printf(" (-W- %s)", romsInfo.exp_rom_warning_msg); } printf("\n"); - } else { + } + else + { printf("%s", preStr); printf("N/A"); - if (romsInfo.exp_rom_err_msg_valid) { + if (romsInfo.exp_rom_err_msg_valid) + { printf(" (-E- %s)", romsInfo.exp_rom_err_msg); } printf("\n"); @@ -1092,52 +1221,68 @@ void SubCommand::displayExpRomInfo(const roms_info_t& romsInfo, const char *preS return; } -bool SubCommand::printGuidLine(guid_t *new_guids, guid_t *old_guids, int guid_index) +bool SubCommand::printGuidLine(guid_t* new_guids, guid_t* old_guids, int guid_index) { printf(GUID_FORMAT GUID_SPACES, new_guids[guid_index].h, new_guids[guid_index].l); - if (old_guids != NULL) { + if (old_guids != NULL) + { printf(GUID_FORMAT, old_guids[guid_index].h, old_guids[guid_index].l); - } else { + } + else + { printf(" N/A"); } printf("\n"); return true; } -bool SubCommand::printMacLine(guid_t *new_guids, guid_t *old_guids, int mac_index) +bool SubCommand::printMacLine(guid_t* new_guids, guid_t* old_guids, int mac_index) { printf(" " MAC_FORMAT MAC_SPACES, new_guids[mac_index].h, new_guids[mac_index].l); - if (old_guids != NULL) { + if (old_guids != NULL) + { printf(MAC_FORMAT, old_guids[mac_index].h, old_guids[mac_index].l); - } else { + } + else + { printf(" N/A"); } printf("\n"); return true; } -bool SubCommand::printGUIDsFunc(guid_t guids[GUIDS], guid_t macs[MACS], guid_t old_guids[GUIDS], \ - guid_t old_macs[MACS], bool print_guids, bool print_macs, int portNum, bool old_guid_fmt) +bool SubCommand::printGUIDsFunc(guid_t guids[GUIDS], + guid_t macs[MACS], + guid_t old_guids[GUIDS], + guid_t old_macs[MACS], + bool print_guids, + bool print_macs, + int portNum, + bool old_guid_fmt) { - - if (print_guids) { + if (print_guids) + { printf(" Node GUID: "); printGuidLine(guids, old_guids, 0); - if (portNum > 0) { + if (portNum > 0) + { printf(" Port1 GUID: "); printGuidLine(guids, old_guids, 1); } - if (portNum > 1) { + if (portNum > 1) + { printf(" Port2 GUID: "); printGuidLine(guids, old_guids, 2); } - if (!old_guid_fmt) { + if (!old_guid_fmt) + { printf(" Sys.Image GUID: "); printGuidLine(guids, old_guids, 3); } } - if (print_macs) { + if (print_macs) + { printf(" Port1 MAC: "); printMacLine(macs, old_macs, 0); printf(" Port2 MAC: "); @@ -1146,34 +1291,36 @@ bool SubCommand::printGUIDsFunc(guid_t guids[GUIDS], guid_t macs[MACS], guid_t o return true; } -bool SubCommand::reportGuidChanges(guid_t *new_guids, guid_t *new_macs, \ - guid_t *old_guids, guid_t *old_macs, bool printGuids, \ - bool printMacs, int guidNum) +bool SubCommand::reportGuidChanges(guid_t* new_guids, + guid_t* new_macs, + guid_t* old_guids, + guid_t* old_macs, + bool printGuids, + bool printMacs, + int guidNum) { - //should be used ONLY on FS2 in current implementation - printf(" You are about to change the Guids/Macs/Uids on the %s:\n\n", _flintParams.device_specified ? "device" : "image"); + // should be used ONLY on FS2 in current implementation + printf(" You are about to change the Guids/Macs/Uids on the %s:\n\n", + _flintParams.device_specified ? "device" : "image"); printf(" New Values " GUID_SPACES "Current Values\n"); - printGUIDsFunc(new_guids, new_macs, - old_guids, old_macs, - printGuids, - printMacs, - guidNum, - guidNum < GUIDS); - - if (!askUser()) { + printGUIDsFunc(new_guids, new_macs, old_guids, old_macs, printGuids, printMacs, guidNum, guidNum < GUIDS); + + if (!askUser()) + { return false; } return true; } -//used for dc and dh subcommands +// used for dc and dh subcommands -bool SubCommand::unzipDataFile(std::vector data, std::vector &newData, const char *sectionName) +bool SubCommand::unzipDataFile(std::vector data, std::vector& newData, const char* sectionName) { #ifndef NO_ZLIB int rc; - if (data.empty()) { + if (data.empty()) + { reportErr(true, SECTION_NOT_FOUNT, sectionName); return false; } @@ -1185,17 +1332,19 @@ bool SubCommand::unzipDataFile(std::vector data, std::vector destLen *= 40; // Assuming this is the best compression ratio vector dest(destLen); - for (int i = 0; i < 32; i++) { - rc = uncompress((Bytef*)&(dest[0]), &destLen, - (const Bytef*)&(data[0]), data.size()); - if (rc != Z_BUF_ERROR) { + for (int i = 0; i < 32; i++) + { + rc = uncompress((Bytef*)&(dest[0]), &destLen, (const Bytef*)&(data[0]), data.size()); + if (rc != Z_BUF_ERROR) + { break; } destLen *= 2; dest.resize(destLen); } - if (rc != Z_OK) { + if (rc != Z_OK) + { reportErr(true, UNCOMPRESSS_ERROR, rc); return false; } @@ -1215,44 +1364,60 @@ bool SubCommand::unzipDataFile(std::vector data, std::vector #endif } -bool SubCommand::dumpFile(const char *confFile, std::vector& data, const char *sectionName) +bool SubCommand::dumpFile(const char* confFile, std::vector& data, const char* sectionName) { - FILE *out; + FILE* out; vector dest; - if (confFile == NULL) { + if (confFile == NULL) + { out = stdout; - } else { + } + else + { out = fopen(confFile, "w"); - if (out == NULL) { + if (out == NULL) + { reportErr(true, OPEN_WRITE_FILE_ERROR, confFile, strerror(errno)); return false; } } - if (unzipDataFile(data, dest, sectionName) == false) { - if (confFile != NULL) { + if (unzipDataFile(data, dest, sectionName) == false) + { + if (confFile != NULL) + { fclose(out); } return false; } fprintf(out, "%s", (char*)&(dest[0])); - if (confFile != NULL) { + if (confFile != NULL) + { fclose(out); } return true; } -bool SubCommand::checkGuidsFlags(u_int16_t devType, u_int8_t fwType, - bool guidsSpecified, bool macsSpecified, bool uidSpecified, bool ibDev, bool ethDev) +bool SubCommand::checkGuidsFlags(u_int16_t devType, + u_int8_t fwType, + bool guidsSpecified, + bool macsSpecified, + bool uidSpecified, + bool ibDev, + bool ethDev) { (void)ibDev; - if (guidsSpecified || macsSpecified || uidSpecified) { - if (uidSpecified && fwType != FIT_FS3 && fwType != FIT_FS4 && fwType != FIT_FSCTRL) { + if (guidsSpecified || macsSpecified || uidSpecified) + { + if (uidSpecified && fwType != FIT_FS3 && fwType != FIT_FS4 && fwType != FIT_FSCTRL) + { reportErr(true, "-uid flag is applicable only for FS3/FS4 FW Only.\n"); return false; - } else if (fwType != FIT_FS2 && !ethDev && macsSpecified) { + } + else if (fwType != FIT_FS2 && !ethDev && macsSpecified) + { reportErr(true, "-mac(s) flag is not applicable for IB MT%d device.\n", devType); return false; } @@ -1262,16 +1427,21 @@ bool SubCommand::checkGuidsFlags(u_int16_t devType, u_int8_t fwType, void SubCommand::printMissingGuidErr(bool ibDev, bool ethDev) { - const char *missingInfo; - const char *missingFlags; + const char* missingInfo; + const char* missingFlags; - if (ibDev && ethDev) { + if (ibDev && ethDev) + { missingInfo = "GUIDs / MACs"; missingFlags = "-guid(s) / -mac(s)"; - } else if (ibDev) { + } + else if (ibDev) + { missingInfo = "GUIDs"; missingFlags = "-guid(s)"; - } else { + } + else + { missingInfo = "MACs"; missingFlags = "-mac(s)"; } @@ -1285,40 +1455,50 @@ bool SubCommand::extractValuesFromString(string valStr, u_int8_t values[2], stri // check if we need to extract 2 values or 1 u_int32_t tempNum0 = 0, tempNum1 = 0; string tempNumStr; - if (valStr.find(',') != string::npos) { + if (valStr.find(',') != string::npos) + { std::stringstream ss((valStr.c_str())); // get first value - if (!std::getline(ss, tempNumStr, ',')) { + if (!std::getline(ss, tempNumStr, ',')) + { reportErr(true, FLINT_INVALID_ARG_ERROR, origArg.c_str()); return false; } - if (!str2Num(tempNumStr.c_str(), tempNum0)) { + if (!str2Num(tempNumStr.c_str(), tempNum0)) + { reportErr(true, FLINT_INVALID_ARG_ERROR, origArg.c_str()); return false; } // get second value - if (!std::getline(ss, tempNumStr, ',')) { + if (!std::getline(ss, tempNumStr, ',')) + { reportErr(true, FLINT_INVALID_ARG_ERROR, origArg.c_str()); return false; } - if (!str2Num(tempNumStr.c_str(), tempNum1)) { + if (!str2Num(tempNumStr.c_str(), tempNum1)) + { reportErr(true, FLINT_INVALID_ARG_ERROR, origArg.c_str()); return false; } // make sure no other tokens are present - if (!(!std::getline(ss, tempNumStr, ','))) { + if (!(!std::getline(ss, tempNumStr, ','))) + { reportErr(true, FLINT_INVALID_ARG_ERROR, origArg.c_str()); return false; } - } else { - if (!str2Num(valStr.c_str(), tempNum0)) { + } + else + { + if (!str2Num(valStr.c_str(), tempNum0)) + { reportErr(true, FLINT_INVALID_ARG_ERROR, origArg.c_str()); return false; } tempNum1 = tempNum0; } // perform checks - if (tempNum0 >= 255 || tempNum1 >= 255) { + if (tempNum0 >= 255 || tempNum1 >= 255) + { reportErr(true, "Invalid argument values, values should be taken from the range [0..254]\n"); return false; } @@ -1329,34 +1509,45 @@ bool SubCommand::extractValuesFromString(string valStr, u_int8_t values[2], stri bool SubCommand::extractUIDArgs(std::vector& cmdArgs, u_int8_t numOfGuids[2], u_int8_t stepSize[2]) { - //extract num_of_guids and step_size from numGuidsStr, stepStr + // extract num_of_guids and step_size from numGuidsStr, stepStr string tag, valStr; - for (std::vector::iterator it = cmdArgs.begin(); it != cmdArgs.end(); it++) { + for (std::vector::iterator it = cmdArgs.begin(); it != cmdArgs.end(); it++) + { std::stringstream ss((it->c_str())); // get the tag - if (!std::getline(ss, tag, '=')) { + if (!std::getline(ss, tag, '=')) + { reportErr(true, FLINT_INVALID_ARG_ERROR, it->c_str()); return false; } // get the val - if (!std::getline(ss, valStr, '=')) { + if (!std::getline(ss, valStr, '=')) + { reportErr(true, FLINT_INVALID_ARG_ERROR, it->c_str()); return false; } // make sure no other tokens are present - if (!(!std::getline(ss, valStr, '='))) { + if (!(!std::getline(ss, valStr, '='))) + { reportErr(true, FLINT_INVALID_ARG_ERROR, it->c_str()); return false; } - if (tag == "guids_num") { - if (!extractValuesFromString(valStr, numOfGuids, *it)) { + if (tag == "guids_num") + { + if (!extractValuesFromString(valStr, numOfGuids, *it)) + { return false; } - } else if (tag == "step_size") { - if (!extractValuesFromString(valStr, stepSize, *it)) { + } + else if (tag == "step_size") + { + if (!extractValuesFromString(valStr, stepSize, *it)) + { return false; } - } else { + } + else + { reportErr(true, FLINT_INVALID_ARG_ERROR, it->c_str()); return false; } @@ -1366,26 +1557,27 @@ bool SubCommand::extractUIDArgs(std::vector& cmdArgs, u_int8_t numOfGuid const char* SubCommand::fwImgTypeToStr(u_int8_t fwImgType) { - switch (fwImgType) { - case FIT_FS2: - return "FS2"; - break; + switch (fwImgType) + { + case FIT_FS2: + return "FS2"; + break; - case FIT_FS3: - return "FS3"; - break; + case FIT_FS3: + return "FS3"; + break; - case FIT_FS4: - return "FS4"; - break; + case FIT_FS4: + return "FS4"; + break; - case FIT_FSCTRL: - return "FSCTRL"; - break; + case FIT_FSCTRL: + return "FSCTRL"; + break; - default: - return "Unknown"; - break; + default: + return "Unknown"; + break; } } @@ -1409,30 +1601,31 @@ Extract4MBImageSubCommand::Extract4MBImageSubCommand() _cmdType = SC_Extract_4MB_Image; } -Extract4MBImageSubCommand::~Extract4MBImageSubCommand() -{ - -} +Extract4MBImageSubCommand::~Extract4MBImageSubCommand() {} FlintStatus Extract4MBImageSubCommand::executeCommand() { vector img; - if (preFwOps() == FLINT_FAILED) { + if (preFwOps() == FLINT_FAILED) + { return FLINT_FAILED; } - if (_imgOps->FwType() == FIT_FS2) { + if (_imgOps->FwType() == FIT_FS2) + { reportErr(true, "Extracting FW Data is applicable only for FS3/FS4 FW.\n"); return FLINT_FAILED; } - if (!_imgOps->FwExtract4MBImage(img, true)) { + if (!_imgOps->FwExtract4MBImage(img, true)) + { reportErr(true, "Extracting FW Data failed: %s.\n", _imgOps->err()); return FLINT_FAILED; } - if (!writeToFile(_flintParams.cmd_params[0], img)) { + if (!writeToFile(_flintParams.cmd_params[0], img)) + { return FLINT_FAILED; } @@ -1456,22 +1649,22 @@ AddHmacSubCommand::AddHmacSubCommand() _cmdType = SC_Add_Hmac; } -AddHmacSubCommand:: ~AddHmacSubCommand() -{ - -} +AddHmacSubCommand::~AddHmacSubCommand() {} FlintStatus AddHmacSubCommand::executeCommand() { - if (preFwOps() == FLINT_FAILED) { + if (preFwOps() == FLINT_FAILED) + { return FLINT_FAILED; } - if (_imgOps->FwType() != FIT_FS4) { + if (_imgOps->FwType() != FIT_FS4) + { reportErr(true, "Signing with HMAC is applicable only for FS4 FW.\n"); return FLINT_FAILED; } - if (!_imgOps->FwSignWithHmac(_flintParams.key.c_str())) { + if (!_imgOps->FwSignWithHmac(_flintParams.key.c_str())) + { reportErr(true, FLINT_HMAC_ERROR, _imgOps->err()); return FLINT_FAILED; } @@ -1480,22 +1673,23 @@ FlintStatus AddHmacSubCommand::executeCommand() bool AddHmacSubCommand::verifyParams() { - if (!_flintParams.key_specified) { + if (!_flintParams.key_specified) + { reportErr(true, "To sign with HMAC, you must provide a key \n"); return false; } - if (_flintParams.cmd_params.size() > 0) { - reportErr(true, FLINT_CMD_ARGS_ERROR, _name.c_str(), 1, - (int)_flintParams.cmd_params.size()); + if (_flintParams.cmd_params.size() > 0) + { + reportErr(true, FLINT_CMD_ARGS_ERROR, _name.c_str(), 1, (int)_flintParams.cmd_params.size()); return false; } return true; } /*********************** -* Class: SignSubCommand -***********************/ + * Class: SignSubCommand + ***********************/ SignSubCommand::SignSubCommand() { _name = "sign"; @@ -1504,55 +1698,60 @@ SignSubCommand::SignSubCommand() _flagLong = "sign"; _flagShort = ""; _paramExp = "None"; - _example = FLINT_NAME " -i fw_image.bin [--private_key file.pem --key_uuid uuid_string] OR [--openssl_engine engine --openssl_key_id identifier --key_uuid uuid_string] sign"; + _example = FLINT_NAME + " -i fw_image.bin [--private_key file.pem --key_uuid uuid_string] OR [--openssl_engine engine --openssl_key_id identifier --key_uuid uuid_string] sign"; _v = Wtv_Img; _maxCmdParamNum = 0; _cmdType = SC_Sign; } -SignSubCommand:: ~SignSubCommand() -{ - -} +SignSubCommand::~SignSubCommand() {} FlintStatus SignSubCommand::executeCommand() { - if (preFwOps() == FLINT_FAILED) { + if (preFwOps() == FLINT_FAILED) + { return FLINT_FAILED; } - if (_imgOps->FwType() != FIT_FS3 && _imgOps->FwType() != FIT_FS4) { + if (_imgOps->FwType() != FIT_FS3 && _imgOps->FwType() != FIT_FS4) + { reportErr(true, IMAGE_SIGN_TYPE_ERROR); return FLINT_FAILED; } - if (_flintParams.openssl_engine_usage_specified) { + if (_flintParams.openssl_engine_usage_specified) + { #if !defined(NO_OPEN_SSL) && !defined(NO_DYNAMIC_ENGINE) MlxSign::OpensslEngineSigner engineSigner(_flintParams.openssl_engine, _flintParams.openssl_key_id); int rc = engineSigner.init(); - if (rc) { + if (rc) + { reportErr(true, "Failed to initialize %s engine (rc = 0x%x)\n", _flintParams.openssl_engine.c_str(), rc); return FLINT_FAILED; } - //flint sign over openssl only allow for 4K key size + // flint sign over openssl only allow for 4K key size int keySize = engineSigner.getPrivateKeySize(); - if( keySize != KEY_SIZE_512 ) { + if (keySize != KEY_SIZE_512) + { reportErr(true, "The HSM key has to be 4096 bit!\n"); return FLINT_FAILED; } vector fourMbImage; vector signature; vector sha; - if (!_imgOps->FwCalcSHA(MlxSign::SHA512, sha, fourMbImage)) { + if (!_imgOps->FwCalcSHA(MlxSign::SHA512, sha, fourMbImage)) + { reportErr(true, FLINT_IMAGE_READ_ERROR, _imgOps->err()); return FLINT_FAILED; } rc = engineSigner.sign(fourMbImage, signature); - if (rc) { + if (rc) + { reportErr(true, "Failed to set private key from engine (rc = 0x%x)\n", rc); return FLINT_FAILED; } - if (!_imgOps->InsertSecureFWSignature(signature, _flintParams.privkey_uuid.c_str(), - &verifyCbFunc)) { + if (!_imgOps->InsertSecureFWSignature(signature, _flintParams.privkey_uuid.c_str(), &verifyCbFunc)) + { reportErr(true, FLINT_SIGN_ERROR, _imgOps->err()); return FLINT_FAILED; } @@ -1562,34 +1761,42 @@ FlintStatus SignSubCommand::executeCommand() return FLINT_FAILED; #endif } - if (_flintParams.hsm_specified) { + if (_flintParams.hsm_specified) + { // Luna HSM not supported reportErr(true, FLINT_NO_HSM); return FLINT_FAILED; } - else { - if (_flintParams.privkey_specified && _flintParams.uuid_specified) { - if (_flintParams.privkey2_specified && _flintParams.uuid2_specified) { + else + { + if (_flintParams.privkey_specified && _flintParams.uuid_specified) + { + if (_flintParams.privkey2_specified && _flintParams.uuid2_specified) + { if (!_imgOps->FwSignWithTwoRSAKeys(_flintParams.privkey_file.c_str(), - _flintParams.privkey_uuid.c_str(), - _flintParams.privkey2_file.c_str(), - _flintParams.privkey2_uuid.c_str(), - &verifyCbFunc)) { + _flintParams.privkey_uuid.c_str(), + _flintParams.privkey2_file.c_str(), + _flintParams.privkey2_uuid.c_str(), + &verifyCbFunc)) + { reportErr(true, FLINT_SIGN_ERROR, _imgOps->err()); return FLINT_FAILED; } } - else { - if (!_imgOps->signForFwUpdate(_flintParams.privkey_file.c_str(), - _flintParams.privkey_uuid.c_str(), - &verifyCbFunc)) { + else + { + if (!_imgOps->signForFwUpdate(_flintParams.privkey_file.c_str(), _flintParams.privkey_uuid.c_str(), + &verifyCbFunc)) + { reportErr(true, FLINT_SIGN_ERROR, _imgOps->err()); return FLINT_FAILED; } } } - else { - if (!_imgOps->FwInsertSHA256(&verifyCbFunc)) { + else + { + if (!_imgOps->FwInsertSHA256(&verifyCbFunc)) + { reportErr(true, FLINT_SIGN_ERROR, _imgOps->err()); return FLINT_FAILED; } @@ -1600,59 +1807,74 @@ FlintStatus SignSubCommand::executeCommand() bool SignSubCommand::verifyParams() { - if (_flintParams.openssl_engine_usage_specified) { - if (_flintParams.privkey_uuid.empty()) { + if (_flintParams.openssl_engine_usage_specified) + { + if (_flintParams.privkey_uuid.empty()) + { reportErr(true, "To Sign the image with OpenSSL you must provide UUID string.\n"); return false; } - if (_flintParams.openssl_engine.empty() || _flintParams.openssl_key_id.empty()) { + if (_flintParams.openssl_engine.empty() || _flintParams.openssl_key_id.empty()) + { reportErr(true, "To Sign the image with OpenSSL you must provide the engine and the key identifier.\n"); return false; } - if (_flintParams.openssl_key_id.find("type=public", 0) != std::string::npos) { + if (_flintParams.openssl_key_id.find("type=public", 0) != std::string::npos) + { reportErr(true, "The Sign command with --openssl_key_id flag does not accept public keys\n"); - return false; + return false; } - if (_flintParams.privkey_specified) { - reportErr(true, "The Sign command does not accept --private_key flag with the following flags: --openssl_engine, --openssl_key_id\n"); + if (_flintParams.privkey_specified) + { + reportErr( + true, + "The Sign command does not accept --private_key flag with the following flags: --openssl_engine, --openssl_key_id\n"); return false; } } - else if (_flintParams.hsm_specified) { - if (_flintParams.uuid_specified == false) { + else if (_flintParams.hsm_specified) + { + if (_flintParams.uuid_specified == false) + { reportErr(true, HSM_UUID_MISSING); return false; } - if (_flintParams.private_key_label_specified == false) { + if (_flintParams.private_key_label_specified == false) + { reportErr(true, HSM_PRIVATE_KEY_LABEL_MISSING); return false; } - if (_flintParams.hsm_password_specified == false) { + if (_flintParams.hsm_password_specified == false) + { reportErr(true, HSM_PASSWORD_MISSING); return false; } } - else { - if (_flintParams.privkey_specified ^ _flintParams.uuid_specified) { + else + { + if (_flintParams.privkey_specified ^ _flintParams.uuid_specified) + { reportErr(true, "To Sign the image with RSA you must provide " - "private key and uuid.\n"); + "private key and uuid.\n"); return false; } - if (!_flintParams.privkey_specified && _flintParams.privkey2_specified) { + if (!_flintParams.privkey_specified && _flintParams.privkey2_specified) + { reportErr(true, "Use --private_key if you want to sign with only one key.\n"); return false; } - if (_flintParams.privkey2_specified ^ _flintParams.uuid2_specified) { + if (_flintParams.privkey2_specified ^ _flintParams.uuid2_specified) + { reportErr(true, "To Sign the image with two RSA keys you must provide " - "two private keys and two uuid.\n"); + "two private keys and two uuid.\n"); return false; } - if (_flintParams.cmd_params.size() > 0) { - reportErr(true, FLINT_CMD_ARGS_ERROR, _name.c_str(), 1, - (int)_flintParams.cmd_params.size()); + if (_flintParams.cmd_params.size() > 0) + { + reportErr(true, FLINT_CMD_ARGS_ERROR, _name.c_str(), 1, (int)_flintParams.cmd_params.size()); return false; } } @@ -1665,7 +1887,8 @@ bool SignSubCommand::verifyParams() BinaryCompareSubCommand::BinaryCompareSubCommand() { _name = "Binary compare"; - _desc = "Binary compare between device firmware and given BIN file. If there is a silent mode, no progress is displayed."; + _desc = + "Binary compare between device firmware and given BIN file. If there is a silent mode, no progress is displayed."; _extendedDesc = _desc; _flagLong = "binary_compare"; _flagShort = "bc"; @@ -1682,10 +1905,11 @@ BinaryCompareSubCommand::BinaryCompareSubCommand() _unknownProgress = 0; } -BinaryCompareSubCommand:: ~BinaryCompareSubCommand() +BinaryCompareSubCommand::~BinaryCompareSubCommand() { #ifndef NO_MSTARCHIVE - if (_mfa2Pkg != NULL) { + if (_mfa2Pkg != NULL) + { delete _mfa2Pkg; } #endif @@ -1693,14 +1917,18 @@ BinaryCompareSubCommand:: ~BinaryCompareSubCommand() bool BinaryCompareSubCommand::verifyParams() { - if (_flintParams.num_of_args == 2) { + if (_flintParams.num_of_args == 2) + { return true; } - else if (_flintParams.num_of_args == 3 && _flintParams.silent == true) { + else if (_flintParams.num_of_args == 3 && _flintParams.silent == true) + { return true; } - else { - fprintf(stdout, "The binary comparison command doesn't accept any flags, except device, image and silent mode.\n"); + else + { + fprintf(stdout, + "The binary comparison command doesn't accept any flags, except device, image and silent mode.\n"); return false; } } @@ -1708,50 +1936,60 @@ bool BinaryCompareSubCommand::verifyParams() FlintStatus BinaryCompareSubCommand::compareMFA2() { #ifndef NO_MSTARCHIVE - if (preFwOps() == FLINT_FAILED) { + if (preFwOps() == FLINT_FAILED) + { return FLINT_FAILED; } - mfile *mf = _fwOps->getMfileObj(); + mfile* mf = _fwOps->getMfileObj(); int is_livefish_mode = dm_is_livefish_mode(mf); - if (is_livefish_mode == 1) { + if (is_livefish_mode == 1) + { _flintParams.override_cache_replacement = true; } - if (!_fwOps->FwQuery(&_devInfo, true, false, true, false, (_flintParams.silent == false))) { + if (!_fwOps->FwQuery(&_devInfo, true, false, true, false, (_flintParams.silent == false))) + { reportErr(true, FLINT_FAILED_QUERY_ERROR, "Device", _flintParams.device.c_str(), _fwOps->err()); return FLINT_FAILED; } vector componentBuffer; - map_string_to_component matchingComponentsMap = _mfa2Pkg->getMatchingComponents( - (char*)_devInfo.fw_info.psid, _devInfo.fw_info.fw_ver); + map_string_to_component matchingComponentsMap = + _mfa2Pkg->getMatchingComponents((char*)_devInfo.fw_info.psid, _devInfo.fw_info.fw_ver); u_int32_t matchingSize = matchingComponentsMap.size(); - if (matchingSize == 0) { - printf("\33[2K\r");//clear the current line + if (matchingSize == 0) + { + printf("\33[2K\r"); // clear the current line reportErr(true, "CompareMFA2 : No matching component found for device.\n"); return FLINT_FAILED; } std::vector imgBuffInFile; - if (!_fwOps->FwExtract4MBImage(imgBuffInFile, true, (_flintParams.silent == false), true)) { + if (!_fwOps->FwExtract4MBImage(imgBuffInFile, true, (_flintParams.silent == false), true)) + { reportErr(true, FLINT_IMAGE_READ_ERROR, _fwOps->err()); return FLINT_FAILED; } - for (u_int32_t choice = 0; choice < matchingSize; choice++) { - if (_mfa2Pkg->unzipComponent(matchingComponentsMap, choice, componentBuffer) == false) { + for (u_int32_t choice = 0; choice < matchingSize; choice++) + { + if (_mfa2Pkg->unzipComponent(matchingComponentsMap, choice, componentBuffer) == false) + { reportErr(true, "CompareMFA2 : Error occurred while extracting MFA2\n"); return FLINT_FAILED; } unsigned int i = 0; - for (; i < imgBuffInFile.size(); i++) { - if (componentBuffer[i] != imgBuffInFile[i]) { + for (; i < imgBuffInFile.size(); i++) + { + if (componentBuffer[i] != imgBuffInFile[i]) + { break; } } - if (i == imgBuffInFile.size()) { - printf("\33[2K\r");//clear the current line + if (i == imgBuffInFile.size()) + { + printf("\33[2K\r"); // clear the current line printf("Binary comparison success.\n"); return FLINT_SUCCESS; } } - printf("\33[2K\r");//clear the current line + printf("\33[2K\r"); // clear the current line reportErr(true, "Binary comparison failed.\n"); return FLINT_FAILED; #else @@ -1765,7 +2003,8 @@ FlintStatus BinaryCompareSubCommand::executeCommand() #ifndef NO_MSTARCHIVE string mfa2file = _flintParams.image; _mfa2Pkg = MFA2::LoadMFA2Package(mfa2file); - if (_mfa2Pkg != NULL) { + if (_mfa2Pkg != NULL) + { _flintParams.mfa2_specified = true; return compareMFA2(); } @@ -1776,83 +2015,95 @@ FlintStatus BinaryCompareSubCommand::executeCommand() vector image_critical; vector image_non_critical; - if (preFwOps() == FLINT_FAILED) { - if (_imgOps) { + if (preFwOps() == FLINT_FAILED) + { + if (_imgOps) + { const char* errMessage = _imgOps->err(); - if (errMessage != NULL && strlen(errMessage) > 0) { + if (errMessage != NULL && strlen(errMessage) > 0) + { reportErr(true, "Error occurred while executing flint initialization : %s\n", errMessage); } } return FLINT_FAILED; } - mfile *mf = _fwOps->getMfileObj(); + mfile* mf = _fwOps->getMfileObj(); int is_livefish_mode = dm_is_livefish_mode(mf); - if (is_livefish_mode == 1) { + if (is_livefish_mode == 1) + { _flintParams.override_cache_replacement = true; } _fwType = _fwOps->FwType(); // query both image and device - if (!_fwOps->FwQuery(&_devInfo, true, false, true, false, (_flintParams.silent == false))) { + if (!_fwOps->FwQuery(&_devInfo, true, false, true, false, (_flintParams.silent == false))) + { reportErr(true, FLINT_FAILED_QUERY_ERROR, "Device", _flintParams.device.c_str(), _fwOps->err()); return FLINT_FAILED; } - if (!_imgOps->FwQuery(&_imgInfo)) { + if (!_imgOps->FwQuery(&_imgInfo)) + { reportErr(true, FLINT_FAILED_QUERY_ERROR, "Image", _flintParams.image.c_str(), _imgOps->err()); return FLINT_FAILED; } - if (strcmp((char*)_imgInfo.fw_info.psid, (char*)_devInfo.fw_info.psid)) { - printf("\33[2K\r");//clear the current line + if (strcmp((char*)_imgInfo.fw_info.psid, (char*)_devInfo.fw_info.psid)) + { + printf("\33[2K\r"); // clear the current line reportErr(true, "Binary comparison failed - PSID mismatch.\n"); return FLINT_FAILED; } FwVersion img_version = FwOperations::createFwVersion(&_imgInfo.fw_info); FwVersion dev_version = FwOperations::createFwVersion(&_devInfo.fw_info); - if (img_version != dev_version) { - printf("\33[2K\r"); //clear the current line + if (img_version != dev_version) + { + printf("\33[2K\r"); // clear the current line reportErr(true, "Binary comparison failed - versions mismatch.\n"); return FLINT_FAILED; } u_int32_t imgSize = 0; - //on first call we get the image size - if (!_fwOps->FwReadData(NULL, &imgSize)) { + // on first call we get the image size + if (!_fwOps->FwReadData(NULL, &imgSize)) + { reportErr(true, FLINT_IMAGE_READ_ERROR, _fwOps->err()); return FLINT_FAILED; } std::vector imgBuffOnDevice(imgSize); - //on second call we fill it - if (!_fwOps->FwReadData((void*)(&imgBuffOnDevice[0]), &imgSize, _flintParams.silent == false)) { + // on second call we fill it + if (!_fwOps->FwReadData((void*)(&imgBuffOnDevice[0]), &imgSize, _flintParams.silent == false)) + { reportErr(true, FLINT_IMAGE_READ_ERROR, _fwOps->err()); return FLINT_FAILED; } std::vector imgBuffInFile; - if (!_imgOps->FwExtract4MBImage(imgBuffInFile, false, (_flintParams.silent == false))) { + if (!_imgOps->FwExtract4MBImage(imgBuffInFile, false, (_flintParams.silent == false))) + { reportErr(true, FLINT_IMAGE_READ_ERROR, _imgOps->err()); return FLINT_FAILED; } _imgOps->PrepItocSectionsForCompare(image_critical, image_non_critical); _fwOps->PrepItocSectionsForCompare(device_critical, device_non_critical); - if (image_critical != device_critical) { + if (image_critical != device_critical) + { reportErr(true, "Binary comparison failed - binary mismatch.\n"); return FLINT_FAILED; } - if (image_non_critical != device_non_critical) { + if (image_non_critical != device_non_critical) + { reportErr(true, "Binary comparison failed - binary mismatch.\n"); return FLINT_FAILED; } - printf("\33[2K\r");//clear the current line + printf("\33[2K\r"); // clear the current line printf("Binary comparison success.\n"); return FLINT_SUCCESS; } - /*********************** -* Class: SignRSASubCommand -***********************/ + * Class: SignRSASubCommand + ***********************/ SignRSASubCommand::SignRSASubCommand() { _name = "rsa_sign"; @@ -1861,56 +2112,62 @@ SignRSASubCommand::SignRSASubCommand() _flagLong = "rsa_sign"; _flagShort = ""; _paramExp = "None"; - _example = FLINT_NAME " -i fw_image.bin [--private_key file.pem] OR [--private_key_label