10#include <QRegularExpression> 
   11#include "PvlKeyword.h" 
   12#include "IException.h" 
   16#include "PvlSequence.h" 
   19using json = nlohmann::json;
 
  103    if (
size() == 0) 
return true;
 
  104    if (index < 0 || index >= (
int)
m_values.size()) {
 
 
  121    QString 
final = 
name.trimmed();
 
  122    if (
final.contains(QRegExp(
"\\s"))) {
 
  123      QString msg = 
"[" + 
name + 
"] is invalid. Keyword name cannot ";
 
  124      msg += 
"contain whitespace.";
 
  134      QByteArray finalAscii = 
final.toLatin1();
 
  135      m_name = 
new char[finalAscii.size() + 1];
 
  136      strncpy(
m_name, finalAscii.data(), 
final.size() + 1);
 
 
  186      m_units = 
new std::vector<QString>();
 
  191    for (
int i = 0; i < 
m_values.size(); i++) {
 
 
  209    while(!found && ++i < (
int) 
m_values.size()) {
 
  223      (*m_units)[i] = units;
 
  226      IString msg = 
"PvlKeyword::setUnits called with value [" + value +
 
  227                    "] which does not exist in this Keyword";
 
 
  304    if (jsonobj.is_array()) {
 
  305      QString msg = 
"Unable to convert " + 
name() + 
" with nested json array value into PvlKeyword";
 
  308    else if (jsonobj.is_number())
 
  310      value = QString::number(jsonobj.get<
double>(), 
'g', 16);
 
  312    else if (jsonobj.is_boolean())
 
  314      value = QString(jsonobj.get<
bool>() ? 
"true" : 
"false");
 
  316    else if (jsonobj.is_null())
 
  318      value = QString(
"Null");
 
  322      value = QString::fromStdString(jsonobj);
 
 
  358  PvlKeyword::operator QString()
 const {
 
  359    return operator[](0);
 
  376    if (index < 0 || index >= (
int)
m_values.size()) {
 
  378                   "for Keyword [" + QString(
m_name) + 
"]";
 
 
  398    if (index < 0 || index >= (
int)
m_values.size()) {
 
 
  417    if (index < 0 || index >= (
int)
m_units->size()) {
 
 
  444    else if (
comment.size() == 1) {
 
 
  472      token = cmt.
Token(
" ");
 
  473      int length = temp.size() + token.size() + 1;
 
  474      while((length < 72) && (token.size() > 0)) {
 
  476        token = cmt.
Token(
" ");
 
  477        length = temp.size() + token.size() + 1;
 
  481    if (token.size() != 0) 
addComment(token.c_str());
 
 
  501    if (index < 0 || index >= (
int)
m_comments->size()) {
 
 
  517    static bool firstTime = 
true;
 
  518    static bool iPVL = 
true;
 
  526      if (s == 
"PVL") iPVL = 
false;
 
  529    if (iPVL) 
return toIPvl(value);
 
 
  542    bool lastlower = 
true;
 
  543    for (
int i = 0; i < value.size(); i++) {
 
  544      if ((lastlower) && (value[i].isUpper())) upcase = 
true;
 
  545      if (value[i] == 
'_') {
 
  549        out += value[i].toUpper();
 
  554        out += value[i].toLower();
 
  555        if (value[i].isLower()) lastlower = 
true;
 
 
  569    bool lastlower = 
false;
 
  570    for (
int i = 0; i < value.size(); i++) {
 
  571      if ((lastlower) && (value[i].isUpper())) out += 
"_";
 
  572      if (value[i] == 
'_') {
 
  577        out += value[i].toUpper();
 
  578        if (value[i].isLower()) lastlower = 
true;
 
 
  593                               const QString &QString2) {
 
  597    s1.ConvertWhiteSpace();
 
  598    s2.ConvertWhiteSpace();
 
  606    if (s1 == s2) 
return true;
 
 
  620    if (index < 0 || index >= (
int)
m_values.size()) {
 
 
  635    for (
int i = 0; i < seq.Size(); i++) {
 
  637      for (
int j = 0; j < (int)seq[i].
size(); j++) {
 
  638        QString val = seq[i][j];
 
  639        if (val.contains(
" ")) {
 
  640          temp += 
"\"" + val + 
"\"";
 
  645        if (j < (
int) seq[i].size() - 1) temp += 
", ";
 
 
  669                                     const QString &textToWrite,
 
  720    QString remainingText = textToWrite;
 
  726    vector< pair<int, int> > quotedAreas;
 
  730    if (textToWrite.count() > 0 && (textToWrite[0] == 
'(' || textToWrite[0] == 
'"')) {
 
  741    vector< pair<char, char> > quoteStartEnds;
 
  742    quoteStartEnds.push_back(pair<char, char>(
'"', 
'"'));
 
  743    quoteStartEnds.push_back(pair<char, char>(
'\'', 
'\''));
 
  744    quoteStartEnds.push_back(pair<char, char>(
'<', 
'>'));
 
  748    for (
int pos = 0; pos < remainingText.size(); pos++) {
 
  750      if (remainingText[pos] == 
'\n' || remainingText[pos] == 
'\r') {
 
  751        if (pos != remainingText.size() - 1) {
 
  752          remainingText = remainingText.mid(0, pos) +
 
  753                          remainingText.mid(pos + 1);
 
  756          remainingText = remainingText.mid(0, pos);
 
  761      if (quoteStart == -1) {
 
  763              remainingText[pos-1] == 
' ' &&
 
  764              remainingText[pos] == 
' ') {
 
  765          remainingText = remainingText.mid(0, pos) +
 
  766                          remainingText.mid(pos + 1);
 
  771      for (
unsigned int i = 0;
 
  772          (quoteStart < 0) && i < quoteStartEnds.size();
 
  774        if (quoteStartEnds[i].first == remainingText[pos]) {
 
  784      if (quoteStart != (
int)pos && quoteStart != -1) {
 
  785        for (
unsigned int i = 0; i < quoteStartEnds.size(); i++) {
 
  786          if (quoteStartEnds[i].second == remainingText[pos]) {
 
  787            if (quoteStartEnds[i].first != remainingText[quoteStart]) {
 
  792            quotedAreas.push_back(pair<int, int>(quoteStart, pos));
 
  806    int charsLeft = spaceForText;
 
  807    int printedSoFar = 0;
 
  810    while(!remainingText.isEmpty()) {
 
  812      int lastSpacePosition = charsLeft;
 
  816      if (lastSpacePosition >= (
int)remainingText.length()) {
 
  817        lastSpacePosition = remainingText.length();
 
  824        int excellentSpace = -1;
 
  825        int searchPosition = lastSpacePosition;
 
  826        bool doneSearching = 
false;
 
  828        while(!doneSearching) {
 
  829          bool currentPosQuoted = 
false;
 
  831          for (
unsigned int i = 0; i < quotedAreas.size(); i++) {
 
  832            if (searchPosition + printedSoFar >= quotedAreas[i].first &&
 
  833                searchPosition + printedSoFar <= quotedAreas[i].second) {
 
  834              currentPosQuoted = 
true;
 
  838          if (remainingText[searchPosition] == 
' ') {
 
  839            bool validSpace = 
true;
 
  843            if (searchPosition > 0 && remainingText[searchPosition - 1] == 
'-') {
 
  847            if (validSpace && goodSpace < 0) {
 
  848              goodSpace = searchPosition;
 
  854            if (validSpace && !currentPosQuoted) {
 
  855              if ((
int)searchPosition < (int)(remainingText.size() - 1) &&
 
  856                  remainingText[searchPosition+1] != 
'<') {
 
  857                excellentSpace = searchPosition;
 
  862          doneSearching = (excellentSpace >= 0 || searchPosition <= 1);
 
  867        if (excellentSpace > 0) {
 
  868          lastSpacePosition = excellentSpace;
 
  870        else if (goodSpace > 0) {
 
  871          lastSpacePosition = goodSpace;
 
  874          lastSpacePosition = -1;
 
  880      if (lastSpacePosition >= 0) {
 
  881        os << remainingText.mid(0, lastSpacePosition);
 
  883        remainingText = remainingText.mid(lastSpacePosition);
 
  884        printedSoFar += lastSpacePosition;
 
  890        if (remainingText.mid(charsLeft-1, 2) == 
"//") {
 
  891          os << remainingText.mid(0, charsLeft - 2);
 
  893          remainingText = remainingText.mid(charsLeft - 2);
 
  894          printedSoFar += charsLeft - 2;
 
  897          os << remainingText.mid(0, charsLeft - 1);
 
  899          remainingText = remainingText.mid(charsLeft - 1);
 
  900          printedSoFar += charsLeft - 1;
 
  905      if (!remainingText.isEmpty()) {
 
  910        if (remainingText[0] == 
' ') {
 
  911          remainingText = remainingText.mid(1);
 
  916      charsLeft = spaceForText;
 
 
  930    for (
int space = 0; space < numSpaces; space ++) {
 
 
  969    QString keywordString;
 
  971    bool keywordDone = 
false;
 
  972    bool multiLineComment = 
false;
 
  973    bool error = !is.good();
 
  975    while(!error && !keywordDone) {
 
  976      istream::pos_type beforeLine = is.tellg();
 
  983      if (line.isEmpty() && !is.good()) {
 
  984        if (keywordString.isEmpty() ||
 
  985            keywordString[keywordString.size()-1] == 
'\n') {
 
  988          if (multiLineComment) {
 
  997      bool comment = 
false;
 
  999      if (!multiLineComment) {
 
 1000        if (line.size() > 0 && line[0] == 
'#') {
 
 1004        if (line.size() > 1 && line[0] == 
'/' &&
 
 1005            (line[1] == 
'*' || line[1] == 
'/')) {
 
 1008          if (line[1] == 
'*') {
 
 1009            multiLineComment = 
true;
 
 1010            keywordString += line.mid(0, 2);
 
 1011            line = line.mid(2).trimmed();
 
 1016      if (multiLineComment) {
 
 1019        if (line.contains(
"/*")) {
 
 1020          IString msg = 
"Error when reading a pvl: Cannot have ['/*'] inside a " 
 1021                        "multi-line comment";
 
 1025        if (line.contains(
"*/")) {
 
 1026          multiLineComment = 
false;
 
 1028          line = line.mid(0, line.indexOf(
"*/")).trimmed() + 
" */";
 
 1032      if (line.isEmpty()) {
 
 1037        keywordString += line + 
'\n';
 
 1041      else if (keywordString.isEmpty()) {
 
 1042        keywordString = line;
 
 1045      else if (!comment && keywordString[keywordString.size()-1] == 
'-') {
 
 1046        keywordString = keywordString.mid(0, keywordString.size() - 1) + line;
 
 1050        keywordString += 
" " + line;
 
 1053      if (line[line.size()-1] == 
'-') {
 
 1057      std::vector<QString> keywordComments;
 
 1058      QString keywordName;
 
 1059      std::vector< std::pair<QString, QString> > keywordValues;
 
 1061      bool attemptedRead = 
false;
 
 1070        if (is.eof() && !is.bad()) {
 
 1075        is.seekg(beforeLine, ios::beg);
 
 1077        QString msg = 
"Unable to read PVL keyword [";
 
 1078        msg += keywordString;
 
 1085      if (attemptedRead) {
 
 1089        if (is.good() && is.peek() == 
'<' && !keywordValues.empty()) {
 
 1096        for (
unsigned int value = 0; value < keywordValues.size(); value++) {
 
 1097          result.
addValue(keywordValues[value].first,
 
 1098                          keywordValues[value].second);
 
 1104      if (!attemptedRead) {
 
 1105        error = error || !is.good();
 
 1112      while(keywordString.contains(
'\n')) {
 
 1113        keywordString = keywordString.mid(keywordString.indexOf(
'\n') + 1);
 
 1118      if (keywordString.isEmpty() && !multiLineComment) {
 
 1119        msg = 
"PVL input contains no Pvl Keywords";
 
 1121      else if (multiLineComment) {
 
 1122        msg = 
"PVL input ends while still in a multi-line comment";
 
 1125        msg = 
"The PVL keyword [" + keywordString + 
"] does not appear to be";
 
 1126        msg += 
" a valid Pvl Keyword";
 
 1134      while(keywordString.contains(
'\n'))
 
 1135        keywordString = keywordString.mid(keywordString.indexOf(
'\n') + 1);
 
 1139      if (keywordString.isEmpty()) {
 
 1140        msg = 
"Error reading PVL keyword";
 
 1143        msg = 
"The PVL keyword [" + keywordString + 
"] does not appear to be";
 
 
 1160    for (
unsigned int i = 0; i < 
comments.size(); i++) {
 
 
 1181                                    std::vector<QString> &keywordComments,
 
 1182                                    QString &keywordName,
 
 1183                                    std::vector< std::pair<QString, QString> > &keywordValues) {
 
 1185    keywordComments.clear();
 
 1187    keywordValues.clear();
 
 1190    bool explicitIncomplete = 
false;
 
 1199    if (keyword.isEmpty()) 
return 0;
 
 1218    while(keyword.contains(
"\n")) {
 
 1221      bool noneStripped = 
true;
 
 1225      QString keywordStart = keyword.mid(0, 2);
 
 1228      if (keywordStart == 
"/*") {
 
 1229        noneStripped = 
false;
 
 1230        bool inComment = 
true;
 
 1232        while(inComment && keyword.contains(
"*/")) {
 
 1235          int closePos = keyword.indexOf(
"*/\n");
 
 1237          if (closePos == -1) {
 
 1238            closePos = keyword.indexOf(
"*/") + 2;
 
 1239            keyword = keyword.mid(0, closePos) + 
"\n" +
 
 1240                      keyword.mid(closePos);
 
 1243          QString 
comment = keyword.mid(0, keyword.indexOf(
"\n")).trimmed();
 
 1247          bool needsStart = (
comment.size() < 2);
 
 1248          bool needsStartSpace = 
comment.size() < 3;
 
 1250          int commentEndPos = 
comment.size() - 2;
 
 1251          bool needsEnd = (commentEndPos < 0);
 
 1252          bool needsEndSpace = 
comment.size() < 3;
 
 1258            needsStart = (
comment.mid(0, 2) != 
"/*");
 
 1262            needsEnd = (
comment.mid(commentEndPos, 2) != 
"*/");
 
 1265          if (!needsStartSpace) {
 
 1266            needsStartSpace = (
comment.mid(0, 3) != 
"/* ");
 
 1269          if (!needsEndSpace) {
 
 1270            needsEndSpace = (
comment.mid(commentEndPos - 1, 3) != 
" */");
 
 1276          else if (needsStartSpace) {
 
 1283          else if (needsEndSpace) {
 
 1287          inComment = needsEnd;
 
 1289          keywordComments.push_back(
comment);
 
 1291          if (keyword.contains(
"\n")) {
 
 1292            keyword = keyword.mid(keyword.indexOf(
"\n") + 1).trimmed();
 
 1297            if (keyword.size() >= 2)
 
 1298              keywordStart = keyword.mid(0, 2);
 
 1300            inComment = (keywordStart == 
"/*");
 
 1307        for (
unsigned int index = 0; index < keywordComments.size(); index++) {
 
 1308          QString 
comment = keywordComments[index];
 
 1315        for (
unsigned int index = 0; index < keywordComments.size(); index++) {
 
 1316          QString 
comment = keywordComments[index];
 
 1318          while(
comment.size() < longest) {
 
 1323          keywordComments[index] = 
comment;
 
 1329      for (
unsigned int commentType = 0;
 
 1330          commentType < 
sizeof(
comments) / 
sizeof(QString);
 
 1333        if (keywordStart.startsWith(
comments[commentType])) {
 
 1336          QString 
comment = keyword.mid(0, keyword.indexOf(
"\n"));
 
 1337          keywordComments.push_back(
comment.trimmed());
 
 1339          noneStripped = 
false;
 
 1341          if (keyword.contains(
"\n")) {
 
 1342            keyword = keyword.mid(keyword.indexOf(
"\n") + 1).trimmed();
 
 1349      if (noneStripped && keyword.contains(
"/*") &&
 
 1350          keyword.contains(
"*/")) {
 
 1351        QString firstPart = keyword.mid(0, keyword.indexOf(
"\n"));
 
 1352        QString lastPart = keyword.mid(keyword.indexOf(
"\n") + 1);
 
 1354        keyword = firstPart.trimmed() + 
" " + lastPart.trimmed();
 
 1355        noneStripped = 
false;
 
 1359        QString msg = 
"Expected a comment in PVL but found [";
 
 1367    if (keyword.isEmpty()) {
 
 1382    keywordName = readValue(keyword, explicitIncomplete);
 
 1386    if (keyword.isEmpty()) {
 
 1400    if (keyword[0] != 
'=') {
 
 1401      QString msg = 
"Expected an assignment [=] when reading PVL, but found [";
 
 1408    keyword = keyword.mid(1).trimmed();
 
 1410    if (keyword.isEmpty()) {
 
 1415    if (keyword[0] == 
'(' || keyword[0] == 
'{') {
 
 1425      char closingParen = ((keyword[0] == 
'(') ? 
')' : 
'}');
 
 1426      char wrongClosingParen = ((keyword[0] == 
'(') ? 
'}' : 
')');
 
 1427      bool closedProperly = 
false;
 
 1429      vector< pair<char, char> > extraDelims;
 
 1430      extraDelims.push_back(pair<char, char>(
'(', 
')'));
 
 1431      extraDelims.push_back(pair<char, char>(
'{', 
'}'));
 
 1435      keyword = keyword.mid(1).trimmed();
 
 1438      if (!keyword.isEmpty() && keyword[0] == closingParen) {
 
 1439        closedProperly = 
true;
 
 1445      while(!keyword.isEmpty() && keyword[0] != closingParen) {
 
 1448        bool foundComma = 
false;
 
 1451        QString nextItem = readValue(keyword, explicitIncomplete, extraDelims);
 
 1453        if (!keyword.isEmpty() && keyword[0] == wrongClosingParen) {
 
 1455          QString msg = 
"Incorrect array close when reading PVL; expected [";
 
 1456          msg += closingParen;
 
 1457          msg += 
"] but found [";
 
 1458          msg += wrongClosingParen;
 
 1459          msg += 
"] in keyword named [";
 
 1466        pair<QString, QString> keywordValue;
 
 1469        keywordValue.first = nextItem;
 
 1473        if (!keyword.isEmpty() && keyword[0] == 
'<') {
 
 1474          QString unitsValue = readValue(keyword, explicitIncomplete);
 
 1475          keywordValue.second = unitsValue;
 
 1479        if (!keyword.isEmpty() && keyword[0] == 
',') {
 
 1481          keyword = keyword.mid(1).trimmed();
 
 1487        if (!foundComma && keyword.isEmpty()) {
 
 1491        bool foundCloseParen = (!keyword.isEmpty() && keyword[0] == closingParen);
 
 1493        if (foundCloseParen) {
 
 1494          closedProperly = 
true;
 
 1500        if (foundComma && foundCloseParen) {
 
 1501          QString msg = 
"Unexpected close of keyword-value array when reading " 
 1507        if (!foundComma && !foundCloseParen) {
 
 1509          if (explicitIncomplete) 
return false;
 
 1512          QString msg = 
"Found extra data after [";
 
 1514          msg += 
"] in array when reading PVL";
 
 1519        keywordValues.push_back(keywordValue);
 
 1522      if (!closedProperly) {
 
 1527      if (!keyword.isEmpty()) {
 
 1528        keyword = keyword.mid(1).trimmed();
 
 1533      if (!keyword.isEmpty() && keyword[0] == 
'<') {
 
 1534        QString units = readValue(keyword, explicitIncomplete);
 
 1535        for (
unsigned int val = 0; val < keywordValues.size(); val++) {
 
 1536          if (keywordValues[val].second.isEmpty()) {
 
 1537            keywordValues[val].second = units;
 
 1551      pair<QString, QString> keywordValue;
 
 1552      keywordValue.first = readValue(keyword, explicitIncomplete);
 
 1554      if (!keyword.isEmpty() && keyword[0] == 
'<') {
 
 1555        keywordValue.second = readValue(keyword, explicitIncomplete);
 
 1558      keywordValues.push_back(keywordValue);
 
 1565    if (explicitIncomplete) {
 
 1572    if (!keyword.isEmpty()) {
 
 1574      if (keyword[0] == 
'#' ||
 
 1575          ((keyword.size() > 1 && keyword[0] == 
'/') &&
 
 1576           (keyword[1] == 
'/' || keyword[1] == 
'*'))) {
 
 1577        keywordComments.push_back(keyword);
 
 1579        if (keyword.size() > 1 && keyword.mid(0, 2) == 
"/*") {
 
 1580          if (keyword.mid(keyword.size() - 2, 2) != 
"*/")
 
 1589    QRegularExpression regex(
"^,");
 
 1590    QRegularExpressionMatch match = regex.match(keyword);
 
 1591    if (!keyword.isEmpty() && match.hasMatch()) {
 
 1592          keywordValues.at(0).first += keyword;
 
 1599    if (!keyword.isEmpty()) {
 
 1600      QString msg = 
"Keyword has extraneous data [";
 
 1602      msg += 
"] at the end";
 
 
 1611  QString PvlKeyword::readValue(QString &keyword, 
bool "eProblem) {
 
 1612    std::vector< std::pair<char, char> > otherDelims;
 
 1614    return readValue(keyword, quoteProblem, otherDelims);
 
 1633  QString PvlKeyword::readValue(QString &keyword, 
bool "eProblem,
 
 1634                                    const std::vector< std::pair<char, char> > &
 
 1640    keyword = keyword.trimmed();
 
 1642    if (keyword.isEmpty()) {
 
 1650    bool impliedQuote = 
true;
 
 1651    QChar quoteEnd = 
' ';
 
 1652    bool keepQuotes = 
false;
 
 1654    if (keyword[0] == 
'\'' || keyword[0] == 
'"') {
 
 1655      quoteEnd = keyword[0];
 
 1656      impliedQuote = 
false;
 
 1658    else if (keyword[0] == 
'<') {
 
 1660      impliedQuote = 
false;
 
 1664      char implicitQuotes[] = {
 
 1674      bool foundImplicitQuote = 
false;
 
 1677      while(!foundImplicitQuote && currentPos != keyword.size()) {
 
 1678        for (
unsigned int quote = 0;
 
 1679            quote < 
sizeof(implicitQuotes) / 
sizeof(
char);
 
 1681          if (keyword[currentPos] == implicitQuotes[quote]) {
 
 1682            quoteEnd = implicitQuotes[quote];
 
 1683            foundImplicitQuote = 
true;
 
 1687        if (!foundImplicitQuote) {
 
 1693    for (
unsigned int delim = 0; delim < otherDelimiters.size(); delim ++) {
 
 1694      if (keyword[0] == otherDelimiters[delim].first) {
 
 1695        quoteEnd = otherDelimiters[delim].second;
 
 1697        impliedQuote = 
false;
 
 1705    if (!impliedQuote) {
 
 1706      startQuote += keyword[0];
 
 1707      keyword = keyword.mid(1);
 
 1711    int quoteEndPos = keyword.indexOf(quoteEnd);
 
 1713    if (quoteEndPos != -1) {
 
 1714      value = keyword.mid(0, quoteEndPos);
 
 1720      if (!impliedQuote) {
 
 1721        keyword = keyword.mid(quoteEndPos + 1);
 
 1724        keyword = keyword.mid(quoteEndPos);
 
 1728      keyword = keyword.trimmed();
 
 1731        value = startQuote + value + quoteEnd;
 
 1738    else if (!impliedQuote) {
 
 1740      keyword = startQuote + keyword;
 
 1741      quoteProblem = 
true;
 
 
 1771    while(is.good() && lineOfData.isEmpty()) {
 
 1775            (!lineOfData.size() || lineOfData[lineOfData.size() - 1] != 
'\n')) {
 
 1776        char next = is.get();
 
 1780          is.seekg(0, ios::end);
 
 1791        if (insideComment &&
 
 1792            lineOfData.size() >= 2 && lineOfData[lineOfData.size() - 2] == 
'*' &&
 
 1793            lineOfData[lineOfData.size() - 1] == 
'/') {
 
 1797        else if (lineOfData.size() >= 2 &&
 
 1798                lineOfData[lineOfData.size() - 2] == 
'/' &&
 
 1799                lineOfData[lineOfData.size() - 1] == 
'*') {
 
 1800          insideComment = 
true;
 
 1805      lineOfData = lineOfData.trimmed();
 
 1809            (is.peek() == 
' ' ||
 
 1810             is.peek() == 
'\r' ||
 
 1811             is.peek() == 
'\n')) {
 
 
 1833    bool removeFormatter = 
false;
 
 1834    if (tempFormat == NULL) {
 
 1836      removeFormatter = 
true;
 
 1840    for (
int i = 0; i < keyword.
comments(); i++) {
 
 1841      for (
int j = 0; j < keyword.
indent(); j++) os << 
" ";
 
 1842      os << keyword.
comment(i) << tempFormat->formatEOL();
 
 1846    int startColumn = 0;
 
 1847    for (
int i = 0; i < keyword.
indent(); i++) {
 
 1851    QString keyname = tempFormat->formatName(keyword);
 
 1853    startColumn += keyname.length();
 
 1856    for (
int i = 0; i < keyword.
width() - (
int)keyname.size(); ++i) {
 
 1864    if (keyword.
size() == 0) {
 
 1865      os << tempFormat->formatValue(keyword);
 
 1869    QString stringToWrite;
 
 1870    for (
int i = 0; i < keyword.
size(); i ++) {
 
 1871      stringToWrite += tempFormat->formatValue(keyword, i);
 
 1879    if (removeFormatter) 
delete tempFormat;
 
 
 1887    if (
this != &other) {
 
 1906      if (other.m_units) {
 
 1907        m_units = 
new std::vector<QString>(*other.m_units);
 
 1915      if (other.m_comments) {
 
 1916        m_comments = 
new std::vector<QString>(*other.m_comments);
 
 
 1940    int iSize = pvlKwrd.size();
 
 1942    QString sType = 
m_values[0].toLower();
 
 1945    if (psValueType.length()) {
 
 1946      psValueType = psValueType.toLower();
 
 1949    double dRangeMin=0, dRangeMax=0;
 
 1950    bool bRange = 
false;
 
 1951    bool bValue = 
false;
 
 1952    if (pvlKwrdValue != NULL) {
 
 1953      QString sValueName = pvlKwrdValue->name();
 
 1956      if (sValueName.contains(
"__Range")) {
 
 1957        dRangeMin = 
toDouble((*pvlKwrdValue)[0]);
 
 1958        dRangeMax = 
toDouble((*pvlKwrdValue)[1]);
 
 1961      else if (sValueName.contains(
"__Value")) {
 
 1967    if (sType == 
"integer") {
 
 1968      for (
int i=0; i<iSize; i++) {
 
 1969        QString sValue = pvlKwrd[i].toLower();
 
 1970        if (sValue != 
"null"){
 
 1973            iValue = 
toInt(sValue);
 
 1975            QString sErrMsg = 
"\"" +pvlKwrd.name() +
"\" expects an Integer value";
 
 1978          if (bRange && (iValue < dRangeMin || iValue > dRangeMax)) {
 
 1979            QString sErrMsg = 
"\"" +pvlKwrd.name() +
"\" is not in the specified Range";
 
 1983            bool bFound = 
false;
 
 1984            for (
int j=0; j<pvlKwrdValue->size(); j++) {
 
 1985              if (iValue == 
toInt((*pvlKwrdValue)[j])) {
 
 1991              QString sErrMsg = 
"\"" +pvlKwrd.name() +
"\" has value not in the accepted list";
 
 1996          if (psValueType.length()) {
 
 1997            if ((psValueType == 
"positive" && iValue < 0) || (psValueType == 
"negative" && iValue >= 0) ) {
 
 1998              QString sErrMsg = 
"\"" +pvlKwrd.name() +
"\" has invalid value";
 
 2008    if (sType == 
"double") {
 
 2009      for (
int i=0; i<iSize; i++) {
 
 2010        QString sValue = pvlKwrd[i].toLower();
 
 2011        if (sValue != 
"null"){
 
 2013          if (bRange && (dValue < dRangeMin || dValue > dRangeMax)) {
 
 2014            QString sErrMsg = 
"\"" +pvlKwrd.name() +
"\" is not in the specified Range";
 
 2018            bool bFound = 
false;
 
 2019            for (
int j=0; j<pvlKwrdValue->size(); j++) {
 
 2020              if (dValue == 
toDouble((*pvlKwrdValue)[j])) {
 
 2026              QString sErrMsg = 
"\"" +pvlKwrd.name() +
"\" has value not in the accepted list";
 
 2031          if (psValueType.length()) {
 
 2032            if ((psValueType == 
"positive" && dValue < 0) || (psValueType == 
"negative" && dValue >= 0) ) {
 
 2033              QString sErrMsg = 
"\"" +pvlKwrd.name() +
"\" has invalid value";
 
 2043    if (sType == 
"boolean") {
 
 2044      for (
int i=0; i<iSize; i++) {
 
 2045        QString sValue = pvlKwrd[i].toLower();
 
 2046        if (sValue != 
"null" && sValue != 
"true" && sValue != 
"false"){
 
 2047          QString sErrMsg = 
"Wrong Type of value in the Keyword \"" + 
name() + 
"\" \n";
 
 2055    if (sType == 
"string") {
 
 2056      for (
int i=0; i<iSize; i++) {
 
 2057        QString sValue = pvlKwrd[i].toLower();
 
 2059          bool bValFound = 
false;
 
 2060          for (
int i=0; i<pvlKwrdValue->size(); i++) {
 
 2061            if (sValue == (*pvlKwrdValue)[i].toLower()) {
 
 2067            QString sErrMsg = 
"Wrong Type of value in the Keyword \"" + 
name() + 
"\" \n";
 
 
@ Unknown
A type of error that cannot be classified as any of the other error types.
 
@ User
A type of error that could only have occurred due to a mistake on the user's part (e....
 
@ Programmer
This error is for when a programmer made an API call that was illegal.
 
Adds specific functionality to C++ strings.
 
IString UpCase()
Converst any lower case characters in the object IString with uppercase characters.
 
IString Token(const IString &separator)
Returns the first token in the IString.
 
Contains multiple PvlContainers.
 
A single keyword-value pair.
 
PvlKeyword()
Constructs a blank PvlKeyword object.
 
std::vector< QString > * m_comments
The comments for the keyword.
 
QVarLengthArray< QString, 1 > m_values
The values in the keyword.
 
const QString & operator[](int index) const
Gets value for this object at specified index.
 
void setName(QString name)
Sets the keyword name.
 
void setJsonValue(nlohmann::json jsonobj, QString unit="")
Sets new value from Json.
 
QString toIPvl(const QString &value) const
Converts a value to iPVL format.
 
int width() const
Returns the current set longest keyword name.
 
QString name() const
Returns the keyword name.
 
int size() const
Returns the number of values stored in this keyword.
 
PvlKeyword & operator+=(QString value)
Adds a value.
 
std::vector< QString > * m_units
The units for the values.
 
bool isNull(const int index=0) const
Decides whether a value is null or not at a given index.
 
char * m_name
The keyword's name... This is a c-string for memory efficiency.
 
static bool readCleanKeyword(QString keyword, std::vector< QString > &keywordComments, QString &keywordName, std::vector< std::pair< QString, QString > > &keywordValues)
This reads a keyword compressed back to 1 line of data (excluding comments, which are included on sep...
 
QString unit(const int index=0) const
Returns the units of measurement of the element of the array of values for the object at the specifie...
 
~PvlKeyword()
Destructs a PvlKeyword object.
 
void setFormat(PvlFormat *formatter)
Set the PvlFormatter used to format the keyword name and value(s)
 
int comments() const
Returns the number of lines of comments associated with this keyword.
 
QString comment(const int index) const
Return a comment at the specified index.
 
PvlFormat * m_formatter
Formatter object.
 
int indent() const
Returns the current indent level.
 
QString reform(const QString &value) const
Checks if the value needs to be converted to PVL or iPVL and returns it in the correct format.
 
void setUnits(QString units)
Sets the unit of measure for all current values if any exist.
 
static bool stringEqual(const QString &string1, const QString &string2)
Checks to see if two QStrings are equal.
 
PvlFormat * format()
Get the current PvlFormat or create one.
 
void addCommentWrapped(QString comment)
Automatically wraps and adds long comments to the PvlKeyword.
 
QString toPvl(const QString &value) const
Converts a value to PVL format.
 
void addJsonValue(nlohmann::json jsonobj, QString unit="")
Adds a value with units.
 
PvlKeyword & operator=(QString value)
Sets new values.
 
void writeSpaces(std::ostream &, int) const
This writes numSpaces spaces to the ostream.
 
std::ostream & writeWithWrap(std::ostream &os, const QString &textToWrite, int startColumn, PvlFormat &format) const
Wraps output so that length doesn't exceed the character limit.
 
void setValue(QString value, QString unit="")
Sets new values.
 
void addComment(QString comment)
Add a comment to the PvlKeyword.
 
int m_width
The width of the longest keyword.
 
bool isEquivalent(QString string1, int index=0) const
Checks to see if a value with a specified index is equivalent to another QString.
 
void clearComment()
Clears the current comments.
 
void addComments(const std::vector< QString > &comments)
This method adds multiple comments at once by calling AddComments on each element in the vector.
 
static QString readLine(std::istream &is, bool insideComment)
This method reads one line of data from the input stream.
 
int m_indent
The number of indentations to make.
 
void clear()
Clears all values and units for this PvlKeyword object.
 
void validateKeyword(PvlKeyword &pvlKwrd, QString psValueType="", PvlKeyword *pvlKwrdRange=NULL)
Validate Keyword for type and required values.
 
void init()
Clears all PvlKeyword data.
 
void addValue(QString value, QString unit="")
Adds a value with units.
 
@ Traverse
Search child objects.
 
Parse and return elements of a Pvl sequence.
 
QString ArraySubscriptNotInRange(int index)
This error should be used when an Isis object or application is checking array bounds and the legal r...
 
This is free and unencumbered software released into the public domain.
 
int toInt(const QString &string)
Global function to convert from a string to an integer.
 
std::istream & operator>>(std::istream &is, CSVReader &csv)
Input read operator for input stream sources.
 
double toDouble(const QString &string)
Global function to convert from a string to a double.
 
QDebug operator<<(QDebug debug, const Hillshade &hillshade)
Print this class out to a QDebug object.
 
Namespace for the standard library.