|
OpenADFortTk (basic)
|
00001 #include <cstring> // for strlen 00002 00003 //*************************** User Include Files **************************** 00004 00005 #include "sexpostream.h" 00006 00007 //*************************** Forward Declarations *************************** 00008 00009 //**************************************************************************** 00010 00011 /* 00012 A table showing possible state movements. The state-state table 00013 indicates whether it is possible to move from one state (in the left 00014 margin) to another state. Given an initial state (in the left 00015 margin), the state-action table indicates the possible resulting 00016 states after an action 00017 00018 States/Qalifiers Actions 00019 |-------------------------------------------------------------------- 00020 | LIST ATOM| Beg Beg End End Quot Beg End 00021 |INIT DEF OPEN ERR OPEN| Lst Atom Atom Lst Com Com 00022 |-------------------------------------------------------------------- 00023 INIT |no yes yes yes yes | LOPN DEF ERR ERR DEF +COM -COM 00024 DEF |no yes yes yes yes | LOPN DEF DEF ERR DEF +COM -COM 00025 LOPN |no yes yes yes yes | LOPN LOPN LOPN DEF LOPN +COM -COM 00026 | | LOPN 00027 ERR |no no no no no |+ERR +ERR +ERR +ERR +ERR +ERR +ERR 00028 AOPN |no yes yes yes no |+ERR +ERR -AOPN +ERR +ERR +ERR +ERR 00029 COM | |+ERR +ERR +ERR +ERR +ERR +ERR -COM 00030 00031 00032 */ 00033 00034 // For a comments to public member functions, see the interface file. 00035 00036 sexp::ostream::ostream(std::streambuf* sb) 00037 : std::ostream(sb) 00038 { 00039 curAtomFlags = IOFlags::NONE; 00040 state = 0; 00041 00042 SetState(INIT); 00043 indentAmnt = 0; 00044 indentStep = 2; 00045 } 00046 00047 00048 sexp::ostream::~ostream() 00049 { 00050 } 00051 00052 00053 // Atom: specialization for 'const char*' 00054 template <> 00055 void 00056 sexp::ostream::Atom(int xflags, const char* const & val) 00057 { 00058 using namespace IOFlags; 00059 00060 // Sanity check -- rely on BegAtom() 00061 BegAtom(xflags); 00062 const char* outstr = (val) ? val : ""; 00063 if (IsFlag(xflags, A_DQUOTE)) { 00064 EscapeString(outstr); 00065 } 00066 else { 00067 (*this) << outstr; 00068 } 00069 EndAtom(); 00070 } 00071 00072 00073 void 00074 sexp::ostream::BegAtom(int xflags) 00075 { 00076 using namespace IOFlags; 00077 00078 // Sanity check 00079 if (!IsStateQClear()) { 00080 SetStateError(); 00081 throw Exception("BegAtom: Cannot begin atom!"); 00082 } 00083 00084 // Get and check flags 00085 int flags = 0; 00086 if (slistStack.size() != 0) { 00087 int& f = slistStack.front(); 00088 flags = f; 00089 SetFlag(f, L_NONEMPTY); 00090 } 00091 00092 // (note that there can be two sets of atom flags) 00093 AddSpaceIfNecessary(flags); 00094 if (IsFlag(xflags, A_SQUOTE) || IsFlag(flags, A_SQUOTE)) { 00095 (*this) << "'"; 00096 } 00097 if (IsFlag(xflags, A_DQUOTE) || IsFlag(flags, A_DQUOTE)) { 00098 (*this) << '"'; 00099 } 00100 if (IsFlag(xflags, A_OCT) || IsFlag(flags, A_OCT)) { 00101 (*this) << std::oct << "0"; 00102 } 00103 if (IsFlag(xflags, A_HEX) || IsFlag(flags, A_HEX)) { 00104 (*this) << std::hex << "0x"; 00105 } 00106 00107 curAtomFlags = xflags; 00108 00109 // Set state and qualifier 00110 if (IsState(INIT)) { SetState(DEFAULT); } 00111 SetStateQ(ATOM_OPEN); 00112 SetAction(BEG_ATOM); 00113 } 00114 00115 00116 void 00117 sexp::ostream::EndAtom() 00118 { 00119 using namespace IOFlags; 00120 00121 // Sanity check 00122 if (!IsStateQ(ATOM_OPEN)) { 00123 SetStateError(); 00124 throw Exception("EndAtom: No currently open atom!"); 00125 } 00126 00127 // Get and check flags 00128 int flags = 0; 00129 if (slistStack.size() != 0) { 00130 flags = slistStack.front(); 00131 } 00132 00133 // (note that there can be two sets of atom flags) 00134 if (IsFlag(curAtomFlags, A_DQUOTE) || IsFlag(flags, A_DQUOTE)) { 00135 (*this) << '"'; 00136 } 00137 if (IsFlag(curAtomFlags, A_OCT) || IsFlag(flags, A_OCT) || 00138 IsFlag(curAtomFlags, A_HEX) || IsFlag(flags, A_HEX)) { 00139 (*this) << std::dec; 00140 } 00141 00142 curAtomFlags = IOFlags::NONE; 00143 ResetStateQ(ATOM_OPEN); // State remains the same, except for qualifier 00144 SetAction(END_ATOM); 00145 } 00146 00147 00148 void 00149 sexp::ostream::BegList(int xflags) 00150 throw (sexp::ostream::Exception) 00151 { 00152 using namespace IOFlags; 00153 00154 // Sanity check 00155 if (!IsStateQClear()) { 00156 SetStateError(); 00157 throw Exception("BegList: Cannot begin list!"); 00158 } 00159 00160 // Get and check flags 00161 int flags = 0; 00162 if (slistStack.size() != 0) { 00163 int& f = slistStack.front(); 00164 flags = f; 00165 SetFlag(f, L_NONEMPTY); 00166 } 00167 00168 // [FIXME: more checks] 00169 AddSpaceIfNecessary(flags); 00170 00171 (*this) << '('; 00172 IndentIncr(); 00173 00174 slistStack.push_front(xflags); 00175 SetState(LIST_OPEN); 00176 SetAction(BEG_LIST); 00177 } 00178 00179 00180 void 00181 sexp::ostream::EndList() 00182 { 00183 using namespace IOFlags; 00184 00185 // Sanity check 00186 if (!IsState(LIST_OPEN)) { 00187 SetStateError(); 00188 throw Exception("EndList: Cannot end list!"); 00189 } 00190 00191 int& flags = slistStack.front(); 00192 00193 IndentDecr(); 00194 (*this) << ")"; 00195 00196 // Check flags... 00197 00198 // Determine the appropriate state after an element has been closed 00199 slistStack.pop_front(); 00200 if (slistStack.size() == 0) { 00201 SetState(DEFAULT); 00202 } 00203 else { 00204 SetState(LIST_OPEN); 00205 } 00206 SetAction(END_LIST); 00207 } 00208 00209 00210 void 00211 sexp::ostream::Quote() 00212 { 00213 // Sanity check 00214 if (!IsStateQClear()) { 00215 SetStateError(); 00216 throw Exception("Quote: Cannot quote!"); 00217 } 00218 00219 // Get and check flags 00220 int flags = 0; 00221 if (slistStack.size() != 0) { 00222 flags = slistStack.front(); 00223 } 00224 00225 AddSpaceIfNecessary(flags); 00226 00227 (*this) << "'"; 00228 00229 // Set state and qualifier 00230 if (IsState(INIT)) { SetState(DEFAULT); } 00231 SetAction(QUOTE); 00232 } 00233 00234 00235 //**************************************************************************** 00236 00237 void 00238 sexp::ostream::BegComment() 00239 { 00240 // Sanity check 00241 if (IsStateQ(COMMENT)) { 00242 SetStateError(); 00243 throw Exception("BegComment: Already within a comment!"); 00244 } 00245 00246 (*this) << ";; "; 00247 00248 SetStateQ(COMMENT); 00249 SetAction(BEG_COMMENT); 00250 } 00251 00252 00253 void 00254 sexp::ostream::EndComment() 00255 { 00256 // Sanity check 00257 if (!IsStateQ(COMMENT)) { 00258 SetStateError(); 00259 throw Exception("EndComment: Not within a comment!"); 00260 } 00261 00262 SetAction(END_COMMENT); // N.B.: this should come before EndLine() 00263 EndLine(); 00264 ResetStateQ(COMMENT); 00265 } 00266 00267 00268 void 00269 sexp::ostream::Comment(const char* str) 00270 { 00271 // Sanity check -- rely on BegComment() 00272 00273 BegComment(); 00274 (*this) << str; 00275 EndComment(); 00276 } 00277 00278 00279 //**************************************************************************** 00280 00281 void 00282 sexp::ostream::EscapeString(const char* str) 00283 { 00284 for (int i = 0; i < strlen(str); ++i) { 00285 char c = str[i]; 00286 if (c == '\\' || c == '"') { // what about: \n 00287 (*this) << '\\'; 00288 } 00289 (*this) << c; 00290 } 00291 } 00292 00293 00294 //**************************************************************************** 00295 00296 void 00297 sexp::ostream::EndLine() 00298 { 00299 (*this) << "\n"; 00300 SetAction(END_LINE); // N.B.: this should come before Indent() 00301 Indent(); 00302 } 00303 00304 00305 void 00306 sexp::ostream::Indent() 00307 { 00308 for (int i = 0; i < indentAmnt; ++i) { 00309 (*this) << ' '; 00310 } 00311 SetAction(INDENT); 00312 } 00313 00314 //**************************************************************************** 00315 00316 void 00317 sexp::ostream::AddSpaceIfNecessary(int flags) 00318 { 00319 using namespace IOFlags; 00320 00321 // short-circuit if we just quoted, ended a line, or indented 00322 if (WasAction(QUOTE) || WasAction(END_LINE) || WasAction(INDENT)) { 00323 return; 00324 } 00325 00326 if (IsFlag(flags, L_NONEMPTY)) { 00327 (*this) << ' '; 00328 } 00329 }