KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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 <[email protected]>
5 * Copyright (C) 2017-2021 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 <kiplatform/io.h>
30#include <core/ignore.h>
31#include <richio.h>
32#include <errno.h>
33
34#include <wx/file.h>
35#include <wx/translation.h>
36
37
38// Fall back to getc() when getc_unlocked() is not available on the target platform.
39#if !defined( HAVE_FGETC_NOLOCK )
40#ifdef _MSC_VER
41//getc is not a macro on windows and adds a tiny overhead for the indirection to eventually calling fgetc
42#define getc_unlocked _fgetc_nolock
43#else
44#define getc_unlocked getc
45#endif
46#endif
47
48
49static int vprint( std::string* result, const char* format, va_list ap )
50{
51 char msg[512];
52 // This function can call vsnprintf twice.
53 // But internally, vsnprintf retrieves arguments from the va_list identified by arg as if
54 // va_arg was used on it, and thus the state of the va_list is likely to be altered by the call.
55 // see: www.cplusplus.com/reference/cstdio/vsnprintf
56 // we make a copy of va_list ap for the second call, if happens
57 va_list tmp;
58 va_copy( tmp, ap );
59
60 size_t len = vsnprintf( msg, sizeof(msg), format, ap );
61
62 if( len < sizeof(msg) ) // the output fit into msg
63 {
64 result->append( msg, msg + len );
65 }
66 else
67 {
68 // output was too big, so now incur the expense of allocating
69 // a buf for holding suffient characters.
70
71 std::vector<char> buf;
72 buf.reserve( len+1 ); // reserve(), not resize() which writes. +1 for trailing nul.
73
74 len = vsnprintf( &buf[0], len+1, format, tmp );
75
76 result->append( &buf[0], &buf[0] + len );
77 }
78
79 va_end( tmp ); // Release the temporary va_list, initialised from ap
80
81 return len;
82}
83
84
85int StrPrintf( std::string* result, const char* format, ... )
86{
87 va_list args;
88
89 va_start( args, format );
90 int ret = vprint( result, format, args );
91 va_end( args );
92
93 return ret;
94}
95
96
97std::string StrPrintf( const char* format, ... )
98{
99 std::string ret;
100 va_list args;
101
102 va_start( args, format );
103 ignore_unused( vprint( &ret, format, args ) );
104 va_end( args );
105
106 return ret;
107}
108
109
110wxString SafeReadFile( const wxString& aFilePath, const wxString& aReadType )
111{
112 auto From_UTF8_WINE =
113 []( const char* cstring )
114 {
115 wxString line = wxString::FromUTF8( cstring );
116
117 if( line.IsEmpty() ) // happens when cstring is not a valid UTF8 sequence
118 line = wxConvCurrent->cMB2WC( cstring ); // try to use locale conversion
119
120 // We have trouble here *probably* because Wine-hosted LTSpice writes out MSW
121 // encoded text on a macOS, where it isn't expected. In any case, wxWidgets'
122 // wxSafeConvert() appears to get around it.
123
124 if( line.IsEmpty() )
125 line = wxSafeConvertMB2WX( cstring );
126
127 // I'm not sure what the source of this style of line-endings is, but it can be
128 // found in some Fairchild Semiconductor SPICE files.
129 line.Replace( wxS( "\r\r\n" ), wxS( "\n" ) );
130
131 return line;
132 };
133
134 // Open file
135 FILE* fp = wxFopen( aFilePath, aReadType );
136
137 if( !fp )
138 THROW_IO_ERROR( wxString::Format( _( "Cannot open file '%s'." ), aFilePath ) );
139
140 FILE_LINE_READER fileReader( fp, aFilePath );
141
142 wxString contents;
143
144 while( fileReader.ReadLine() )
145 contents += From_UTF8_WINE( fileReader.Line() );
146
147 return contents;
148}
149
150
151//-----<LINE_READER>------------------------------------------------------
152
153LINE_READER::LINE_READER( unsigned aMaxLineLength ) :
154 m_length( 0 ), m_lineNum( 0 ), m_line( nullptr ),
155 m_capacity( 0 ), m_maxLineLength( aMaxLineLength )
156{
157 if( aMaxLineLength != 0 )
158 {
159 // start at the INITIAL size, expand as needed up to the MAX size in maxLineLength
161
162 // but never go above user's aMaxLineLength, and leave space for trailing nul
163 if( m_capacity > aMaxLineLength+1 )
164 m_capacity = aMaxLineLength+1;
165
166 // Be sure there is room for a null EOL char, so reserve at least capacity+1 bytes
167 // to ensure capacity line length and avoid corner cases
168 // Use capacity+5 to cover and corner case
169 m_line = new char[m_capacity+5];
170
171 m_line[0] = '\0';
172 }
173}
174
175
177{
178 delete[] m_line;
179}
180
181
182void LINE_READER::expandCapacity( unsigned aNewsize )
183{
184 // m_length can equal maxLineLength and nothing breaks, there's room for
185 // the terminating nul. cannot go over this.
186 if( aNewsize > m_maxLineLength+1 )
187 aNewsize = m_maxLineLength+1;
188
189 if( aNewsize > m_capacity )
190 {
191 m_capacity = aNewsize;
192
193 // resize the buffer, and copy the original data
194 // Be sure there is room for the null EOL char, so reserve capacity+1 bytes
195 // to ensure capacity line length. Use capacity+5 to cover and corner case
196 char* bigger = new char[m_capacity+5];
197
198 wxASSERT( m_capacity >= m_length+1 );
199
200 memcpy( bigger, m_line, m_length );
201 bigger[m_length] = 0;
202
203 delete[] m_line;
204 m_line = bigger;
205 }
206}
207
208
209FILE_LINE_READER::FILE_LINE_READER( const wxString& aFileName, unsigned aStartingLineNumber,
210 unsigned aMaxLineLength ):
211 LINE_READER( aMaxLineLength ), m_iOwn( true )
212{
213 m_fp = KIPLATFORM::IO::SeqFOpen( aFileName, wxT( "rt" ) );
214
215 if( !m_fp )
216 {
217 wxString msg = wxString::Format( _( "Unable to open %s for reading." ),
218 aFileName.GetData() );
219 THROW_IO_ERROR( msg );
220 }
221
222 m_source = aFileName;
223 m_lineNum = aStartingLineNumber;
224}
225
226
227FILE_LINE_READER::FILE_LINE_READER( FILE* aFile, const wxString& aFileName,
228 bool doOwn,
229 unsigned aStartingLineNumber,
230 unsigned aMaxLineLength ) :
231 LINE_READER( aMaxLineLength ), m_iOwn( doOwn ), m_fp( aFile )
232{
233 m_source = aFileName;
234 m_lineNum = aStartingLineNumber;
235}
236
237
239{
240 if( m_iOwn && m_fp )
241 fclose( m_fp );
242}
243
244
246{
247 fseek( m_fp, 0, SEEK_END );
248 long int fileLength = ftell( m_fp );
249 rewind( m_fp );
250
251 return fileLength;
252}
253
254
256{
257 return ftell( m_fp );
258}
259
260
262{
263 m_length = 0;
264
265 for( ;; )
266 {
268 THROW_IO_ERROR( _( "Maximum line length exceeded" ) );
269
270 if( m_length >= m_capacity )
272
273 // faster, POSIX compatible fgetc(), no locking.
274 int cc = getc_unlocked( m_fp );
275
276 if( cc == EOF )
277 break;
278
279 m_line[ m_length++ ] = (char) cc;
280
281 if( cc == '\n' )
282 break;
283 }
284
285 m_line[ m_length ] = 0;
286
287 // m_lineNum is incremented even if there was no line read, because this
288 // leads to better error reporting when we hit an end of file.
289 ++m_lineNum;
290
291 return m_length ? m_line : nullptr;
292}
293
294
295STRING_LINE_READER::STRING_LINE_READER( const std::string& aString, const wxString& aSource ):
297 m_lines( aString ), m_ndx( 0 )
298{
299 // Clipboard text should be nice and _use multiple lines_ so that
300 // we can report _line number_ oriented error messages when parsing.
301 m_source = aSource;
302}
303
304
307 m_lines( aStartingPoint.m_lines ),
308 m_ndx( aStartingPoint.m_ndx )
309{
310 // since we are keeping the same "source" name, for error reporting purposes
311 // we need to have the same notion of line number and offset.
312
313 m_source = aStartingPoint.m_source;
314 m_lineNum = aStartingPoint.m_lineNum;
315}
316
317
319{
320 size_t nlOffset = m_lines.find( '\n', m_ndx );
321 unsigned new_length;
322
323 if( nlOffset == std::string::npos )
324 new_length = m_lines.length() - m_ndx;
325 else
326 new_length = nlOffset - m_ndx + 1; // include the newline, so +1
327
328 if( new_length )
329 {
330 if( new_length >= m_maxLineLength )
331 THROW_IO_ERROR( _("Line length exceeded") );
332
333 if( new_length+1 > m_capacity ) // +1 for terminating nul
334 expandCapacity( new_length+1 );
335
336 wxASSERT( m_ndx + new_length <= m_lines.length() );
337
338 memcpy( m_line, &m_lines[m_ndx], new_length );
339 m_ndx += new_length;
340 }
341
342 m_length = new_length;
343 ++m_lineNum; // this gets incremented even if no bytes were read
344 m_line[m_length] = 0;
345
346 return m_length ? m_line : nullptr;
347}
348
349
351 const wxString& aSource ) :
353 m_stream( aStream )
354{
355 m_source = aSource;
356}
357
358
360{
361 m_length = 0;
362
363 for( ;; )
364 {
366 THROW_IO_ERROR( _( "Maximum line length exceeded" ) );
367
368 if( m_length + 1 > m_capacity )
370
371 // this read may fail, docs say to test LastRead() before trusting cc.
372 char cc = m_stream->GetC();
373
374 if( !m_stream->LastRead() )
375 break;
376
377 m_line[ m_length++ ] = cc;
378
379 if( cc == '\n' )
380 break;
381 }
382
383 m_line[ m_length ] = 0;
384
385 // m_lineNum is incremented even if there was no line read, because this
386 // leads to better error reporting when we hit an end of file.
387 ++m_lineNum;
388
389 return m_length ? m_line : nullptr;
390}
391
392
393//-----<OUTPUTFORMATTER>----------------------------------------------------
394
395// factor out a common GetQuoteChar
396
397const char* OUTPUTFORMATTER::GetQuoteChar( const char* wrapee, const char* quote_char )
398{
399 // Include '#' so a symbol is not confused with a comment. We intend
400 // to wrap any symbol starting with a '#'.
401 // Our LEXER class handles comments, and comments appear to be an extension
402 // to the SPECCTRA DSN specification.
403 if( *wrapee == '#' )
404 return quote_char;
405
406 if( strlen( wrapee ) == 0 )
407 return quote_char;
408
409 bool isFirst = true;
410
411 for( ; *wrapee; ++wrapee, isFirst = false )
412 {
413 static const char quoteThese[] = "\t ()"
414 "%" // per Alfons of freerouting.net, he does not like this unquoted as of 1-Feb-2008
415 "{}" // guessing that these are problems too
416 ;
417
418 // if the string to be wrapped (wrapee) has a delimiter in it,
419 // return the quote_char so caller wraps the wrapee.
420 if( strchr( quoteThese, *wrapee ) )
421 return quote_char;
422
423 if( !isFirst && '-' == *wrapee )
424 return quote_char;
425 }
426
427 return ""; // caller does not need to wrap, can use an unwrapped string.
428}
429
430
431const char* OUTPUTFORMATTER::GetQuoteChar( const char* wrapee ) const
432{
433 return GetQuoteChar( wrapee, quoteChar );
434}
435
436
437int OUTPUTFORMATTER::vprint( const char* fmt, va_list ap )
438{
439 // This function can call vsnprintf twice.
440 // But internally, vsnprintf retrieves arguments from the va_list identified by arg as if
441 // va_arg was used on it, and thus the state of the va_list is likely to be altered by the call.
442 // see: www.cplusplus.com/reference/cstdio/vsnprintf
443 // we make a copy of va_list ap for the second call, if happens
444 va_list tmp;
445 va_copy( tmp, ap );
446 int ret = vsnprintf( &m_buffer[0], m_buffer.size(), fmt, ap );
447
448 if( ret >= (int) m_buffer.size() )
449 {
450 m_buffer.resize( ret + 1000 );
451 ret = vsnprintf( &m_buffer[0], m_buffer.size(), fmt, tmp );
452 }
453
454 va_end( tmp ); // Release the temporary va_list, initialised from ap
455
456 if( ret > 0 )
457 write( &m_buffer[0], ret );
458
459 return ret;
460}
461
462
463int OUTPUTFORMATTER::sprint( const char* fmt, ... )
464{
465 va_list args;
466
467 va_start( args, fmt );
468 int ret = vprint( fmt, args);
469 va_end( args );
470
471 return ret;
472}
473
474
475int OUTPUTFORMATTER::Print( int nestLevel, const char* fmt, ... )
476{
477#define NESTWIDTH 2
478
479 va_list args;
480
481 va_start( args, fmt );
482
483 int result = 0;
484 int total = 0;
485
486 for( int i = 0; i < nestLevel; ++i )
487 {
488 // no error checking needed, an exception indicates an error.
489 result = sprint( "%*c", NESTWIDTH, ' ' );
490
491 total += result;
492 }
493
494 // no error checking needed, an exception indicates an error.
495 result = vprint( fmt, args );
496
497 va_end( args );
498
499 total += result;
500 return total;
501}
502
503
504std::string OUTPUTFORMATTER::Quotes( const std::string& aWrapee ) const
505{
506 std::string ret;
507
508 ret.reserve( aWrapee.size() * 2 + 2 );
509
510 ret += '"';
511
512 for( std::string::const_iterator it = aWrapee.begin(); it != aWrapee.end(); ++it )
513 {
514 switch( *it )
515 {
516 case '\n':
517 ret += '\\';
518 ret += 'n';
519 break;
520 case '\r':
521 ret += '\\';
522 ret += 'r';
523 break;
524 case '\\':
525 ret += '\\';
526 ret += '\\';
527 break;
528 case '"':
529 ret += '\\';
530 ret += '"';
531 break;
532 default:
533 ret += *it;
534 }
535 }
536
537 ret += '"';
538
539 return ret;
540}
541
542
543std::string OUTPUTFORMATTER::Quotew( const wxString& aWrapee ) const
544{
545 // wxStrings are always encoded as UTF-8 as we convert to a byte sequence.
546 // The non-virtual function calls the virtual workhorse function, and if
547 // a different quoting or escaping strategy is desired from the standard,
548 // a derived class can overload Quotes() above, but
549 // should never be a reason to overload this Quotew() here.
550 return Quotes( (const char*) aWrapee.utf8_str() );
551}
552
553
554//-----<STRING_FORMATTER>----------------------------------------------------
555
556void STRING_FORMATTER::write( const char* aOutBuf, int aCount )
557{
558 m_mystring.append( aOutBuf, aCount );
559}
560
562{
563 std::string copy = m_mystring;
564
565 m_mystring.clear();
566
567 for( std::string::iterator i = copy.begin(); i != copy.end(); ++i )
568 {
569 if( !isspace( *i ) && *i != ')' && *i != '(' && *i != '"' )
570 {
571 m_mystring += *i;
572 }
573 }
574}
575
576
577FILE_OUTPUTFORMATTER::FILE_OUTPUTFORMATTER( const wxString& aFileName, const wxChar* aMode,
578 char aQuoteChar ):
579 OUTPUTFORMATTER( OUTPUTFMTBUFZ, aQuoteChar ),
580 m_filename( aFileName )
581{
582 m_fp = wxFopen( aFileName, aMode );
583
584 if( !m_fp )
585 THROW_IO_ERROR( strerror( errno ) );
586}
587
588
590{
591 if( m_fp )
592 fclose( m_fp );
593}
594
595
596void FILE_OUTPUTFORMATTER::write( const char* aOutBuf, int aCount )
597{
598 if( fwrite( aOutBuf, (unsigned) aCount, 1, m_fp ) != 1 )
599 THROW_IO_ERROR( strerror( errno ) );
600}
601
602
603void STREAM_OUTPUTFORMATTER::write( const char* aOutBuf, int aCount )
604{
605 int lastWrite;
606
607 // This might delay awhile if you were writing to say a socket, but for
608 // a file it should only go through the loop once.
609 for( int total = 0; total<aCount; total += lastWrite )
610 {
611 lastWrite = m_os.Write( aOutBuf, aCount ).LastWrite();
612
613 if( !m_os.IsOk() )
614 {
615 THROW_IO_ERROR( _( "OUTPUTSTREAM_OUTPUTFORMATTER write error" ) );
616 }
617 }
618}
619
A LINE_READER that reads from an open file.
Definition: richio.h:185
~FILE_LINE_READER()
May or may not close the open file, depending on doOwn in constructor.
Definition: richio.cpp:238
FILE_LINE_READER(const wxString &aFileName, unsigned aStartingLineNumber=0, unsigned aMaxLineLength=LINE_READER_LINE_DEFAULT_MAX)
Take aFileName and the size of the desired line buffer and opens the file and assumes the obligation ...
Definition: richio.cpp:209
FILE * m_fp
I may own this file, but might not.
Definition: richio.h:245
char * ReadLine() override
Read a line of text into the buffer and increments the line number counter.
Definition: richio.cpp:261
bool m_iOwn
if I own the file, I'll promise to close it, else not.
Definition: richio.h:244
long int FileLength()
Definition: richio.cpp:245
long int CurPos()
Definition: richio.cpp:255
FILE * m_fp
takes ownership
Definition: richio.h:488
FILE_OUTPUTFORMATTER(const wxString &aFileName, const wxChar *aMode=wxT("wt"), char aQuoteChar='"' )
Definition: richio.cpp:577
void write(const char *aOutBuf, int aCount) override
Should be coded in the interface implementation (derived) classes.
Definition: richio.cpp:596
wxInputStream * m_stream
Definition: richio.h:300
INPUTSTREAM_LINE_READER(wxInputStream *aStream, const wxString &aSource)
Construct a LINE_READER from a wxInputStream object.
Definition: richio.cpp:350
char * ReadLine() override
Read a line of text into the buffer and increments the line number counter.
Definition: richio.cpp:359
An abstract class from which implementation specific LINE_READERs may be derived to read single lines...
Definition: richio.h:93
LINE_READER(unsigned aMaxLineLength=LINE_READER_LINE_DEFAULT_MAX)
Build a line reader and fixes the length of the maximum supported line length to aMaxLineLength.
Definition: richio.cpp:153
unsigned m_maxLineLength
maximum allowed capacity using resizing.
Definition: richio.h:173
unsigned m_length
no. bytes in line before trailing nul.
Definition: richio.h:167
unsigned m_capacity
no. bytes allocated for line.
Definition: richio.h:171
void expandCapacity(unsigned aNewsize)
Will expand the capacity of line up to maxLineLength but not greater, so be careful about making assu...
Definition: richio.cpp:182
char * m_line
the read line of UTF8 text
Definition: richio.h:170
unsigned m_lineNum
Definition: richio.h:168
virtual ~LINE_READER()
Definition: richio.cpp:176
wxString m_source
origin of text lines, e.g. filename or "clipboard"
Definition: richio.h:175
char * Line() const
Return a pointer to the last line that was read in.
Definition: richio.h:129
An interface used to output 8 bit text in a convenient way.
Definition: richio.h:322
virtual void write(const char *aOutBuf, int aCount)=0
Should be coded in the interface implementation (derived) classes.
int sprint(const char *fmt,...)
Definition: richio.cpp:463
std::vector< char > m_buffer
Definition: richio.h:412
char quoteChar[2]
Definition: richio.h:413
int vprint(const char *fmt, va_list ap)
Definition: richio.cpp:437
std::string Quotew(const wxString &aWrapee) const
Definition: richio.cpp:543
int PRINTF_FUNC Print(int nestLevel, const char *fmt,...)
Format and write text to the output stream.
Definition: richio.cpp:475
static const char * GetQuoteChar(const char *wrapee, const char *quote_char)
Perform quote character need determination according to the Specctra DSN specification.
Definition: richio.cpp:397
virtual std::string Quotes(const std::string &aWrapee) const
Check aWrapee input string for a need to be quoted (e.g.
Definition: richio.cpp:504
void write(const char *aOutBuf, int aCount) override
Should be coded in the interface implementation (derived) classes.
Definition: richio.cpp:603
wxOutputStream & m_os
Definition: richio.h:500
void write(const char *aOutBuf, int aCount) override
Should be coded in the interface implementation (derived) classes.
Definition: richio.cpp:556
void StripUseless()
Removes whitespace, '(', and ')' from the string.
Definition: richio.cpp:561
std::string m_mystring
Definition: richio.h:459
Is a LINE_READER that reads from a multiline 8 bit wide std::string.
Definition: richio.h:253
std::string m_lines
Definition: richio.h:255
STRING_LINE_READER(const std::string &aString, const wxString &aSource)
Construct a string line reader.
Definition: richio.cpp:295
char * ReadLine() override
Read a line of text into the buffer and increments the line number counter.
Definition: richio.cpp:318
#define _(s)
void ignore_unused(const T &)
Definition: ignore.h:24
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38
FILE * SeqFOpen(const wxString &aPath, const wxString &mode)
Opens the file like fopen but sets flags (if available) for sequential read hinting.
Definition: gtk/io.cpp:29
static int vprint(std::string *result, const char *format, va_list ap)
Definition: richio.cpp:49
#define NESTWIDTH
#define getc_unlocked
Definition: richio.cpp:44
int StrPrintf(std::string *result, const char *format,...)
This is like sprintf() but the output is appended to a std::string instead of to a character array.
Definition: richio.cpp:85
wxString SafeReadFile(const wxString &aFilePath, const wxString &aReadType)
Nominally opens a file and reads it into a string.
Definition: richio.cpp:110
#define OUTPUTFMTBUFZ
default buffer size for any OUTPUT_FORMATTER
Definition: richio.h:304
#define LINE_READER_LINE_INITIAL_SIZE
Definition: richio.h:86
#define LINE_READER_LINE_DEFAULT_MAX
Definition: richio.h:85