]> git.mxchange.org Git - simgear.git/blobdiff - simgear/misc/props_io.cxx
Patch from Cameron Moore:
[simgear.git] / simgear / misc / props_io.cxx
index 122d6bffa0d307d20c3e044cbf558cda892f092c..45f8829665f7d5f85b69d122066e0b5800dba413 100644 (file)
@@ -9,6 +9,7 @@
 
 #include "sg_path.hxx"
 #include "props.hxx"
+#include "props_io.hxx"
 
 #include STL_IOSTREAM
 #if !defined(SG_HAVE_NATIVE_SGI_COMPILERS)
@@ -30,7 +31,7 @@ SG_USING_STD(string);
 SG_USING_STD(vector);
 SG_USING_STD(map);
 
-#define DEFAULT_MODE (SGPropertyNode::READ|SGPropertyNode::WRITE|SGPropertyNode::ARCHIVE)
+#define DEFAULT_MODE (SGPropertyNode::READ|SGPropertyNode::WRITE)
 
 
 \f
@@ -43,7 +44,9 @@ class PropsVisitor : public XMLVisitor
 public:
 
   PropsVisitor (SGPropertyNode * root, const string &base)
-    : _ok(true), _root(root), _level(0), _base(base) {}
+    : _root(root), _level(0), _base(base), _hasException(false) {}
+
+  virtual ~PropsVisitor () {}
 
   void startXML ();
   void endXML ();
@@ -51,9 +54,13 @@ public:
   void endElement (const char * name);
   void data (const char * s, int length);
   void warning (const char * message, int line, int column);
-  void error (const char * message, int line, int column);
 
-  bool isOK () const { return _ok; }
+  bool hasException () const { return _hasException; }
+  sg_io_exception &getException () { return _exception; }
+  void setException (const sg_io_exception &exception) {
+    _exception = exception;
+    _hasException = true;
+  }
 
 private:
 
@@ -84,12 +91,13 @@ private:
     _level--;
   }
 
-  bool _ok;
   string _data;
   SGPropertyNode * _root;
   int _level;
   vector<State> _state_stack;
   string _base;
+  sg_io_exception _exception;
+  bool _hasException;
 };
 
 void
@@ -108,19 +116,23 @@ PropsVisitor::endXML ()
 
 
 /**
- * Check a yes/no flag that defaults to 'yes'.
+ * Check a yes/no flag, with default.
  */
 static bool
-checkFlag (const char * flag)
+checkFlag (const char * flag, bool defaultState = true)
 {
-  if (flag == 0 || string(flag) == "y")
+  if (flag == 0)
+    return defaultState;
+  else if (string(flag) == "y")
     return true;
   else if (string(flag) == "n")
     return false;
   else {
-    SG_LOG(SG_INPUT, SG_ALERT, "Unrecognized flag value '" << flag
-          << "', assuming 'y'");
-    return true;
+    string message = "Unrecognized flag value '";
+    message += flag;
+    message += '\'';
+                               // FIXME: add location info
+    throw sg_io_exception(message, "SimGear Property Reader");
   }
 }
 
@@ -131,9 +143,10 @@ PropsVisitor::startElement (const char * name, const XMLAttributes &atts)
 
   if (_level == 0) {
     if (string(name) != (string)"PropertyList") {
-      SG_LOG(SG_INPUT, SG_ALERT, "Root element name is " <<
-            name << "; expected PropertyList");
-      _ok = false;
+      string message = "Root element name is ";
+      message += name;
+      message += "; expected PropertyList";
+      throw sg_io_exception(message, "SimGear Property Reader");
     }
     push_state(_root, "", DEFAULT_MODE);
   }
@@ -161,14 +174,20 @@ PropsVisitor::startElement (const char * name, const XMLAttributes &atts)
     int mode = 0;
 
     attval = atts.getValue("read");
-    if (checkFlag(attval))
+    if (checkFlag(attval, true))
       mode |= SGPropertyNode::READ;
     attval = atts.getValue("write");
-    if (checkFlag(attval))
+    if (checkFlag(attval, true))
       mode |= SGPropertyNode::WRITE;
     attval = atts.getValue("archive");
-    if (checkFlag(attval))
+    if (checkFlag(attval, false))
       mode |= SGPropertyNode::ARCHIVE;
+    attval = atts.getValue("trace-read");
+    if (checkFlag(attval, false))
+      mode |= SGPropertyNode::TRACE_READ;
+    attval = atts.getValue("trace-write");
+    if (checkFlag(attval, false))
+      mode |= SGPropertyNode::TRACE_WRITE;
 
                                // Check for an alias.
     attval = atts.getValue("alias");
@@ -181,13 +200,11 @@ PropsVisitor::startElement (const char * name, const XMLAttributes &atts)
     attval = atts.getValue("include");
     if (attval != 0) {
       SGPath path(SGPath(_base).dir());
-      cerr << "Base is " << _base << endl;
-      cerr << "Dir is " << SGPath(_base).dir() << endl;
       path.append(attval);
-      if (!readProperties(path.str(), node)) {
-       SG_LOG(SG_INPUT, SG_ALERT, "Failed to read include file "
-              << attval);
-       _ok = false;
+      try {
+       readProperties(path.str(), node);
+      } catch (sg_io_exception &e) {
+       setException(e);
       }
     }
 
@@ -218,13 +235,15 @@ PropsVisitor::endElement (const char * name)
     } else if (st.type == "double") {
       ret = st.node->setDoubleValue(strtod(_data.c_str(), 0));
     } else if (st.type == "string") {
-      ret = st.node->setStringValue(_data);
+      ret = st.node->setStringValue(_data.c_str());
     } else if (st.type == "unspecified") {
-      ret = st.node->setUnspecifiedValue(_data);
+      ret = st.node->setUnspecifiedValue(_data.c_str());
     } else {
-      SG_LOG(SG_INPUT, SG_ALERT, "Unrecognized data type " << st.type
-            << " assuming 'unspecified'");
-      ret = st.node->setUnspecifiedValue(_data);
+      string message = "Unrecognized data type '";
+      message += st.type;
+      message += '\'';
+                               // FIXME: add location information
+      throw sg_io_exception(message, "SimGear Property Reader");
     }
     if (!ret)
       SG_LOG(SG_INPUT, SG_ALERT, "readProperties: Failed to set "
@@ -254,14 +273,6 @@ PropsVisitor::warning (const char * message, int line, int column)
         << message << " at line " << line << ", column " << column);
 }
 
-void
-PropsVisitor::error (const char * message, int line, int column)
-{
-  SG_LOG(SG_INPUT, SG_ALERT, "readProperties: FATAL: " <<
-        message << " at line " << line << ", column " << column);
-  _ok = false;
-}
-
 
 \f
 ////////////////////////////////////////////////////////////////////////
@@ -277,12 +288,14 @@ PropsVisitor::error (const char * message, int line, int column)
  * @param base A base path for resolving external include references.
  * @return true if the read succeeded, false otherwise.
  */
-bool
+void
 readProperties (istream &input, SGPropertyNode * start_node,
                const string &base)
 {
   PropsVisitor visitor(start_node, base);
-  return readXML(input, visitor) && visitor.isOK();
+  readXML(input, visitor, base);
+  if (visitor.hasException())
+    throw visitor.getException();
 }
 
 
@@ -293,18 +306,13 @@ readProperties (istream &input, SGPropertyNode * start_node,
  * @param start_node The root node for reading properties.
  * @return true if the read succeeded, false otherwise.
  */
-bool
+void
 readProperties (const string &file, SGPropertyNode * start_node)
 {
-  cerr << "Reading properties from " << file << endl;
-  ifstream input(file.c_str());
-  if (input.good()) {
-    return readProperties(input, start_node, file);
-  } else {
-    SG_LOG(SG_INPUT, SG_ALERT, "Error reading property list from file "
-          << file);
-    return false;
-  }
+  PropsVisitor visitor(start_node, file);
+  readXML(file, visitor);
+  if (visitor.hasException())
+    throw visitor.getException();
 }
 
 
@@ -336,6 +344,9 @@ getTypeName (SGPropertyNode::Type type)
     return "double";
   case SGPropertyNode::STRING:
     return "string";
+  case SGPropertyNode::ALIAS:
+  case SGPropertyNode::NONE:
+    return "unspecified";
   }
 
   // keep the compiler from squawking
@@ -382,36 +393,57 @@ writeAtts (ostream &output, const SGPropertyNode * node)
   int index = node->getIndex();
 
   if (index != 0)
-    output << " n = \"" << index << '"';
+    output << " n=\"" << index << '"';
 
+#if 0
   if (!node->getAttribute(SGPropertyNode::READ))
     output << " read=\"n\"";
 
   if (!node->getAttribute(SGPropertyNode::WRITE))
     output << " write=\"n\"";
 
