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  ConsoleOut::G()->Write(mSStream.str(),0,0,0); // verb 0 <> always
152  mSStream.str("");
153  }
154 }
155 
156 // Str()
157 std::string TokenWriter::Str(void) {
158  if(mMode!=String) {
159  std::stringstream errstr;
160  errstr << "Not in String Mode";
161  throw Exception("TokenWriter::Str()", errstr.str(), 2);
162  }
163  Flush();
164  return mSStream.str();
165 }
166 
167 // Stream()
168 std::ostream* TokenWriter::Streamp(void) {
169  DoFlush(0); // no extra formating
170  return mpStream;
171 }
172 
173 
174 
175 // Columns()
176 int TokenWriter::Columns(void) const {
177  return mColumns;
178 }
179 
180 // Columns()
181 void TokenWriter::Columns(int columns) {
182  mColumns = columns;
183 }
184 
185 // Endl()
186 void TokenWriter::Endl(void) {
187  DoFlush(1);
188  try{
189  if(mEndl) *mpStream << std::endl;
190  else *mpStream << " ";
191  }
192  catch (std::ios::failure&) {
193  std::stringstream errstr;
194  errstr << "Exception opening/writing file \"" << mFileName << "\"";
195  throw Exception("Generator::write", errstr.str(), 2);
196  }
197 }
198 
199 // Endl(bool)
200 void TokenWriter::Endl(bool on) {
201  mEndl=on;
202 }
203 
204 // DoFlush: write buffered token
205 // Note: dont call Endl() since this calls DoFlush
206 void TokenWriter::DoFlush(bool clf) {
207  if(!mHasOutBuffer) return;
208  FD_DV("TokenWriter::DoFlush()");
209  try{
210  // write preceeding space
211  for(size_t i=0; i< mOutBuffer.mPreceedingSpace.size(); ++i) {
212  char c= mOutBuffer.mPreceedingSpace.at(i);
213  if(c=='\n') {
214  if(mEndl) *mpStream << std::endl;
215  else *mpStream << " ";
216  mColCount=0; ;
217  continue;
218  }
219  if(c=='\r') continue;
220  if(isspace(c)) mpStream->put(c);
221  }
222  // do the write
224  // count my columns
225  mColCount++;
226  // have closing linefeed for true flush
227  if(clf) {
228  if(mOutBuffer.IsBegin() || mOutBuffer.IsEnd())
229  if(mColCount==1)
230  if(mEndl) { *mpStream << std::endl; mColCount=0;}
232  }
233  }
234  catch (std::ios::failure&) {
235  std::stringstream errstr;
236  errstr << "Exception opening/writing file \"" << mFileName << "\"";
237  throw Exception("TokenWriter::Write(token)", errstr.str(), 2);
238  }
239  mHasOutBuffer=false;
240 }
241 
242 // Write(rToken)
243 void TokenWriter::Write(Token& rToken) {
244  FD_DV("TokenWriter::Write(token)");
245  // figure wether we can merge to an empty section:
246  // 1. buffer begin must match the current token end tag
247  if(rToken.IsEnd() && !rToken.IsBegin())
248  if(mHasOutBuffer)
249  if(mOutBuffer.IsBegin() && !mOutBuffer.IsEnd())
250  if(mOutBuffer.StringValue()==rToken.StringValue())
251  // 2. dont do it on HTML tags since it irritates bowsers
252  if(mOutBuffer.StringValue()!="b")
253  if(mOutBuffer.StringValue()!="i")
254  if(mOutBuffer.StringValue()!="tt")
255  if(mOutBuffer.StringValue()!="p")
256  if(mOutBuffer.StringValue()!="h1")
257  if(mOutBuffer.StringValue()!="h2")
258  if(mOutBuffer.StringValue()!="h3")
259  if(mOutBuffer.StringValue()!="h4")
260  if(mOutBuffer.StringValue()!="font")
261  if(mOutBuffer.StringValue()!="strong")
262  {
264  DoFlush(0);
265  return;
266  }
267  // flush buffer
268  if(mHasOutBuffer) DoFlush(0);
269  // prefer markup in new line before
270  if(rToken.PreceedingSpace()=="")
271  if(rToken.IsBegin() || rToken.IsEnd())
272  if(mColCount > 0)
273  rToken.PreceedingSpace("\n");
274  // prefer markup in new line after
275  if(rToken.PreceedingSpace()=="")
276  if(mOutBuffer.IsBegin() || mOutBuffer.IsEnd())
277  if(mColCount == 1)
278  rToken.PreceedingSpace("\n");
279  // columncount proposes linefeed
280  if(rToken.PreceedingSpace()=="")
281  if(mColCount >= mColumns && (mColumns>0) && mEndl) {
282  rToken.mPreceedingSpace="\n";
283  }
284  // insist in space between data tokens
285  if(rToken.PreceedingSpace()=="")
286  if(!(rToken.IsBegin()) && (!rToken.IsEnd()))
287  if(!(mOutBuffer.IsBegin()) && (!mOutBuffer.IsEnd())) {
288  rToken.mPreceedingSpace=" ";
289  }
290  // record token to buffer
291  mOutBuffer=rToken;
292  mHasOutBuffer=true;
293 }
294 
295 
296 // WriteString(rName)
297 void TokenWriter::WriteString(const std::string& rName) {
298  if((rName == "\n") || (rName == "\r\n")) {
299  Endl();
300  mColCount = 0;
301  return;
302  }
303  Token token;
304  token.SetString(rName);
305  Write(token);
306 }
307 
308 
309 // WriteText(rText) --- depreciated, use below variants
310 void TokenWriter::WriteText(const std::string& rText) {
311  try {
312  DoFlush();
314  }
315  catch (std::ios::failure&) {
316  std::stringstream errstr;
317  errstr << "Exception opening/writing file \"" << mFileName << "\"";
318  throw Exception("TokenWriter::WriteText(text)", errstr.str(), 2);
319  }
320 }
321 
322 // WriteText(rBegin,rText)
323 void TokenWriter::WriteText(Token& rBeginTag, const std::string& rText) {
324  if(!rBeginTag.IsBegin() || rBeginTag.IsEnd()) {
325  std::stringstream errstr;
326  errstr << "Invalid begin token while writing file \"" << mFileName << "\"";
327  throw Exception("TokenWriter::WriteText(label,text)", errstr.str(), 2);
328  }
329  try {
330  Write(rBeginTag);
331  Flush();
333  Endl();
334  WriteEnd(rBeginTag.StringValue());
335  }
336  catch (std::ios::failure&) {
337  std::stringstream errstr;
338  errstr << "Exception writing file \"" << mFileName << "\"";
339  throw Exception("TokenWriter::WriteText(label,text)", errstr.str(), 2);
340  }
341 }
342 
343 
344 // WriteText(rLabel,rText) -- wrapper
345 void TokenWriter::WriteText(const std::string& rLabel, const std::string& rText) {
346  Token btag;
347  btag.SetBegin(rLabel);
348  WriteText(btag,rText);
349 }
350 
351 
352 // WriteVerbatim(rData)
353 void TokenWriter::WriteVerbatim(Token& rBeginTag, const std::string& rText) {
354  FD_DV("TokenWriter::Write(token)");
355  if(!rBeginTag.IsBegin() || rBeginTag.IsEnd()) {
356  std::stringstream errstr;
357  errstr << "Invalid begin token while writing file \"" << mFileName << "\"";
358  throw Exception("TokenWriter::WriteVerbatim(tag,text)", errstr.str(), 2);
359  }
360  Write(rBeginTag);
361  Flush();
362  try{
363  if(mColCount !=0) Endl();
364  Token::WriteVerbatim(mpStream,rText,1); // flag: add linefeeds
365  mColCount = 0;
366  Endl();
367  }
368  catch (std::ios::failure&) {
369  std::stringstream errstr;
370  errstr << "Exception opening/writing file \"" << mFileName << "\"";
371  throw Exception("TokenWriter::WriteVerbatim()", errstr.str(), 2);
372  }
373  WriteEnd(rBeginTag.StringValue());
374 }
375 
376 // WriteVerbatim(rLabel,rText) -- wrapper
377 void TokenWriter::WriteVerbatim(const std::string& rLabel, const std::string& rText) {
378  Token btag;
379  btag.SetBegin(rLabel);
380  WriteVerbatim(btag,rText);
381 }
382 
383 
384 // WriteCharacterData(rCData)
385 void TokenWriter::WriteCharacterData(const std::string& rCharacterData) {
386  // bail out on trivial to avoid unnecessary flush
387  if(rCharacterData.size()==0) return;
388  // do write
389  try {
390  DoFlush(0); // no extra linefeed formating here
391  *mpStream << rCharacterData;
392  }
393  catch (std::ios::failure&) {
394  std::stringstream errstr;
395  errstr << "Exception opening/writing file \"" << mFileName << "\"";
396  throw Exception("TokenWriter::WriteCharacterData(text)", errstr.str(), 2);
397  }
398  // adjust column count
400  if(rCharacterData.size()>=1)
401  if(rCharacterData.at(rCharacterData.size()-1)=='\n')
402  mColCount=0;
403 }
404 
405 // WriteInteger(index)
407  Token token;
408  token.SetInteger(index);
409  Write(token);
410 }
411 
412 // WriteInteger(index)
413 void TokenWriter::WriteInteger16(long int val) {
414  Token token;
415  token.SetInteger16(val);
416  Write(token);
417 }
418 
419 // WriteFloat(float)
420 void TokenWriter::WriteFloat(const double& val) {
421  Token token;
422  token.SetFloat(val);
423  Write(token);
424 }
425 
426 
427 // WriteOption(rOpt)
428 void TokenWriter::WriteOption(const std::string& rOpt) {
429  Token token;
430  token.SetOption(rOpt);
431  Write(token);
432 }
433 
434 
435 // WriteBegin(rLabel)
436 void TokenWriter::WriteBegin(const std::string& rLabel) {
437  Token token;
438  token.SetBegin(rLabel);
439  Write(token);
440 }
441 
442 // WriteEnd(rLabel)
443 void TokenWriter::WriteEnd(const std::string& rLabel) {
444  Token token;
445  token.SetEnd(rLabel);
446  Write(token);
447 }
448 
449 // WriteBegin(rLabel)
450 void TokenWriter::WriteEmpty(const std::string& rLabel) {
451  Token token;
452  token.SetEmpty(rLabel);
453  Write(token);
454 }
455 
456 // WriteComment(comment)
457 void TokenWriter::WriteComment(const std::string& comment){
458  DoFlush();
459  // auto xml
460  if(mMode==XmlFile || mMode==XmlStream) { WriteXmlComment(comment); return; }
461  // no endl ... no comment
462  if(!mEndl) return;
463  try{
464  if(mColCount!=0) Endl();
465  // fix comment indicator
466  if(comment.length()==0)
467  *mpStream << "% ";
468  if(comment.length()>0)
469  if(comment.at(0)!='%')
470  *mpStream << "% ";
471  // xml/endl escape
472  std::string::const_iterator cit=comment.begin();
473  for(;cit!=comment.end(); cit++) {
474  if(*cit=='<')
475  { *mpStream << "&lt;"; continue;}
476  if(*cit=='>')
477  { *mpStream << "&gt;"; continue;}
478  if(*cit=='&')
479  { *mpStream << "&amp;"; continue;}
480  if(*cit=='\n')
481  { *mpStream << " "; continue;}
482  if(*cit=='\r')
483  { ; continue;}
484  *mpStream << *cit;
485  }
486  // done
487  Endl();
488  mColCount = 0;
489  }
490  catch (std::ios::failure&) {
491  std::stringstream errstr;
492  errstr << "Exception opening/writing file \"" << mFileName << "\"";
493  throw Exception("TokenWriter::Comment", errstr.str(), 2);
494  }
495 }
496 
497 // WriteXmlComment(comment)
498 void TokenWriter::WriteXmlComment(const std::string& comment){
499  if(!mEndl) return; // no endl implies no comments
500  DoFlush();
501  try{
502  if(mColCount!=0) Endl();
503  // begin tag
504  *mpStream << "<!-- ";
505  // test for multiline
506  static const std::string newline="\n\r";
507  if(comment.find_first_of(newline)!=std::string::npos)
508  Endl();
509  // xml/endl escape
510  std::string::const_iterator cit=comment.begin();
511  for(;cit!=comment.end(); cit++) {
512  if(*cit=='>')
513  { *mpStream << "&gt;"; continue;}
514  *mpStream << *cit;
515  }
516  // end tag
517  *mpStream << " -->";
518  // done
519  Endl();
520  mColCount = 0;
521  }
522  catch (std::ios::failure&) {
523  std::stringstream errstr;
524  errstr << "Exception opening/writing file \"" << mFileName << "\"";
525  throw Exception("TokenWriter::Comment", errstr.str(), 2);
526  }
527 }
528 
529 // write base64
530 void TokenWriter::WriteBinary(const char* pData, long int len) {
531  DoFlush();
532  Token::WriteBinary(mpStream,pData,len);
533 }
534 
535 // FileName()
536 std::string TokenWriter::FileName(void) const {
537  return mFileName;
538 }
539 
540 
541 
542 
543 } // namespace faudes
#define FD_NAMELEN
#define FD_DV(message)
Class TokenWriter.
static ConsoleOut * G(void)
Definition: cfl_utils.cpp:442
virtual void Write(const std::string &message, long int cntnow=0, long int cntdone=0, int verb=1)
Definition: cfl_utils.cpp:461
void WriteInteger16(long int val)
std::ostringstream mSStream
std::string FileName(void) const
std::string Str(void)
void WriteFloat(const double &val)
void WriteXmlComment(const std::string &rComment)
std::ostream * mpStream
void WriteText(const std::string &rText)
void WriteEmpty(const std::string &rLabel)
void WriteCharacterData(const std::string &rCharData)
void WriteComment(const std::string &rComment)
void Write(Token &rToken)
std::ostream * Streamp(void)
void WriteString(const std::string &rString)
std::ostream * pSStream
void WriteEnd(const std::string &rLabel)
void WriteBinary(const char *pData, long int len)
int Columns(void) const
void WriteVerbatim(Token &rBeginTag, const std::string &rText)
std::ofstream mFStream
void DoFlush(bool clf=1)
void WriteInteger(Idx index)
void WriteBegin(const std::string &rLabel)
void WriteOption(const std::string &rOpt)
void SetNone(void)
Definition: cfl_token.cpp:73
const std::string & PreceedingSpace(void) const
Definition: cfl_token.cpp:189
void SetInteger16(const Int number)
Definition: cfl_token.cpp:129
const std::string & StringValue(void) const
Definition: cfl_token.cpp:178
void SetInteger(const Int number)
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)
Definition: cfl_token.cpp:417
void Write(std::ostream *pStream) const
Definition: cfl_token.cpp:750
void SetString(const std::string &rName)
Definition: cfl_token.cpp:85
void SetOption(const std::string &rName)
Definition: cfl_token.cpp:113
bool IsBegin(void) const
Definition: cfl_token.cpp:259
void SetFloat(const faudes::Float number)
Definition: cfl_token.cpp:145
void SetEmpty(const std::string &rName)
Definition: cfl_token.cpp:106
static void WriteBinary(std::ostream *pStream, const char *pData, std::size_t len)
Definition: cfl_token.cpp:446
static int WriteEscapedString(std::ostream *pStream, const std::string &outstr)
Definition: cfl_token.cpp:813
void SetBegin(const std::string &rName)
Definition: cfl_token.cpp:92
bool IsEnd(void) const
Definition: cfl_token.cpp:270
std::string mPreceedingSpace
Definition: cfl_token.h:649
void SetEnd(const std::string &rName)
Definition: cfl_token.cpp:99
uint32_t Idx

libFAUDES 2.33h --- 2025.06.18 --- c++ api documentaion by doxygen