|
OpenADFortTk (basic)
|
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 */