-  if (!node->getAttribute(SGPropertyNode::ARCHIVE))
-    output << " archive=\"n\"";
+  if (node->getAttribute(SGPropertyNode::ARCHIVE))
+    output << " archive=\"y\"";
+#endif
 
 }
 
 
+/**
+ * Test whether a node is archivable or has archivable descendants.
+ */
 static bool
-writeNode (ostream &output, const SGPropertyNode * node, int indent)
+isArchivable (const SGPropertyNode * node)
+{
+  // FIXME: it's inefficient to do this all the time
+  if (node->getAttribute(SGPropertyNode::ARCHIVE))
+    return true;
+  else {
+    int nChildren = node->nChildren();
+    for (int i = 0; i < nChildren; i++)
+      if (isArchivable(node->getChild(i)))
+       return true;
+  }
+  return false;
+}
+
+
+static bool
+writeNode (ostream &output, const SGPropertyNode * node,
+          bool write_all, int indent)
 {
                                // Don't write the node or any of
                                // its descendants unless it is
                                // allowed to be archived.
-  if (!node->getAttribute(SGPropertyNode::ARCHIVE))
+  if (!write_all && !isArchivable(node))
     return true;               // Everything's OK, but we won't write.
 
-  const string &name = node->getName();
-  int index = node->getIndex();
+  const string name = node->getName();
   int nChildren = node->nChildren();
 
                                // If there is a literal value,
                                // write it first.
-  if (node->hasValue()) {
+  if (node->hasValue() && (write_all || node->getAttribute(SGPropertyNode::ARCHIVE))) {
     doIndent(output, indent);
     output << '<' << name;
     writeAtts(output, node);
@@ -427,15 +459,14 @@ writeNode (ostream &output, const SGPropertyNode * node, int indent)
     }
   }
 
-                               // If there are children, write them
-                               // next.
+                               // If there are children, write them next.
   if (nChildren > 0 || node->isAlias()) {
     doIndent(output, indent);
     output << '<' << name;
     writeAtts(output, node);
     output << '>' << endl;
     for (int i = 0; i < nChildren; i++)
-      writeNode(output, node->getChild(i), indent + INDENT_STEP);
+      writeNode(output, node->getChild(i), write_all, indent + INDENT_STEP);
     doIndent(output, indent);
     output << "</" << name << '>' << endl;
   }
@@ -444,15 +475,9 @@ writeNode (ostream &output, const SGPropertyNode * node, int indent)
 }
 
 
-/**
- * Write a property tree to an output stream in XML format.
- *
- * @param output The output stream.
- * @param start_node The root node to write.
- * @return true if the write succeeded, false otherwise.
- */
-bool
-writeProperties (ostream &output, const SGPropertyNode * start_node)
+void
+writeProperties (ostream &output, const SGPropertyNode * start_node,
+                bool write_all)
 {
   int nChildren = start_node->nChildren();
 
@@ -460,32 +485,22 @@ writeProperties (ostream &output, const SGPropertyNode * start_node)
   output << "<PropertyList>" << endl;
 
   for (int i = 0; i < nChildren; i++) {
-    writeNode(output, start_node->getChild(i), INDENT_STEP);
+    writeNode(output, start_node->getChild(i), write_all, INDENT_STEP);
   }
 
   output << "</PropertyList>" << endl;
-
-  return true;
 }
 
 
-/**
- * Write a property tree to a file in XML format.
- *
- * @param file The destination file.
- * @param start_node The root node to write.
- * @return true if the write succeeded, false otherwise.
- */
-bool
-writeProperties (const string &file, const SGPropertyNode * start_node)
+void
+writeProperties (const string &file, const SGPropertyNode * start_node,
+                bool write_all)
 {
   ofstream output(file.c_str());
   if (output.good()) {
-    return writeProperties(output, start_node);
+    writeProperties(output, start_node, write_all);
   } else {
-    SG_LOG(SG_INPUT, SG_ALERT, "Cannot write properties to file "
-          << file);
-    return false;
+    throw sg_io_exception("Cannot open file", sg_location(file));
   }
 }
 
@@ -542,7 +557,9 @@ copyProperties (const SGPropertyNode *in, SGPropertyNode *out)
        retval = false;
       break;
     default:
-      throw string("Unrecognized SGPropertyNode type");
+      string message = "Unknown internal SGPropertyNode type";
+      message += in->getType();
+      throw sg_error(message, "SimGear Property Reader");
     }
   }