Newer
Older
* Distributed under the OSI-approved Apache License, Version 2.0. See
* accompanying file Copyright.txt for details.
*
* Created on: May 17, 2017
* Author: William F Godoy godoywf@ornl.gov
#include <stdexcept> //std::invalid_argument
#include "adios2/ADIOSTypes.h"
void RemoveCommentsXML(std::string ¤tContent) noexcept
std::string::size_type startComment(currentContent.find("<!--"));
while (startComment != currentContent.npos)
{
std::string::size_type endComment(currentContent.find("-->"));
currentContent.erase(startComment, endComment - startComment + 3);
startComment = currentContent.find("<!--");
}
}
TagXML GetTagXML(const std::string tagName, const std::string &content,
std::string::size_type &position)
{
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
[](const std::string input, const std::string &content,
std::string::size_type &position) -> std::string::size_type {
const std::string::size_type inputPosition =
GetStringPositionXML(input, content, position);
if (inputPosition != std::string::npos)
{
position = inputPosition + input.size();
}
return inputPosition;
};
TagXML tagXML;
std::string name(tagName);
if (name.back() == ' ')
{
name.pop_back();
}
auto openingStart = lf_SetPositions("<" + name, content, position);
auto openingEnd = lf_SetPositions(">", content, position);
if (openingStart == std::string::npos || openingEnd == std::string::npos)
{
tagXML.IsFull = false;
return tagXML;
}
tagXML.Header = content.substr(openingStart, openingEnd + 1 - openingStart);
auto closingStart =
GetStringPositionXML("</" + name + ">", content, position);
if (closingStart == std::string::npos)
throw std::invalid_argument(
"ERROR: could not find closing tag </" + name +
"> in XML config file, in call to ADIOS constructor\n");
tagXML.IsFull = true;
tagXML.Elements =
content.substr(openingEnd + 1, closingStart - (openingEnd + 1));
// std::cout << "START..." << tagXML.Header << "...";
// std::cout << tagXML.Elements << "...END\n";
return tagXML;
}
std::string::size_type
GetStringPositionXML(const std::string input, const std::string &content,
const std::string::size_type &startPosition) noexcept
{
std::string::size_type foundPosition(content.find(input, startPosition));
if (foundPosition == content.npos)
// check if it is not inside " " or ' '
std::string::size_type currentPosition(startPosition);
const std::string::size_type singleQuotePosition(
content.find('\'', currentPosition));
const std::string::size_type doubleQuotePosition(
content.find('\"', currentPosition));
if ((singleQuotePosition == content.npos &&
doubleQuotePosition == content.npos) ||
(singleQuotePosition == content.npos &&
(doubleQuotePosition == content.npos &&
foundPosition < singleQuotePosition) ||
(foundPosition < singleQuotePosition &&
foundPosition < doubleQuotePosition))
{
break;
}
// find the closing corresponding quote
std::string::size_type closingQuotePosition;
if (singleQuotePosition != content.npos &&
doubleQuotePosition == content.npos)
{
currentPosition = singleQuotePosition;
closingQuotePosition = content.find('\'', currentPosition + 1);
else if (singleQuotePosition == content.npos &&
doubleQuotePosition != content.npos)
{
currentPosition = doubleQuotePosition;
closingQuotePosition = content.find('\"', currentPosition + 1);
}
else
{
if (singleQuotePosition < doubleQuotePosition)
{
currentPosition = singleQuotePosition;
closingQuotePosition = content.find('\'', currentPosition + 1);
{
currentPosition = doubleQuotePosition;
closingQuotePosition = content.find('\"', currentPosition + 1);
// if can't find closing it's open until the end
if (closingQuotePosition == content.npos)
currentPosition == content.npos;
break;
}
currentPosition = closingQuotePosition + 1;
// if this point is reached it means it's a value inside " " or ' ',
// iterate
foundPosition = content.find(input, currentPosition);
currentPosition = foundPosition;
Params GetTagAttributesXML(const std::string &tagHeader)
auto lf_GetQuotedValue = [](const char quote,
const std::string::size_type "ePosition,
std::string ¤tTag) -> std::string {
currentTag = currentTag.substr(quotePosition + 1);
auto nextQuotePosition = currentTag.find(quote);
if (nextQuotePosition == currentTag.npos)
throw std::invalid_argument(
"ERROR: Invalid attribute in..." + currentTag +
"...check XML file, in call to ADIOS constructor\n");
const std::string value(currentTag.substr(0, nextQuotePosition));
currentTag = currentTag.substr(nextQuotePosition + 1);
};
auto lf_GetAttributes = [&](const std::string &tag) -> Params {
Params attributes;
std::string currentTag(tag.substr(tag.find_first_of(" \t\n")));
std::string::size_type currentPosition(0);
while (currentTag.find('=', currentPosition) !=
currentTag.npos) // equalPosition
currentTag = currentTag.substr(
currentTag.find_first_not_of(" \t\n", currentPosition));
auto equalPosition = currentTag.find('=');
if (currentTag.size() <= equalPosition + 1)
{
throw std::invalid_argument(
"ERROR: tag " + tag +
" is incomplete, check XML config file, "
"in call to ADIOS constructor\n");
}
std::string key(currentTag.substr(0, equalPosition));
key.erase(key.find_last_not_of(" \t\n") + 1);
auto quotePosition =
currentTag.find_first_not_of(" \t\n", equalPosition + 1);
const char quote = currentTag.at(quotePosition);
if (quote == '\'' || quote == '"')
{
value = lf_GetQuotedValue(quote, quotePosition, currentTag);
throw std::invalid_argument(
"ERROR: quote must be \" or ' in XML config tag " + tag +
", in call to ADIOS constructor");
attributes.emplace(key, value);
currentPosition = quotePosition + value.size() + 1;
}
return attributes;
};
// BODY of function starts here
Params attributes;
// eliminate < >
std::string openingTag = tagHeader.substr(1, tagHeader.size() - 2);
if (tagHeader.back() == '/') // last char is / --> "XML empty tag"
// attributes = lf_GetAttributes(openingTag);
// throw exception here, ADIOS2 doesn't allow XML empty tags
else if (tagHeader[0] == '/') // first char is / ---> closing tag
if (attributes.size() > 0)
{
throw std::invalid_argument(
" can't have attributes, in call to ADIOS constructor\n");
}
}
else // opening tag
{
void InitXML(const std::string configXML, const MPI_Comm mpiComm,
const bool debugMode,
std::vector<std::shared_ptr<Transform>> &transforms,
std::map<std::string, IO> &ios)
{
// independent IO
std::string fileContents(FileToString(configXML));
if (fileContents.empty())
{
// issue a warning?
return;
}
std::string::size_type position(0);
const TagXML adiosConfigXML(
GetTagXML("adios-config", fileContents, position));
// process transforms, not yet implemented
const TagXML transformXML(
GetTagXML("transform ", adiosConfigXML.Elements, position));
{
break;
}
// InitTransform(transformTag, debugMode, transforms);
}
const TagXML ioXML(GetTagXML("io ", adiosConfigXML.Elements, position));
if (ioXML.Header.empty()) // no more groups to find
InitIOXML(ioXML, mpiComm, debugMode, transforms, ios);
void InitIOXML(const TagXML &ioXML, const MPI_Comm mpiComm,
const bool debugMode,
std::vector<std::shared_ptr<Transform>> &transforms,
std::map<std::string, IO> &ios)
{
const Params ioAttributes(GetTagAttributesXML(ioXML.Header));
std::string ioName;
for (const auto &ioAttribute : ioAttributes)
{
if (ioAttribute.first == "name")
{
ioName = ioAttribute.second;
}
}
if (debugMode)
{
if (ioName.empty())
{
throw std::invalid_argument(
"ERROR: io name=\"value\" attribute not found in opening XML "
"tag " +
", check XML config file, in call to ADIOS constructor\n");
}
if (ios.count(ioName) == 1) // io exists
{
throw std::invalid_argument("ERROR: io name " + ioName +
" must be unique in XML config file, "
"in call to ADIOS constructor\n");
}
}
// emplace io with inConfigFile argument as true
auto itIO = ios.emplace(ioName, IO(ioName, mpiComm, true, debugMode));
// process engine
TagXML engineXML(GetTagXML("engine ", ioXML.Elements, position));
if (!engineXML.Header.empty()) // found first one
InitEngineXML(engineXML, debugMode, itIO.first->second);
}
if (debugMode)
{
// try finding a 2nd one from current position
TagXML engineXML(GetTagXML("engine ", ioXML.Elements, position));
if (!engineXML.Header.empty()) // found first one
throw std::invalid_argument(
"ERROR: more than one engine found in <io name=" + ioName +
"...>, only one per io tag is allowed in XML "
"config file, in call to "
"ADIOS constructor\n");
// process transports
while (position != std::string::npos)
{
TagXML transportXML(GetTagXML("transport", ioXML.Elements, position));
if (transportXML.Header.empty()) // no more groups to find
InitTransportXML(transportXML, debugMode, itIO.first->second);
void InitEngineXML(const TagXML &engineXML, const bool debugMode, IO &io)
const Params attributes = GetTagAttributesXML(engineXML.Header);
std::string type;
for (const auto &attribute : attributes)
{
if (attribute.first == "type")
{
type = attribute.second;
if (!type.empty())
{
io.SetEngine(type);
}
io.SetParameters(ParseParamsXML(engineXML.Elements, debugMode));
void InitTransportXML(const TagXML &transportXML, const bool debugMode, IO &io)
const Params attributes = GetTagAttributesXML(transportXML.Header);
std::string type;
for (const auto &attribute : attributes)
{
if (attribute.first == "type")
{
type = attribute.second;
if (type.empty())
{
throw std::invalid_argument(
"ERROR: missing transport type in " + transportXML.Header +
", in XML config file, in call to ADIOS constructor\n");
}
io.AddTransport(type, ParseParamsXML(transportXML.Elements, debugMode));
Params ParseParamsXML(const std::string &tagElements, const bool debugMode)
auto start = tagElements.find_first_not_of(" \t\n");
auto end = tagElements.find_last_not_of(" \t\n");
std::string parametersString(tagElements.substr(start, end - start + 1));
if (debugMode)
{
if (parametersString.back() != ';')
{
throw std::invalid_argument(
"ERROR: parameters in config XML file must end with a ; " +
tagElements + ", in call to ADIOS constructor\n");
}
}
std::istringstream parametersSS(parametersString);
std::string pair;
Params parameters;
while (std::getline(parametersSS, pair, ';'))
{
pair = pair.substr(pair.find_first_not_of(" \t\n"));
auto equalPosition = pair.find("=");
if (debugMode)
{
if (equalPosition == std::string::npos ||
equalPosition == pair.size())
{
throw std::invalid_argument("ERROR: wrong parameter " + pair +
" format is "
"key=value in XML config file, in "
"call to ADIOS constructor\n");
}
}
const std::string key(pair.substr(0, equalPosition));
const std::string value(pair.substr(equalPosition + 1));
parameters.emplace(key, value);
}
return parameters;
}