cfl_tokenwriter.cpp
Go to the documentation of this file.
1 /** @file cfl_tokenwriter.cpp @brief Class TokenWriter */
2 
3 /* FAU Discrete Event Systems Library (libfaudes)
4 
5 Copyright (C) 2006 Bernd Opitz
6 Copyright (C) 2006, 2010, 2024 Thomas Moor
7 Exclusive copyright is granted to Klaus Schmidt
8 
9 This library is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Lesser General Public
11 License as published by the Free Software Foundation; either
12 version 2.1 of the License, or (at your option) any later version.
13 
14 This library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
18 
19 You should have received a copy of the GNU Lesser General Public
20 License along with this library; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22 
23 
24 #include "cfl_tokenwriter.h"
25 
26 namespace faudes {
27 
28 // TokenWriter(rFilename, openmode)
29 TokenWriter::TokenWriter(const std::string& rFilename, std::ios::openmode openmode)
30  : mMode(File), pSStream(0), mHasOutBuffer(false), mFileName(rFilename), mColumns(80/FD_NAMELEN), mColCount(0) {
31  // set up mFStream
32  mFStream.exceptions(std::ios::badbit|std::ios::failbit);
33  try{
34  mFStream.open(rFilename.c_str(), openmode);
35  }
36  catch (std::ios::failure&) {
37  std::stringstream errstr;
38  errstr << "Exception opening/writing file \""<< rFilename << "\"";
39  throw Exception("TokenWriter::TokenWriter", errstr.str(), 2);
40  }
41  // use mFStream
43  mEndl=true;
44 }
45 
46 // TokenWriter(rFilename, doctype)
47 TokenWriter::TokenWriter(const std::string& rFilename, const std::string& ftype)
48  : mMode(XmlFile), pSStream(0), mHasOutBuffer(false), mFileName(rFilename), mColumns(80/FD_NAMELEN), mColCount(0) {
49  // set up mFStream
50  mFStream.exceptions(std::ios::badbit|std::ios::failbit);
51  try{
52  mFStream.open(rFilename.c_str(), std::ios::out|std::ios::trunc);
53  mFStream << "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" standalone=\"no\"?>" << std::endl;
54  if(ftype!="")
55  if(ftype!="Void") {
56  std::string dtdfile=ftype;
57  std::transform(dtdfile.begin(), dtdfile.end(), dtdfile.begin(), tolower);
58  dtdfile="http://www.faudes.org/dtd/1.0/"+dtdfile+".dtd";
59  mFStream << "<!DOCTYPE " << ftype << " SYSTEM \"" << dtdfile << "\">" << std::endl;
60  }
61  }
62  catch (std::ios::failure&) {
63  std::stringstream errstr;
64  errstr << "Exception opening/writing xml file \""<< rFilename << "\"";
65  throw Exception("TokenWriter::TokenWriter", errstr.str(), 2);
66  }
67  // use mFStream
69  mEndl=true;
70 }
71 
72 // TokenWriter(mode)
74  : mMode(mode), pSStream(0), mHasOutBuffer(false), mFileName(""), mColumns(80/FD_NAMELEN), mColCount(0) {
75  switch(mode) {
76  case Stdout:
77  // set up mFStream
78  /*
79  try {
80  mFStream.copyfmt(std::cout);
81  mFStream.clear(std::cout.rdstate());
82  typedef std::basic_ios<char> ___basic_ios_char_; // trick for vc++
83  mFStream.___basic_ios_char_::rdbuf(std::cout.rdbuf());
84  }
85  catch (std::ios::failure&) {
86  std::stringstream errstr;
87  errstr << "Exception opening/writing file \""<< mFileName << "\"";
88  throw Exception("TokenWriter::TokenWriter", errstr.str(), 2);
89  }
90  // use mFStream
91  mpStream=&mFStream;
92  */
93  // use std::cout
94  /*
95  mpStream= &std::cout;
96  mEndl=true;
97  */
98  // use mSStream to buffer and write to faudes ConsoleOut
99  mFileName="stdout";
101  mEndl=true;
102  break;
103  case String:
104  // use mSStream
105  mFileName="string";
107  mEndl=false;
108  break;
109  default:
110  std::stringstream errstr;
111  errstr << "Invalid Mode / Not Implemented";
112  throw Exception("TokenWriter::TokenWriter", errstr.str(), 2);
113  }
114 }
115 
116 
117 // TokenWriter(stream)
118 TokenWriter::TokenWriter(std::ostream& stream, const std::string& ftype)
119  : mMode(Stream), pSStream(&stream), mHasOutBuffer(false), mFileName("stream"), mColumns(0), mColCount(0) {
120  // xml if there is a doctype
121  try {
122  if(ftype!="")
123  if(ftype!="Void") {
124  std::string dtdfile=ftype;
125  std::transform(dtdfile.begin(), dtdfile.end(), dtdfile.begin(), tolower);
126  dtdfile="http://www.faudes.org/dtd/1.0/"+dtdfile+".dtd";
127  *pSStream << "<!DOCTYPE " << ftype << " SYSTEM \"" << dtdfile << "\">" << std::endl;
129  }
130  } catch (std::ios::failure&) {
131  std::stringstream errstr;
132  errstr << "Exception opening/writing xml stream";
133  throw Exception("TokenWriter::TokenWriter", errstr.str(), 2);
134  }
135  // use provided stream
137  mEndl=true;
138 }
139 
140 // destructor
142  Flush();
143  if(mMode==File) mFStream.close();
144 }
145 
146 // Flush buffers
147 void TokenWriter::Flush(void) {
148  DoFlush(); // incl linefeed if col>0
149  mpStream->flush();
150  if(mMode==Stdout) {
151  bool m=ConsoleOut::G()->Mute();
152  ConsoleOut::G()->Mute(false);
153  ConsoleOut::G()->Write(mSStream.str());
154  ConsoleOut::G()->Mute(m);
155  mSStream.str("");
156  }
157 }
158 
159 // Str()
160 std::string TokenWriter::Str(void) {
161  if(mMode!=String) {
162  std::stringstream errstr;
163  errstr << "Not in String Mode";
164  throw Exception("TokenWriter::Str()", errstr.str(), 2);
165  }
166  Flush();
167  return mSStream.str();
168 }
169 
170 // Stream()
171 std::ostream* TokenWriter::Streamp(void) {
172  DoFlush(0); // no extra formating
173  return mpStream;
174 }
175 
176 
177 
178 // Columns()
179 int TokenWriter::Columns(void) const {
180  return mColumns;
181 }
182 
183 // Columns()
184 void TokenWriter::Columns(int columns) {
185  mColumns = columns;
186 }
187 
188 // Endl()
189 void TokenWriter::Endl(void) {
190  DoFlush(1);
191  try{
192  if(mEndl) *mpStream << std::endl;
193  else *mpStream << " ";
194  }
195  catch (std::ios::failure&) {
196  std::stringstream errstr;
197  errstr << "Exception opening/writing file \"" << mFileName << "\"";
198  throw Exception("Generator::write", errstr.str(), 2);
199  }
200 }
201 
202 // Endl(bool)
203 void TokenWriter::Endl(bool on) {
204  mEndl=on;
205 }
206 
207 // DoFlush: write buffered token
208 // Note: dont call Endl() since this calls DoFlush
209 void TokenWriter::DoFlush(bool clf) {
210  if(!mHasOutBuffer) return;
211  FD_DV("TokenWriter::DoFlush()");
212  try{
213  // write preceeding space
214  for(size_t i=0; i< mOutBuffer.mPreceedingSpace.size(); ++i) {
215  char c= mOutBuffer.mPreceedingSpace.at(i);
216  if(c=='\n') {
217  if(mEndl) *mpStream << std::endl;
218  else *mpStream << " ";
219  mColCount=0; ;
220  continue;
221  }
222  if(c=='\r') continue;
223  if(isspace(c)) mpStream->put(c);
224  }
225  // do the write
227  // count my columns
228  mColCount++;
229  // have closing linefeed for true flush
230  if(clf) {
231  if(mOutBuffer.IsBegin() || mOutBuffer.IsEnd())
232  if(mColCount==1)
233  if(mEndl) { *mpStream << std::endl; mColCount=0;}
235  }
236  }
237  catch (std::ios::failure&) {
238  std::stringstream errstr;
239  errstr << "Exception opening/writing file \"" << mFileName << "\"";
240  throw Exception("TokenWriter::Write(token)", errstr.str(), 2);
241  }
242  mHasOutBuffer=false;
243 }
244 
245 // Write(rToken)
246 void TokenWriter::Write(Token& rToken) {
247  FD_DV("TokenWriter::Write(token)");
248  // figure wether we can merge to an empty section:
249  // 1. buffer begin must match the current token end tag
250  if(rToken.IsEnd() && !rToken.IsBegin())
251  if(mHasOutBuffer)
252  if(mOutBuffer.IsBegin() && !mOutBuffer.IsEnd())
253  if(mOutBuffer.StringValue()==rToken.StringValue())
254  // 2. dont do it on HTML tags since it irritates bowsers
255  if(mOutBuffer.StringValue()!="b")
256  if(mOutBuffer.StringValue()!="i")
257  if(mOutBuffer.StringValue()!="tt")
258  if(mOutBuffer.StringValue()!="p")
259  if(mOutBuffer.StringValue()!="h1")
260  if(mOutBuffer.StringValue()!="h2")
261  if(mOutBuffer.StringValue()!="h3")
262  if(mOutBuffer.StringValue()!="h4")
263  if(mOutBuffer.StringValue()!="font")
264  if(mOutBuffer.StringValue()!="strong")
265  {
267  DoFlush(0);
268  return;
269  }
270  // flush buffer
271  if(mHasOutBuffer) DoFlush(0);
272  // prefer markup in new line before
273  if(rToken.PreceedingSpace()=="")
274  if(rToken.IsBegin() || rToken.IsEnd())
275  if(mColCount > 0)
276  rToken.PreceedingSpace("\n");
277  // prefer markup in new line after
278  if(rToken.PreceedingSpace()=="")
279  if(mOutBuffer.IsBegin() || mOutBuffer.IsEnd())
280  if(mColCount == 1)
281  rToken.PreceedingSpace("\n");
282  // columncount proposes linefeed
283  if(rToken.PreceedingSpace()=="")
284  if(mColCount >= mColumns && (mColumns>0) && mEndl) {
285  rToken.mPreceedingSpace="\n";
286  }
287  // insist in space between data tokens
288  if(rToken.PreceedingSpace()=="")
289  if(!(rToken.IsBegin()) && (!rToken.IsEnd()))
290  if(!(mOutBuffer.IsBegin()) && (!mOutBuffer.IsEnd())) {
291  rToken.mPreceedingSpace=" ";
292  }
293  // record token to buffer
294  mOutBuffer=rToken;
295  mHasOutBuffer=true;
296 }
297 
298 
299 // WriteString(rName)
300 void TokenWriter::WriteString(const std::string& rName) {
301  if((rName == "\n") || (rName == "\r\n")) {
302  Endl();
303  mColCount = 0;
304  return;
305  }
306  Token token;
307  token.SetString(rName);
308  Write(token);
309 }
310 
311 
312 // WriteText(rText) --- depreciated, use below variants
313 void TokenWriter::WriteText(const std::string& rText) {
314  try {
315  DoFlush();
317  }
318  catch (std::ios::failure&) {
319  std::stringstream errstr;
320  errstr << "Exception opening/writing file \"" << mFileName << "\"";
321  throw Exception("TokenWriter::WriteText(text)", errstr.str(), 2);
322  }
323 }
324 
325 // WriteText(rBegin,rText)
326 void TokenWriter::WriteText(Token& rBeginTag, const std::string& rText) {
327  if(!rBeginTag.IsBegin() || rBeginTag.IsEnd()) {
328  std::stringstream errstr;
329  errstr << "Invalid begin token while writing file \"" << mFileName << "\"";
330  throw Exception("TokenWriter::WriteText(label,text)", errstr.str(), 2);
331  }
332  try {
333  Write(rBeginTag);
334  Flush();
336  Endl();
337  WriteEnd(rBeginTag.StringValue());
338  }
339  catch (std::ios::failure&) {
340  std::stringstream errstr;
341  errstr << "Exception writing file \"" << mFileName << "\"";
342  throw Exception("TokenWriter::WriteText(label,text)", errstr.str(), 2);
343  }
344 }
345 
346 
347 // WriteText(rLabel,rText) -- wrapper
348 void TokenWriter::WriteText(const std::string& rLabel, const std::string& rText) {
349  Token btag;
350  btag.SetBegin(rLabel);
351  WriteText(btag,rText);
352 }
353 
354 
355 // WriteVerbatim(rData)
356 void TokenWriter::WriteVerbatim(Token& rBeginTag, const std::string& rText) {
357  FD_DV("TokenWriter::Write(token)");
358  if(!rBeginTag.IsBegin() || rBeginTag.IsEnd()) {
359  std::stringstream errstr;
360  errstr << "Invalid begin token while writing file \"" << mFileName << "\"";
361  throw Exception("TokenWriter::WriteVerbatim(tag,text)", errstr.str(), 2);
362  }
363  Write(rBeginTag);
364  Flush();
365  try{
366  if(mColCount !=0) Endl();
367  Token::WriteVerbatim(mpStream,rText,1); // flag: add linefeeds
368  mColCount = 0;
369  Endl();
370  }
371  catch (std::ios::failure&) {
372  std::stringstream errstr;
373  errstr << "Exception opening/writing file \"" << mFileName << "\"";
374  throw Exception("TokenWriter::WriteVerbatim()", errstr.str(), 2);
375  }
376  WriteEnd(rBeginTag.StringValue());
377 }
378 
379 // WriteVerbatim(rLabel,rText) -- wrapper
380 void TokenWriter::WriteVerbatim(const std::string& rLabel, const std::string& rText) {
381  Token btag;
382  btag.SetBegin(rLabel);
383  WriteVerbatim(btag,rText);
384 }
385 
386 
387 // WriteCharacterData(rCData)
388 void TokenWriter::WriteCharacterData(const std::string& rCharacterData) {
389  // bail out on trivial to avoid unnecessary flush
390  if(rCharacterData.size()==0) return;
391  // do write
392  try {
393  DoFlush(0); // no extra linefeed formating here
394  *mpStream << rCharacterData;
395  }
396  catch (std::ios::failure&) {
397  std::stringstream errstr;
398  errstr << "Exception opening/writing file \"" << mFileName << "\"";
399  throw Exception("TokenWriter::WriteCharacterData(text)", errstr.str(), 2);
400  }
401  // adjust column count
403  if(rCharacterData.size()>=1)
404  if(rCharacterData.at(rCharacterData.size()-1)=='\n')
405  mColCount=0;
406 }
407 
408 // WriteInteger(index)
410  Token token;
411  token.SetInteger(index);
412  Write(token);
413 }
414 
415 // WriteInteger(index)
416 void TokenWriter::WriteInteger16(long int val) {
417  Token token;
418  token.SetInteger16(val);
419  Write(token);
420 }
421 
422 // WriteFloat(float)
423 void TokenWriter::WriteFloat(const double& val) {
424  Token token;
425  token.SetFloat(val);
426  Write(token);
427 }
428 
429 
430 // WriteOption(rOpt)
431 void TokenWriter::WriteOption(const std::string& rOpt) {
432  Token token;
433  token.SetOption(rOpt);
434  Write(token);
435 }
436 
437 
438 // WriteBegin(rLabel)
439 void TokenWriter::WriteBegin(const std::string& rLabel) {
440  Token token;
441  token.SetBegin(rLabel);
442  Write(token);
443 }
444 
445 // WriteEnd(rLabel)
446 void TokenWriter::WriteEnd(const std::string& rLabel) {
447  Token token;
448  token.SetEnd(rLabel);
449  Write(token);
450 }
451 
452 // WriteBegin(rLabel)
453 void TokenWriter::WriteEmpty(const std::string& rLabel) {
454  Token token;
455  token.SetEmpty(rLabel);
456  Write(token);
457 }
458 
459 // WriteComment(comment)
460 void TokenWriter::WriteComment(const std::string& comment){
461  DoFlush();
462  // auto xml
463  if(mMode==XmlFile || mMode==XmlStream) { WriteXmlComment(comment); return; }
464  // no endl ... no comment
465  if(!mEndl) return;
466  try{
467  if(mColCount!=0) Endl();
468  // fix comment indicator
469  if(comment.length()==0)
470  *mpStream << "% ";
471  if(comment.length()>0)
472  if(comment.at(0)!='%')
473  *mpStream << "% ";
474  // xml/endl escape
475  std::string::const_iterator cit=comment.begin();
476  for(;cit!=comment.end(); cit++) {
477  if(*cit=='<')
478  { *mpStream << "&lt;"; continue;}
479  if(*cit=='>')
480  { *mpStream << "&gt;"; continue;}
481  if(*cit=='&')
482  { *mpStream << "&amp;"; continue;}
483  if(*cit=='\n')
484  { *mpStream << " "; continue;}
485  if(*cit=='\r')
486  { ; continue;}
487  *mpStream << *cit;
488  }
489  // done
490  Endl();
491  mColCount = 0;
492  }
493  catch (std::ios::failure&) {
494  std::stringstream errstr;
495  errstr << "Exception opening/writing file \"" << mFileName << "\"";
496  throw Exception("TokenWriter::Comment", errstr.str(), 2);
497  }
498 }
499 
500 // WriteXmlComment(comment)
501 void TokenWriter::WriteXmlComment(const std::string& comment){
502  if(!mEndl) return; // no endl implies no comments
503  DoFlush();
504  try{
505  if(mColCount!=0) Endl();
506  // begin tag
507  *mpStream << "<!-- ";
508  // test for multiline
509  static const std::string newline="\n\r";
510  if(comment.find_first_of(newline)!=std::string::npos)
511  Endl();
512  // xml/endl escape
513  std::string::const_iterator cit=comment.begin();
514  for(;cit!=comment.end(); cit++) {
515  if(*cit=='>')
516  { *mpStream << "&gt;"; continue;}
517  *mpStream << *cit;
518  }
519  // end tag
520  *mpStream << " -->";
521  // done
522  Endl();
523  mColCount = 0;
524  }
525  catch (std::ios::failure&) {
526  std::stringstream errstr;
527  errstr << "Exception opening/writing file \"" << mFileName << "\"";
528  throw Exception("TokenWriter::Comment", errstr.str(), 2);
529  }
530 }
531 
532 // write base64
533 void TokenWriter::WriteBinary(const char* pData, long int len) {
534  DoFlush();
535  Token::WriteBinary(mpStream,pData,len);
536 }
537 
538 // FileName()
539 std::string TokenWriter::FileName(void) const {
540  return mFileName;
541 }
542 
543 
544 
545 
546 } // namespace faudes
#define FD_NAMELEN
Length of strings for text fields in token output.
#define FD_DV(message)
Debug: optional low-level report on iterations and token IO.
Class TokenWriter.
static ConsoleOut * G(void)
Acess static instance.
Definition: cfl_utils.cpp:415
virtual void Write(const std::string &message, long int cntnow=0, long int cntdone=0, int verb=0)
Write a std::string message (optional progress report and verbosity)
Definition: cfl_utils.cpp:434
void Mute(bool on)
Mute.
Definition: cfl_utils.h:332
Faudes exception class.
Elementary type.
void WriteInteger16(long int val)
Write integer as hex.
std::ostringstream mSStream
Actual stream object, string output.
std::string FileName(void) const
Get the filename.
std::string Str(void)
Retrieve output as string (if in String mode)
void WriteFloat(const double &val)
Write float.
bool mEndl
Endl seperator on/off.
void WriteXmlComment(const std::string &rComment)
Write comment in Xml format.
std::ostream * mpStream
ostream object pointer
Mode mMode
Output mode.
~TokenWriter(void)
Destructor.
std::string mFileName
Filename.
Token mOutBuffer
Outputbuffer.
void WriteText(const std::string &rText)
Write text.
Mode
Mode of operation: write to file, string or stdout.
void WriteEmpty(const std::string &rLabel)
Write empty section label.
int mColCount
Column counter.
void WriteCharacterData(const std::string &rCharData)
Write character data.
int mColumns
Number of columns.
void WriteComment(const std::string &rComment)
Write comment in faudes format.
void Write(Token &rToken)
Write next token.
void Endl(void)
Write endl separator.
std::ostream * Streamp(void)
Access C++ stream.
void WriteString(const std::string &rString)
Write string.
std::ostream * pSStream
Actual stream object, stream output.
void WriteEnd(const std::string &rLabel)
Write end label.
void WriteBinary(const char *pData, long int len)
Write comment.
int Columns(void) const
Get number of columns in a line.
void Flush(void)
Flush any buffers.
void WriteVerbatim(Token &rBeginTag, const std::string &rText)
Write verbatim text section.
TokenWriter(Mode mode)
Console or String TokenWriter constructor.
std::ofstream mFStream
Actual stream object, file output.
void DoFlush(bool clf=1)
Flush internal buffer.
void WriteInteger(Idx index)
Write non negative integer.
void WriteBegin(const std::string &rLabel)
Write begin label.
void WriteOption(const std::string &rOpt)
Write option (may not contain any "+")
Tokens model atomic data for stream IO.
Definition: cfl_token.h:54
void SetNone(void)
Initialize None token.
Definition: cfl_token.cpp:73
const std::string & PreceedingSpace(void) const
Preceeding space when writing to stream.
Definition: cfl_token.cpp:189
void SetInteger16(const Int number)
Initialize as Integer16 token.
Definition: cfl_token.cpp:129
const std::string & StringValue(void) const
Get string value of a name token.
Definition: cfl_token.cpp:178
void SetInteger(const Int number)
Initialize as Integer token.
Definition: cfl_token.cpp:121
@ End
<\label> (end of section)
Definition: cfl_token.h:85
static void WriteVerbatim(std::ostream *pStream, const std::string &rString, bool lfflag=0)
Write a std::string value to an output stream.
Definition: cfl_token.cpp:417
void Write(std::ostream *pStream) const
Write Token to output stream.
Definition: cfl_token.cpp:750
void SetString(const std::string &rName)
Initialize as String token.
Definition: cfl_token.cpp:85
void SetOption(const std::string &rName)
Initialize as Option token.
Definition: cfl_token.cpp:113
bool IsBegin(void) const
Test token Type.
Definition: cfl_token.cpp:259
void SetFloat(const faudes::Float number)
Initialize as Float token.
Definition: cfl_token.cpp:145
void SetEmpty(const std::string &rName)
Initialize as empty-tag token.
Definition: cfl_token.cpp:106
static void WriteBinary(std::ostream *pStream, const char *pData, std::size_t len)
Write specified binary data as base64 string to output stream.
Definition: cfl_token.cpp:446
static int WriteEscapedString(std::ostream *pStream, const std::string &outstr)
Write a std::string value to an output stream.
Definition: cfl_token.cpp:813
int mType
Token type.
Definition: cfl_token.h:634
void SetBegin(const std::string &rName)
Initialize as Begin token.
Definition: cfl_token.cpp:92
bool IsEnd(void) const
Test token Type.
Definition: cfl_token.cpp:270
std::string mPreceedingSpace
Preceeding space (cosmetic)
Definition: cfl_token.h:649
void SetEnd(const std::string &rName)
Initialize as End token.
Definition: cfl_token.cpp:99
libFAUDES resides within the namespace faudes.
uint32_t Idx
Type definition for index type (allways 32bit)

libFAUDES 2.32f --- 2024.12.22 --- c++ api documentaion by doxygen