OpenADFortTk (basic)
src/lib/support/xmlostream.h
Go to the documentation of this file.
00001 // ##########################################################
00002 // # This file is part of OpenADFortTk.                     #
00003 // # The full COPYRIGHT notice can be found in the top      #
00004 // # level directory of the OpenADFortTk source tree.       #
00005 // # For more information visit                             #
00006 // # http://www.mcs.anl.gov/openad                          #
00007 // ##########################################################
00008 
00009 #ifndef xmlostream_INCLUDED_h
00010 #define xmlostream_INCLUDED_h
00011 
00012 #include <iostream>
00013 #include <string>
00014 #include <list> // STL
00015 
00016 // FIXME: add xml escaping routines
00017 
00018 // ---------------------------------------------------------
00019 // xml::ostream:
00020 // 
00021 // FIXME: we do not require that this be a full xml document (no state
00022 // for dtd, etc.) since one should be able to create subdocuments that
00023 // can be appended to larger ones.
00024 // ---------------------------------------------------------
00025 namespace xml {
00026 
00027 class ostream : public std::ostream {
00028  public:
00029   ostream(std::streambuf* sb);
00030   virtual ~ostream();
00031 
00032   // ---------------------------------------------------------
00033 
00034   class Exception {
00035   public:
00036     Exception (const char* msg_) { msg = msg_; }
00037     virtual ~Exception () { }
00038 
00039     virtual const std::string& GetMessage() const { return msg; }
00040     virtual void Report(std::ostream& os) const { 
00041       os << "xml::ostream::Exception: " << msg << std::endl; 
00042     }    
00043     virtual void Report() const { Report(std::cerr); }
00044 
00045   private: 
00046     std::string msg;
00047   };
00048 
00049   // ---------------------------------------------------------
00050   
00051   // BegElem: Output an incomplete start tag [<tag...] for the
00052   // element 'etag' automatically closing any previous incomplete
00053   // start tags.  The start tag is incomplete so that an arbitrary
00054   // number of attributes can be added.  Indentation is incremented,
00055   // if necessary.
00056   void BegElem(const char* etag)
00057     throw (Exception);
00058 
00059   // EndElem: Output the current element's end tag, using either the
00060   // 'compact' form [<.../>] or the 'normal' form [</tag>], whichever
00061   // is appropriate.  Indentation is decremented, if necessary.
00062   void EndElem();
00063 
00064 
00065   // Attr: Output the attribute 'attr' with the value 'val'
00066   // [attr="val"] for the element's start tag, leaving the stream
00067   // ready to accept another attribute (i.e. the element's start tag
00068   // is still incomplete).  (FIXME: check for invalid character?)
00069   template <class T>
00070     void Attr(const char* attr, const T& val);
00071 
00072   // BegAttr and EndAttr together are equivalent to Attr.  These
00073   // functions are useful, e.g., when the attribute value needs to be
00074   // concatenated together from several sub-values.
00075   
00076   // BegAttr: Prepare the stream for the attribute value,
00077   // automatically closing any previous incomplete attributes.
00078   void BegAttr(const char* attr);
00079 
00080   // EndAttr: End this attribute and prepare the stream for the end of
00081   // the attribute list or another attribute.
00082   void EndAttr();
00083   
00084 
00085   // EndAttrs: Manually complete the attribute list and end the
00086   // current element's start tag (ending any open attribute).  This is
00087   // useful, e.g., if comments or newlines need to be inserted.
00088   void EndAttrs();
00089 
00090   // ---------------------------------------------------------
00091   
00092   // BegComment/EndComment: Ouput an arbitrary comment, automatically
00093   // closing any previous incomplete start tag or attribute.  Comments
00094   // cannot be nested. No indentation. EndComment() ends the current
00095   // line.
00096   void BegComment();
00097   void EndComment();
00098 
00099   // Comment: Output an indented, one-line comment (including
00100   // newline).  A previous incomplete start tag is closed.
00101   void Comment(const char* str);
00102 
00103   // ---------------------------------------------------------
00104 
00105   // Indentation: Both IndentAmnt (whitespace between the left margin
00106   // and the text) and the IndentStep (amount the indentation changes
00107   // for the next level) can be set independently.  It is
00108   // possible to have a negative step, but a negative amount is
00109   // ignored.
00110   void Indent();
00111   void IndentIncr() { indentAmnt += indentStep; }
00112   void IndentDecr() { indentAmnt -= indentStep; }
00113   bool IsIndent() { return (indentStep == 0 && indentAmnt == 0); }
00114 
00115   void SetIndentAmnt(int amnt) { indentAmnt = amnt; }
00116   void SetIndentStep(int step) { indentStep = step; }
00117   int GetIndentAmnt() { return indentAmnt; }
00118   int GetIndentStep() { return indentStep; }
00119   
00120   // FIXME Add a setIndent(xml::ostream) to coordinate indentation settings
00121 
00122  protected:
00123 
00124  private:
00125   // Disable
00126   ostream(const ostream& x);
00127   ostream& operator=(const ostream& x) { return *this; }
00128 
00129   void EndElemUpdateState();
00130 
00131  private: 
00132   // Stack of elements.  (Use a list instead a stack so that we can
00133   // easily examine contents.  The top of the stack will be the
00134   // *front* of the list. (push_front, pop_front).
00135   typedef std::list<std::string>           ElemStack;
00136   typedef std::list<std::string>::iterator ElemStackIt;
00137   typedef std::list<std::string>::const_iterator ElemStackItC;
00138 
00139   enum State {
00140     // A list of mutually exclusive states 
00141     INIT       = 0x00000001, // initial state, nothing has happened
00142     FINI       = 0x00000002, // a complete, top-level element has been finished
00143 
00144     ELEM_OPENI = 0x00000004, // within element, incomplete start tag
00145                              //   no incomplete attrs
00146     ELEM_OPENA = 0x00000008, // within element, incomplete start tag
00147                              //   incomplete attr
00148     ELEM_OPEN  = 0x00000010, // within element, complete start tag
00149 
00150     STMASK     = 0xff000000, // reserves 8 bits for state qualifiers
00151 
00152     // A list of state qualifiers (can co-exist with some/all of the above)
00153     ERR        = 0x10000000, // error
00154     COMMENT    = 0x20000000  // within a comment
00155   };
00156 
00157   // Access to mutually exclusive states (do not use with state qualifiers!)
00158   bool IsState(State st) { return (st & state); }
00159   void SetState(State st) { state = ((state & STMASK) | st); }
00160 
00161   // Access to state qualifiers
00162   bool IsStateError() { return (state & ERR); }
00163   void SetStateError() { state = (state | ERR); }
00164 
00165   bool IsStateComment() { return (state & COMMENT); }
00166   void SetStateComment() { state = (state | COMMENT); }
00167   void ResetStateComment() { state = (state & ~COMMENT); }
00168   
00169  private:
00170   ElemStack elemstack;
00171   unsigned int state;
00172   
00173   int indentAmnt;
00174   int indentStep;
00175 };
00176 
00177 }; /* namespace xml */
00178 
00179 
00180 //***************************************************************************
00181 // Definitions for xml::ostream member template functions
00182 //***************************************************************************
00183 
00184 template<class T> 
00185 void
00186 xml::ostream::Attr(const char* attr, const T& val)
00187 {
00188   // Sanity check -- rely on BegAttr()
00189 
00190   BegAttr(attr);
00191   (*this) << val;
00192   EndAttr();
00193 }
00194 
00195 //***************************************************************************
00196 // xml::ostream operators that take no arguments
00197 //***************************************************************************
00198 
00199 namespace xml {
00200 
00201 typedef ostream& (*omanip)(ostream&);
00202 
00203 inline ostream& 
00204 operator<<(std::ostream& os, omanip f)
00205 { 
00206   ostream& xos = dynamic_cast<ostream&>(os);
00207   return f(xos);
00208 }
00209 
00210 
00211 inline ostream& 
00212 EndElem(ostream& xos)
00213 { 
00214   xos.EndElem();
00215   return xos;
00216 }
00217 
00218 inline ostream& 
00219 EndAttr(ostream& xos)
00220 { 
00221   xos.EndAttr();
00222   return xos;
00223 }
00224 
00225 inline ostream& 
00226 EndAttrs(ostream& xos)
00227 { 
00228   xos.EndAttrs();
00229   return xos;
00230 }
00231 
00232 
00233 inline ostream& 
00234 BegComment(ostream& xos)
00235 { 
00236   xos.BegComment();
00237   return xos;
00238 }
00239 
00240 inline ostream& 
00241 EndComment(ostream& xos)
00242 { 
00243   xos.EndComment();
00244   return xos;
00245 }
00246 
00247 
00248 inline ostream& 
00249 Indent(ostream& xos)
00250 { 
00251   xos.Indent();
00252   return xos;
00253 }
00254 
00255 inline ostream& 
00256 IndentIncr(ostream& xos)
00257 { 
00258   xos.IndentIncr();
00259   return xos;
00260 }
00261 
00262 inline ostream& 
00263 IndentDecr(ostream& xos)
00264 { 
00265   xos.IndentDecr();
00266   return xos;
00267 }
00268 
00269 }; /* namespace xml */
00270 
00271 
00272 //***************************************************************************
00273 // xml::ostream operators that take arguments
00274 //***************************************************************************
00275 
00276 namespace xml {
00277 
00278 // ---------------------------------------------------------
00279 // BegElem
00280 // ---------------------------------------------------------
00281 struct BegElemInfo_ {
00282   const char* etag;
00283 };
00284 
00285 inline ostream&
00286 operator<<(std::ostream& os, const BegElemInfo_ x) // ok to pass x directly
00287 {
00288   ostream& xos = dynamic_cast<ostream&>(os); // FIXME
00289   xos.BegElem(x.etag);
00290   return xos;
00291 }
00292 
00293 inline BegElemInfo_ 
00294 BegElem(const char* etag_)
00295 {
00296   BegElemInfo_ x;
00297   x.etag = etag_;
00298   return x;
00299 }
00300 
00301 // ---------------------------------------------------------
00302 // Attr
00303 // ---------------------------------------------------------
00304 template<class T> 
00305 struct AttrInfo_ {
00306   const char* attr;
00307   const T* val;
00308 };
00309 
00310 template<class T> 
00311 ostream& 
00312 operator<<(std::ostream& os, const AttrInfo_<T>& x)
00313 {
00314   ostream& xos = dynamic_cast<ostream&>(os);
00315   xos.Attr(x.attr, *x.val);
00316   return xos;
00317 }
00318 
00319 template<class T> 
00320 AttrInfo_<T>
00321 Attr(const char* attr_, const T& val_)
00322 {
00323   AttrInfo_<T> x;
00324   x.attr = attr_;
00325   x.val = &val_;
00326   return x;
00327 }
00328 
00329 // ---------------------------------------------------------
00330 // BegAttr
00331 // ---------------------------------------------------------
00332 struct BegAttrInfo_ {
00333   const char* attr;
00334 };
00335 
00336 inline ostream&
00337 operator<<(std::ostream& os, const BegAttrInfo_ x) // ok to pass x directly
00338 {
00339   ostream& xos = dynamic_cast<ostream&>(os); // FIXME
00340   xos.BegAttr(x.attr);
00341   return xos;
00342 }
00343 
00344 inline BegAttrInfo_ 
00345 BegAttr(const char* attr_)
00346 {
00347   BegAttrInfo_ x;
00348   x.attr = attr_;
00349   return x;
00350 }
00351 
00352 // ---------------------------------------------------------
00353 // Comment
00354 // ---------------------------------------------------------
00355 struct CommentInfo_ {
00356   const char* str;
00357 };
00358 
00359 inline ostream&
00360 operator<<(std::ostream& os, const CommentInfo_ x) // ok to pass x directly
00361 {
00362   ostream& xos = dynamic_cast<ostream&>(os);
00363   xos.Comment(x.str);
00364   return xos;
00365 }
00366 
00367 inline CommentInfo_ 
00368 Comment(const char* str_)
00369 {
00370   CommentInfo_ x;
00371   x.str = str_;
00372   return x;
00373 }
00374 
00375 // ---------------------------------------------------------
00376 // SetIndentAmnt
00377 // ---------------------------------------------------------
00378 struct IndentAmntInfo_ {
00379   int amnt;
00380 };
00381 
00382 inline ostream& 
00383 operator<<(std::ostream& os, const IndentAmntInfo_ x) // ok to pass x directly
00384 {
00385   ostream& xos = dynamic_cast<ostream&>(os);
00386   xos.SetIndentAmnt(x.amnt);
00387   return xos;
00388 }
00389 
00390 inline IndentAmntInfo_ 
00391 SetIndentAmnt(int amnt_)
00392 {
00393   IndentAmntInfo_ x;
00394   x.amnt = amnt_;
00395   return x;
00396 }
00397 
00398 // ---------------------------------------------------------
00399 // SetIndentStep
00400 // ---------------------------------------------------------
00401 struct IndentStepInfo_ {
00402   int step;
00403 };
00404 
00405 inline ostream& 
00406 operator<<(std::ostream& os, const IndentStepInfo_ x) // ok to pass x directly
00407 {
00408   ostream& xos = dynamic_cast<ostream&>(os);
00409   xos.SetIndentStep(x.step);
00410   return xos;
00411 }
00412 
00413 inline IndentStepInfo_ 
00414 SetIndentStep(int step_)
00415 {
00416   IndentStepInfo_ x;
00417   x.step = step_;
00418   return x;
00419 }
00420 
00421 }; /* namespace xml */
00422 
00423 // FIXME:
00424 inline void Append_Token_String(xml::ostream& xos, const char *string)
00425 {
00426   xos << string << " ";
00427 }
00428 
00429 #endif /* xmlostream_INLUCDED_h */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines