KiCad PCB EDA Suite
richio.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2007-2011 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
5  * Copyright (C) 2016 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
25 
26 #include <cstdarg>
27 #include <config.h> // HAVE_FGETC_NOLOCK
28 
29 #include <richio.h>
30 
31 
32 // Fall back to getc() when getc_unlocked() is not available on the target platform.
33 #if !defined( HAVE_FGETC_NOLOCK )
34 #define getc_unlocked getc
35 #endif
36 
37 
38 static int vprint( std::string* result, const char* format, va_list ap )
39 {
40  char msg[512];
41  // This function can call vsnprintf twice.
42  // But internally, vsnprintf retrieves arguments from the va_list identified by arg as if
43  // va_arg was used on it, and thus the state of the va_list is likely to be altered by the call.
44  // see: www.cplusplus.com/reference/cstdio/vsnprintf
45  // we make a copy of va_list ap for the second call, if happens
46  va_list tmp;
47  va_copy( tmp, ap );
48 
49  size_t len = vsnprintf( msg, sizeof(msg), format, ap );
50 
51  if( len < sizeof(msg) ) // the output fit into msg
52  {
53  result->append( msg, msg + len );
54  }
55  else
56  {
57  // output was too big, so now incur the expense of allocating
58  // a buf for holding suffient characters.
59 
60  std::vector<char> buf;
61 
62  buf.reserve( len+1 ); // reserve(), not resize() which writes. +1 for trailing nul.
63 
64  len = vsnprintf( &buf[0], len+1, format, tmp );
65 
66  result->append( &buf[0], &buf[0] + len );
67  }
68 
69  va_end( tmp ); // Release the temporary va_list, initialised from ap
70 
71  return len;
72 }
73 
74 
75 int StrPrintf( std::string* result, const char* format, ... )
76 {
77  va_list args;
78 
79  va_start( args, format );
80  int ret = vprint( result, format, args );
81  va_end( args );
82 
83  return ret;
84 }
85 
86 
87 std::string StrPrintf( const char* format, ... )
88 {
89  std::string ret;
90  va_list args;
91 
92  va_start( args, format );
93  int ignore = vprint( &ret, format, args );
94  (void) ignore;
95  va_end( args );
96 
97  return ret;
98 }
99 
100 
101 //-----<LINE_READER>------------------------------------------------------
102 
103 LINE_READER::LINE_READER( unsigned aMaxLineLength ) :
104  length( 0 ),
105  lineNum( 0 ),
106  line( NULL ),
107  capacity( 0 ),
108  maxLineLength( aMaxLineLength )
109 {
110  if( aMaxLineLength != 0 )
111  {
112  // start at the INITIAL size, expand as needed up to the MAX size in maxLineLength
114 
115  // but never go above user's aMaxLineLength, and leave space for trailing nul
116  if( capacity > aMaxLineLength+1 )
117  capacity = aMaxLineLength+1;
118 
119  line = new char[capacity];
120 
121  line[0] = '\0';
122  }
123 }
124 
125 
127 {
128  delete[] line;
129 }
130 
131 
132 void LINE_READER::expandCapacity( unsigned newsize )
133 {
134  // length can equal maxLineLength and nothing breaks, there's room for
135  // the terminating nul. cannot go over this.
136  if( newsize > maxLineLength+1 )
137  newsize = maxLineLength+1;
138 
139  if( newsize > capacity )
140  {
141  capacity = newsize;
142 
143  // resize the buffer, and copy the original data
144  char* bigger = new char[capacity];
145 
146  wxASSERT( capacity >= length+1 );
147 
148  memcpy( bigger, line, length );
149  bigger[length] = 0;
150 
151  delete[] line;
152  line = bigger;
153  }
154 }
155 
156 
157 FILE_LINE_READER::FILE_LINE_READER( const wxString& aFileName,
158  unsigned aStartingLineNumber,
159  unsigned aMaxLineLength ):
160  LINE_READER( aMaxLineLength ),
161  iOwn( true )
162 {
163  fp = wxFopen( aFileName, wxT( "rt" ) );
164  if( !fp )
165  {
166  wxString msg = wxString::Format(
167  _( "Unable to open filename '%s' for reading" ), aFileName.GetData() );
168  THROW_IO_ERROR( msg );
169  }
170 
171  source = aFileName;
172  lineNum = aStartingLineNumber;
173 }
174 
175 
176 FILE_LINE_READER::FILE_LINE_READER( FILE* aFile, const wxString& aFileName,
177  bool doOwn,
178  unsigned aStartingLineNumber,
179  unsigned aMaxLineLength ) :
180  LINE_READER( aMaxLineLength ),
181  iOwn( doOwn ),
182  fp( aFile )
183 {
184  source = aFileName;
185  lineNum = aStartingLineNumber;
186 }
187 
188 
190 {
191  if( iOwn && fp )
192  fclose( fp );
193 }
194 
195 
197 {
198  length = 0;
199 
200  for(;;)
201  {
202  if( length >= maxLineLength )
203  THROW_IO_ERROR( _( "Maximum line length exceeded" ) );
204 
205  if( length >= capacity )
206  expandCapacity( capacity * 2 );
207 
208  // faster, POSIX compatible fgetc(), no locking.
209  int cc = getc_unlocked( fp );
210  if( cc == EOF )
211  break;
212 
213  line[ length++ ] = (char) cc;
214 
215  if( cc == '\n' )
216  break;
217  }
218 
219  line[ length ] = 0;
220 
221  // lineNum is incremented even if there was no line read, because this
222  // leads to better error reporting when we hit an end of file.
223  ++lineNum;
224 
225  return length ? line : NULL;
226 }
227 
228 
229 STRING_LINE_READER::STRING_LINE_READER( const std::string& aString, const wxString& aSource ):
231  lines( aString ),
232  ndx( 0 )
233 {
234  // Clipboard text should be nice and _use multiple lines_ so that
235  // we can report _line number_ oriented error messages when parsing.
236  source = aSource;
237 }
238 
239 
242  lines( aStartingPoint.lines ),
243  ndx( aStartingPoint.ndx )
244 {
245  // since we are keeping the same "source" name, for error reporting purposes
246  // we need to have the same notion of line number and offset.
247 
248  source = aStartingPoint.source;
249  lineNum = aStartingPoint.lineNum;
250 }
251 
252 
254 {
255  size_t nlOffset = lines.find( '\n', ndx );
256 
257  if( nlOffset == std::string::npos )
258  length = lines.length() - ndx;
259  else
260  length = nlOffset - ndx + 1; // include the newline, so +1
261 
262  if( length )
263  {
264  if( length >= maxLineLength )
265  THROW_IO_ERROR( _("Line length exceeded") );
266 
267  if( length+1 > capacity ) // +1 for terminating nul
268  expandCapacity( length+1 );
269 
270  wxASSERT( ndx + length <= lines.length() );
271 
272  memcpy( line, &lines[ndx], length );
273 
274  ndx += length;
275  }
276 
277  ++lineNum; // this gets incremented even if no bytes were read
278 
279  line[length] = 0;
280 
281  return length ? line : NULL;
282 }
283 
284 
285 INPUTSTREAM_LINE_READER::INPUTSTREAM_LINE_READER( wxInputStream* aStream, const wxString& aSource ) :
287  m_stream( aStream )
288 {
289  source = aSource;
290 }
291 
292 
294 {
295  length = 0;
296 
297  for(;;)
298  {
299  if( length >= maxLineLength )
300  THROW_IO_ERROR( _( "Maximum line length exceeded" ) );
301 
302  if( length + 1 > capacity )
303  expandCapacity( capacity * 2 );
304 
305  // this read may fail, docs say to test LastRead() before trusting cc.
306  char cc = m_stream->GetC();
307 
308  if( !m_stream->LastRead() )
309  break;
310 
311  line[ length++ ] = cc;
312 
313  if( cc == '\n' )
314  break;
315  }
316 
317  line[ length ] = 0;
318 
319  // lineNum is incremented even if there was no line read, because this
320  // leads to better error reporting when we hit an end of file.
321  ++lineNum;
322 
323  return length ? line : NULL;
324 }
325 
326 
327 //-----<OUTPUTFORMATTER>----------------------------------------------------
328 
329 // factor out a common GetQuoteChar
330 
331 const char* OUTPUTFORMATTER::GetQuoteChar( const char* wrapee, const char* quote_char )
332 {
333  // Include '#' so a symbol is not confused with a comment. We intend
334  // to wrap any symbol starting with a '#'.
335  // Our LEXER class handles comments, and comments appear to be an extension
336  // to the SPECCTRA DSN specification.
337  if( *wrapee == '#' )
338  return quote_char;
339 
340  if( strlen( wrapee ) == 0 )
341  return quote_char;
342 
343  bool isFirst = true;
344 
345  for( ; *wrapee; ++wrapee, isFirst = false )
346  {
347  static const char quoteThese[] = "\t ()"
348  "%" // per Alfons of freerouting.net, he does not like this unquoted as of 1-Feb-2008
349  "{}" // guessing that these are problems too
350  ;
351 
352  // if the string to be wrapped (wrapee) has a delimiter in it,
353  // return the quote_char so caller wraps the wrapee.
354  if( strchr( quoteThese, *wrapee ) )
355  return quote_char;
356 
357  if( !isFirst && '-' == *wrapee )
358  return quote_char;
359  }
360 
361  return ""; // caller does not need to wrap, can use an unwrapped string.
362 }
363 
364 
365 const char* OUTPUTFORMATTER::GetQuoteChar( const char* wrapee )
366 {
367  return GetQuoteChar( wrapee, quoteChar );
368 }
369 
370 int OUTPUTFORMATTER::vprint( const char* fmt, va_list ap )
371 {
372  // This function can call vsnprintf twice.
373  // But internally, vsnprintf retrieves arguments from the va_list identified by arg as if
374  // va_arg was used on it, and thus the state of the va_list is likely to be altered by the call.
375  // see: www.cplusplus.com/reference/cstdio/vsnprintf
376  // we make a copy of va_list ap for the second call, if happens
377  va_list tmp;
378  va_copy( tmp, ap );
379  int ret = vsnprintf( &buffer[0], buffer.size(), fmt, ap );
380 
381  if( ret >= (int) buffer.size() )
382  {
383  buffer.resize( ret + 1000 );
384  ret = vsnprintf( &buffer[0], buffer.size(), fmt, tmp );
385  }
386 
387  va_end( tmp ); // Release the temporary va_list, initialised from ap
388 
389  if( ret > 0 )
390  write( &buffer[0], ret );
391 
392  return ret;
393 }
394 
395 
396 int OUTPUTFORMATTER::sprint( const char* fmt, ... )
397 {
398  va_list args;
399 
400  va_start( args, fmt );
401  int ret = vprint( fmt, args);
402  va_end( args );
403 
404  return ret;
405 }
406 
407 
408 int OUTPUTFORMATTER::Print( int nestLevel, const char* fmt, ... )
409 {
410 #define NESTWIDTH 2
411 
412  va_list args;
413 
414  va_start( args, fmt );
415 
416  int result = 0;
417  int total = 0;
418 
419  for( int i=0; i<nestLevel; ++i )
420  {
421  // no error checking needed, an exception indicates an error.
422  result = sprint( "%*c", NESTWIDTH, ' ' );
423 
424  total += result;
425  }
426 
427  // no error checking needed, an exception indicates an error.
428  result = vprint( fmt, args );
429 
430  va_end( args );
431 
432  total += result;
433  return total;
434 }
435 
436 
437 std::string OUTPUTFORMATTER::Quotes( const std::string& aWrapee )
438 {
439  static const char quoteThese[] = "\t ()\n\r";
440 
441  if( !aWrapee.size() || // quote null string as ""
442  aWrapee[0]=='#' || // quote a potential s-expression comment, so it is not a comment
443  aWrapee[0]=='"' || // NextTok() will travel through DSN_STRING path anyway, then must apply escapes
444  aWrapee.find_first_of( quoteThese ) != std::string::npos )
445  {
446  std::string ret;
447 
448  ret.reserve( aWrapee.size()*2 + 2 );
449 
450  ret += '"';
451 
452  for( std::string::const_iterator it = aWrapee.begin(); it!=aWrapee.end(); ++it )
453  {
454  switch( *it )
455  {
456  case '\n':
457  ret += '\\';
458  ret += 'n';
459  break;
460  case '\r':
461  ret += '\\';
462  ret += 'r';
463  break;
464  case '\\':
465  ret += '\\';
466  ret += '\\';
467  break;
468  case '"':
469  ret += '\\';
470  ret += '"';
471  break;
472  default:
473  ret += *it;
474  }
475  }
476 
477  ret += '"';
478 
479  return ret;
480  }
481 
482  return aWrapee;
483 }
484 
485 
486 std::string OUTPUTFORMATTER::Quotew( const wxString& aWrapee )
487 {
488  // wxStrings are always encoded as UTF-8 as we convert to a byte sequence.
489  // The non-virutal function calls the virtual workhorse function, and if
490  // a different quoting or escaping strategy is desired from the standard,
491  // a derived class can overload Quotes() above, but
492  // should never be a reason to overload this Quotew() here.
493  return Quotes( (const char*) aWrapee.utf8_str() );
494 }
495 
496 
497 //-----<STRING_FORMATTER>----------------------------------------------------
498 
499 void STRING_FORMATTER::write( const char* aOutBuf, int aCount )
500 {
501  mystring.append( aOutBuf, aCount );
502 }
503 
505 {
506  std::string copy = mystring;
507 
508  mystring.clear();
509 
510  for( std::string::iterator i=copy.begin(); i!=copy.end(); ++i )
511  {
512  if( !isspace( *i ) && *i!=')' && *i!='(' && *i!='"' )
513  {
514  mystring += *i;
515  }
516  }
517 }
518 
519 //-----<FILE_OUTPUTFORMATTER>----------------------------------------
520 
522  const wxChar* aMode, char aQuoteChar ):
523  OUTPUTFORMATTER( OUTPUTFMTBUFZ, aQuoteChar ),
524  m_filename( aFileName )
525 {
526  m_fp = wxFopen( aFileName, aMode );
527 
528  if( !m_fp )
529  {
530  wxString msg = wxString::Format(
531  _( "cannot open or save file '%s'" ),
532  m_filename.GetData() );
533  THROW_IO_ERROR( msg );
534  }
535 }
536 
537 
539 {
540  if( m_fp )
541  fclose( m_fp );
542 }
543 
544 
545 void FILE_OUTPUTFORMATTER::write( const char* aOutBuf, int aCount )
546 {
547  if( 1 != fwrite( aOutBuf, aCount, 1, m_fp ) )
548  {
549  wxString msg = wxString::Format(
550  _( "error writing to file '%s'" ),
551  m_filename.GetData() );
552  THROW_IO_ERROR( msg );
553  }
554 }
555 
556 
557 //-----<STREAM_OUTPUTFORMATTER>--------------------------------------
558 
559 void STREAM_OUTPUTFORMATTER::write( const char* aOutBuf, int aCount )
560 {
561  int lastWrite;
562 
563  // This might delay awhile if you were writing to say a socket, but for
564  // a file it should only go through the loop once.
565  for( int total = 0; total<aCount; total += lastWrite )
566  {
567  lastWrite = os.Write( aOutBuf, aCount ).LastWrite();
568 
569  if( !os.IsOk() )
570  {
571  THROW_IO_ERROR( _( "OUTPUTSTREAM_OUTPUTFORMATTER write error" ) );
572  }
573  }
574 }
575 
int sprint(const char *fmt,...)
Definition: richio.cpp:396
void write(const char *aOutBuf, int aCount) override
Function write should be coded in the interface implementation (derived) classes. ...
Definition: richio.cpp:545
std::string lines
Definition: richio.h:257
Class LINE_READER is an abstract class from which implementation specific LINE_READERs may be derived...
Definition: richio.h:81
virtual ~LINE_READER()
Definition: richio.cpp:126
char * ReadLine() override
Function ReadLine reads a line of text into the buffer and increments the line number counter...
Definition: richio.cpp:196
#define LINE_READER_LINE_INITIAL_SIZE
Definition: richio.h:74
#define NESTWIDTH
~FILE_LINE_READER()
Destructor may or may not close the open file, depending on doOwn in constructor. ...
Definition: richio.cpp:189
unsigned maxLineLength
maximum allowed capacity using resizing.
Definition: richio.h:90
virtual void write(const char *aOutBuf, int aCount)=0
Function write should be coded in the interface implementation (derived) classes. ...
INPUTSTREAM_LINE_READER(wxInputStream *aStream, const wxString &aSource)
Constructor WXINPUTSTREAM_LINE_READER.
Definition: richio.cpp:285
Class OUTPUTFORMATTER is an important interface (abstract class) used to output 8 bit text in a conve...
Definition: richio.h:327
wxInputStream * m_stream
Definition: richio.h:293
std::string mystring
Definition: richio.h:447
FILE * fp
I may own this file, but might not.
Definition: richio.h:185
char * ReadLine() override
Function ReadLine reads a line of text into the buffer and increments the line number counter...
Definition: richio.cpp:253
int StrPrintf(std::string *result, const char *format,...)
Function StrPrintf is like sprintf() but the output is appended to a std::string instead of to a char...
Definition: richio.cpp:75
unsigned lineNum
Definition: richio.h:85
bool iOwn
if I own the file, I'll promise to close it, else not.
Definition: richio.h:184
char * line
the read line of UTF8 text
Definition: richio.h:87
wxString m_filename
Definition: richio.h:517
int vprint(const char *fmt, va_list ap)
Definition: richio.cpp:370
#define LINE_READER_LINE_DEFAULT_MAX
Definition: richio.h:73
std::vector< char > buffer
Definition: richio.h:329
void expandCapacity(unsigned newsize)
Function expandCapacity will expand the capacity of line up to maxLineLength but not greater...
Definition: richio.cpp:132
#define getc_unlocked
Definition: richio.cpp:34
void write(const char *aOutBuf, int aCount) override
Function write should be coded in the interface implementation (derived) classes. ...
Definition: richio.cpp:559
#define OUTPUTFMTBUFZ
default buffer size for any OUTPUT_FORMATTER
Definition: richio.h:309
std::string Quotew(const wxString &aWrapee)
Definition: richio.cpp:486
#define THROW_IO_ERROR(x)
Definition: utf8.cpp:60
LINE_READER(unsigned aMaxLineLength=LINE_READER_LINE_DEFAULT_MAX)
Constructor LINE_READER builds a line reader and fixes the length of the maximum supported line lengt...
Definition: richio.cpp:103
unsigned length
no. bytes in line before trailing nul.
Definition: richio.h:84
static const char * GetQuoteChar(const char *wrapee, const char *quote_char)
Function GetQuoteChar performs quote character need determination according to the Specctra DSN speci...
Definition: richio.cpp:331
virtual std::string Quotes(const std::string &aWrapee)
Function Quotes checks aWrapee input string for a need to be quoted (e.g.
Definition: richio.cpp:437
FILE * m_fp
takes ownership
Definition: richio.h:516
FILE_OUTPUTFORMATTER(const wxString &aFileName, const wxChar *aMode=wxT("wt"), char aQuoteChar= '"' )
Constructor.
Definition: richio.cpp:521
wxOutputStream & os
Definition: richio.h:528
FILE_LINE_READER(const wxString &aFileName, unsigned aStartingLineNumber=0, unsigned aMaxLineLength=LINE_READER_LINE_DEFAULT_MAX)
Constructor FILE_LINE_READER takes aFileName and the size of the desired line buffer and opens the fi...
Definition: richio.cpp:157
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
void write(const char *aOutBuf, int aCount) override
Function write should be coded in the interface implementation (derived) classes. ...
Definition: richio.cpp:499
void StripUseless()
Function StripUseless removes whitespace, '(', and ')' from the mystring.
Definition: richio.cpp:504
char * ReadLine() override
Function ReadLine reads a line of text into the buffer and increments the line number counter...
Definition: richio.cpp:293
int PRINTF_FUNC Print(int nestLevel, const char *fmt,...)
Function Print formats and writes text to the output stream.
Definition: richio.cpp:408
unsigned capacity
no. bytes allocated for line.
Definition: richio.h:88
static int vprint(std::string *result, const char *format, va_list ap)
Definition: richio.cpp:38
char quoteChar[2]
Definition: richio.h:330
Class STRING_LINE_READER is a LINE_READER that reads from a multiline 8 bit wide std::string.
Definition: richio.h:254
wxString source
origin of text lines, e.g. filename or "clipboard"
Definition: richio.h:92
STRING_LINE_READER(const std::string &aString, const wxString &aSource)
Constructor STRING_LINE_READER( const std::string&, const wxString& )
Definition: richio.cpp:229