/*************************************************************************** PUserFcnBase.cpp Author: Andreas Suter e-mail: andreas.suter@psi.ch ***************************************************************************/ /*************************************************************************** * Copyright (C) 2007-2026 by Andreas Suter * * andreas.suter@psi.ch * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include "PUserFcnBase.h" ClassImp(PUserFcnBase) //-------------------------------------------------------------------------- /** * \brief Parses an XML file using buffer-based parsing for better compatibility. * * This function provides a replacement for TSAXParser::ParseFile() that works * reliably across different environments. Some systems have issues with direct * file parsing, but buffer-based parsing (ParseBuffer) works consistently. * * \section parsexml_usage Usage in User Functions * * User functions that need to read XML configuration files should use this * function instead of TSAXParser::ParseFile(): * * \code{.cpp} * class TMyConfigurableFcn : public PUserFcnBase { * private: * MyConfigHandler fHandler; // Derived from TSAXParser callbacks * * public: * Bool_t LoadConfig(const char* configFile) { * TSAXParser parser; * parser.ConnectToHandler("MyConfigHandler", &fHandler); * * Int_t status = parseXmlFile(&parser, configFile); * if (status != 0) { * std::cerr << "Failed to parse config: " << configFile << std::endl; * return false; * } * return true; * } * }; * \endcode * * \section parsexml_algorithm Algorithm * * 1. Opens the file in binary mode, seeking to end * 2. Determines file size from stream position * 3. Allocates buffer and reads entire file * 4. Passes buffer to TSAXParser::ParseBuffer() * 5. Cleans up buffer memory * * \param saxParser Pointer to a configured TSAXParser object. The parser * should have its handler connected before calling this function. * \param startup_path_name Full filesystem path to the XML file to parse. * * \return Status code: * - 0: Success - file parsed without errors * - 1: File error - could not open or read the file * - >1: XML parse error from TSAXParser::ParseBuffer() * * \see PStartupHandler for an example of XML parsing in musrfit * \see TSAXParser for ROOT's SAX parser documentation */ Int_t parseXmlFile(TSAXParser *saxParser, const char *startup_path_name) { Int_t status; std::fstream xmlFile; UInt_t xmlSize = 0; Char_t *xmlBuffer = nullptr; xmlFile.open(startup_path_name, std::ios::in | std::ios::ate); // open file for reading and go to the end of the file if (xmlFile.is_open()) { // check if file has been opened successfully xmlSize = xmlFile.tellg(); // get the position within the stream == size of the file (since we are at the end) xmlFile.seekg(0, std::ios::beg); // go back to the beginning of the stream xmlBuffer = new Char_t[xmlSize]; // allocate buffer memory for the whole XML file xmlFile.read(xmlBuffer, xmlSize); // read in the whole XML file into the buffer xmlFile.close(); // close the XML file } if (!xmlBuffer) { // file has not been read into the buffer status = 1; } else { status = saxParser->ParseBuffer(xmlBuffer, xmlSize); // parse buffer delete[] xmlBuffer; // free the buffer memory xmlBuffer = nullptr; } return status; } //-------------------------------------------------------------------------- /** * \brief Global storage for user function objects requiring persistent state. * * This vector provides a global container for user functions that need to * maintain state across multiple evaluations or share data between runs. * It is primarily used by user functions implementing the "global part" * interface (NeedGlobalPart(), SetGlobalPart(), GlobalPartIsValid()). * * \section gGlobalUserFcn_usage Usage Pattern * * User functions with expensive initialization (lookup tables, precomputed * grids, loaded data files) store their global objects here: * * \code{.cpp} * // In user function's SetGlobalPart implementation: * void TMyFcn::SetGlobalPart(std::vector &globalPart, UInt_t idx) { * if (idx < globalPart.size() && globalPart[idx] != nullptr) { * fGlobal = static_cast(globalPart[idx]); * } else { * fGlobal = new MyGlobalData(); * fGlobal->Initialize(); // Expensive one-time computation * if (idx < globalPart.size()) * globalPart[idx] = fGlobal; * else * globalPart.push_back(fGlobal); * } * } * \endcode * * \note The vector stores void pointers, so user functions must cast * appropriately and manage memory for their specific data types. * * \warning User functions are responsible for proper cleanup of their * global objects to avoid memory leaks. * * \see PUserFcnBase::SetGlobalPart() for the interface to populate this vector * \see PTheory for how global parts are initialized during theory setup */ std::vector gGlobalUserFcn;