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 The 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, see <https://www.gnu.org/licenses/>.
19 */
20
21
22#include <cstdarg>
23#include <config.h> // HAVE_FGETC_NOLOCK
24
25#include <kiplatform/io.h>
26#include <core/ignore.h>
27#include <richio.h>
28#include <errno.h>
29#include <string.h>
30#include <advanced_config.h>
32
33#include <wx/filename.h>
34#include <wx/translation.h>
35#include <wx/ffile.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
42// getc is not a macro on windows and adds a tiny overhead for the indirection to eventually
43// calling fgetc
44#define getc_unlocked _fgetc_nolock
45#else
46#define getc_unlocked getc
47#endif
48#endif
49
50
51wxString SafeReadFile( const wxString& aFilePath, const wxString& aReadType )
52{
53 // Check the path exists as a file first
54 // the IsOpened check would be logical, but on linux you can fopen (in read mode) a directory
55 // And then everything else in here will barf
56 if( !wxFileExists( aFilePath ) )
57 THROW_IO_ERRORF( _( "File '%s' does not exist." ), aFilePath );
58
59 wxString contents;
60 wxFFile ff( aFilePath );
61
62 if( !ff.IsOpened() )
63 THROW_IO_ERRORF( _( "Cannot open file '%s'." ), aFilePath );
64
65 // Try to determine encoding
66 char bytes[2]{ 0 };
67 ff.Read( bytes, 2 );
68 bool utf16le = bytes[1] == 0;
69
70 ff.Seek( 0 );
71
72 bool readOk = false;
73
74 if( utf16le )
75 readOk = ff.ReadAll( &contents, wxMBConvUTF16LE() );
76 else
77 readOk = ff.ReadAll( &contents, wxMBConvUTF8() );
78
79 if( !readOk || contents.empty() )
80 {
81 ff.Seek( 0 );
82 ff.ReadAll( &contents, wxConvAuto( wxFONTENCODING_CP1252 ) );
83 }
84
85 if( contents.empty() )
86 THROW_IO_ERRORF( _( "Unable to read file '%s'." ), aFilePath );
87
88 // I'm not sure what the source of this style of line-endings is, but it can be
89 // found in some Fairchild Semiconductor SPICE files.
90 contents.Replace( wxS( "\r\r\n" ), wxS( "\n" ) );
91
92 return contents;
93}
94
95
96//-----<LINE_READER>------------------------------------------------------
97
98LINE_READER::LINE_READER( unsigned aMaxLineLength ) :
99 m_length( 0 ), m_lineNum( 0 ), m_line( nullptr ),
100 m_capacity( 0 ), m_maxLineLength( aMaxLineLength )
101{
102 if( aMaxLineLength != 0 )
103 {
104 // start at the INITIAL size, expand as needed up to the MAX size in maxLineLength
106
107 // but never go above user's aMaxLineLength, and leave space for trailing nul
108 if( m_capacity > aMaxLineLength+1 )
109 m_capacity = aMaxLineLength+1;
110
111 // Be sure there is room for a null EOL char, so reserve at least capacity+1 bytes
112 // to ensure capacity line length and avoid corner cases
113 // Use capacity+5 to cover and corner case
114 m_line = new char[m_capacity+5];
115
116 m_line[0] = '\0';
117 }
118}
119
120
122{
123 delete[] m_line;
124}
125
126
127void LINE_READER::expandCapacity( unsigned aNewsize )
128{
129 // m_length can equal maxLineLength and nothing breaks, there's room for
130 // the terminating nul. cannot go over this.
131 if( aNewsize > m_maxLineLength+1 )
132 aNewsize = m_maxLineLength+1;
133
134 if( aNewsize > m_capacity )
135 {
136 m_capacity = aNewsize;
137
138 // resize the buffer, and copy the original data
139 // Be sure there is room for the null EOL char, so reserve capacity+1 bytes
140 // to ensure capacity line length. Use capacity+5 to cover and corner case
141 char* bigger = new char[m_capacity+5];
142
143 wxASSERT( m_capacity >= m_length+1 );
144
145 memcpy( bigger, m_line, m_length );
146 bigger[m_length] = 0;
147
148 delete[] m_line;
149 m_line = bigger;
150 }
151}
152
153
154FILE_LINE_READER::FILE_LINE_READER( const wxString& aFileName, unsigned aStartingLineNumber,
155 unsigned aMaxLineLength ):
156 LINE_READER( aMaxLineLength ), m_iOwn( true )
157{
158 m_fp = KIPLATFORM::IO::SeqFOpen( aFileName, wxT( "rt" ) );
159
160 if( !m_fp )
161 THROW_IO_ERRORF( _( "Unable to open %s for reading." ), aFileName.GetData() );
162
163 m_source = aFileName;
164 m_lineNum = aStartingLineNumber;
165}
166
167
168FILE_LINE_READER::FILE_LINE_READER( FILE* aFile, const wxString& aFileName,
169 bool doOwn,
170 unsigned aStartingLineNumber,
171 unsigned aMaxLineLength ) :
172 LINE_READER( aMaxLineLength ), m_iOwn( doOwn ), m_fp( aFile )
173{
174 m_source = aFileName;
175 m_lineNum = aStartingLineNumber;
176}
177
178
180{
181 if( m_iOwn && m_fp )
182 fclose( m_fp );
183}
184
185
187{
188 fseek( m_fp, 0, SEEK_END );
189 long int fileLength = ftell( m_fp );
190 rewind( m_fp );
191
192 return fileLength;
193}
194
195
197{
198 return ftell( m_fp );
199}
200
201
203{
204 m_length = 0;
205
206 for( ;; )
207 {
209 THROW_IO_ERROR( _( "Maximum line length exceeded" ) );
210
211 if( m_length >= m_capacity )
213
214 // faster, POSIX compatible fgetc(), no locking.
215 int cc = getc_unlocked( m_fp );
216
217 if( cc == EOF )
218 break;
219
220 m_line[ m_length++ ] = (char) cc;
221
222 if( cc == '\n' )
223 break;
224 }
225
226 m_line[ m_length ] = 0;
227
228 // m_lineNum is incremented even if there was no line read, because this
229 // leads to better error reporting when we hit an end of file.
230 ++m_lineNum;
231
232 return m_length ? m_line : nullptr;
233}
234
235
236STRING_LINE_READER::STRING_LINE_READER( const std::string& aString, const wxString& aSource ):
238 m_lines( aString ), m_ndx( 0 )
239{
240 // Clipboard text should be nice and _use multiple lines_ so that
241 // we can report _line number_ oriented error messages when parsing.
242 m_source = aSource;
243}
244
245
248 m_lines( aStartingPoint.m_lines ),
249 m_ndx( aStartingPoint.m_ndx )
250{
251 // since we are keeping the same "source" name, for error reporting purposes
252 // we need to have the same notion of line number and offset.
253
254 m_source = aStartingPoint.m_source;
255 m_lineNum = aStartingPoint.m_lineNum;
256}
257
258
260{
261 size_t nlOffset = m_lines.find( '\n', m_ndx );
262 unsigned new_length;
263
264 if( nlOffset == std::string::npos )
265 new_length = m_lines.length() - m_ndx;
266 else
267 new_length = nlOffset - m_ndx + 1; // include the newline, so +1
268
269 if( new_length )
270 {
271 if( new_length >= m_maxLineLength )
272 THROW_IO_ERROR( _("Line length exceeded") );
273
274 if( new_length+1 > m_capacity ) // +1 for terminating nul
275 expandCapacity( new_length+1 );
276
277 wxASSERT( m_ndx + new_length <= m_lines.length() );
278
279 memcpy( m_line, &m_lines[m_ndx], new_length );
280 m_ndx += new_length;
281 }
282
283 m_length = new_length;
284 ++m_lineNum; // this gets incremented even if no bytes were read
285 m_line[m_length] = 0;
286
287 return m_length ? m_line : nullptr;
288}
289
290
292 const wxString& aSource ) :
294 m_stream( aStream )
295{
296 m_source = aSource;
297}
298
299
301{
302 m_length = 0;
303
304 for( ;; )
305 {
307 THROW_IO_ERROR( _( "Maximum line length exceeded" ) );
308
309 if( m_length + 1 > m_capacity )
311
312 // this read may fail, docs say to test LastRead() before trusting cc.
313 char cc = m_stream->GetC();
314
315 if( !m_stream->LastRead() )
316 break;
317
318 m_line[ m_length++ ] = cc;
319
320 if( cc == '\n' )
321 break;
322 }
323
324 m_line[ m_length ] = 0;
325
326 // m_lineNum is incremented even if there was no line read, because this
327 // leads to better error reporting when we hit an end of file.
328 ++m_lineNum;
329
330 return m_length ? m_line : nullptr;
331}
332
333
334//-----<OUTPUTFORMATTER>----------------------------------------------------
335
336// factor out a common GetQuoteChar
337
338const char* OUTPUTFORMATTER::GetQuoteChar( const char* wrapee, const char* quote_char )
339{
340 // Include '#' so a symbol is not confused with a comment. We intend
341 // to wrap any symbol starting with a '#'.
342 // Our LEXER class handles comments, and comments appear to be an extension
343 // to the SPECCTRA DSN specification.
344 if( *wrapee == '#' )
345 return quote_char;
346
347 if( strlen( wrapee ) == 0 )
348 return quote_char;
349
350 bool isFirst = true;
351
352 for( ; *wrapee; ++wrapee, isFirst = false )
353 {
354 static const char quoteThese[] = "\t ()"
355 "%" // per Alfons of freerouting.net, he does not like this unquoted as of 1-Feb-2008
356 "{}" // guessing that these are problems too
357 ;
358
359 // if the string to be wrapped (wrapee) has a delimiter in it,
360 // return the quote_char so caller wraps the wrapee.
361 if( strchr( quoteThese, *wrapee ) )
362 return quote_char;
363
364 if( !isFirst && '-' == *wrapee )
365 return quote_char;
366 }
367
368 return ""; // caller does not need to wrap, can use an unwrapped string.
369}
370
371
372const char* OUTPUTFORMATTER::GetQuoteChar( const char* wrapee ) const
373{
374 return GetQuoteChar( wrapee, quoteChar );
375}
376
377
378int OUTPUTFORMATTER::vprint( const char* fmt, va_list ap )
379{
380 // This function can call vsnprintf twice.
381 // But internally, vsnprintf retrieves arguments from the va_list identified by arg as if
382 // va_arg was used on it, and thus the state of the va_list is likely to be altered by the call.
383 // see: www.cplusplus.com/reference/cstdio/vsnprintf
384 // we make a copy of va_list ap for the second call, if happens
385 va_list tmp;
386 va_copy( tmp, ap );
387 int ret = vsnprintf( &m_buffer[0], m_buffer.size(), fmt, ap );
388
389 if( ret >= (int) m_buffer.size() )
390 {
391 m_buffer.resize( ret + 1000 );
392 ret = vsnprintf( &m_buffer[0], m_buffer.size(), fmt, tmp );
393 }
394
395 va_end( tmp ); // Release the temporary va_list, initialised from ap
396
397 if( ret > 0 )
398 write( &m_buffer[0], ret );
399
400 return ret;
401}
402
403
404int OUTPUTFORMATTER::sprint( const char* fmt, ... )
405{
406 va_list args;
407
408 va_start( args, fmt );
409 int ret = vprint( fmt, args );
410 va_end( args );
411
412 return ret;
413}
414
415
416int OUTPUTFORMATTER::Indent( int aNestLevel )
417{
418#define NESTWIDTH 2
419
420 int total = 0;
421
422 for( int i = 0; i < aNestLevel; ++i )
423 {
424 // no error checking needed, an exception indicates an error.
425 total += sprint( "%*c", NESTWIDTH, ' ' );
426 }
427
428 return total;
429}
430
431
432int OUTPUTFORMATTER::Print( int nestLevel, const char* fmt, ... )
433{
434 va_list args;
435
436 va_start( args, fmt );
437
438 int total = Indent( nestLevel );
439
440 // no error checking needed, an exception indicates an error.
441 total += vprint( fmt, args );
442
443 va_end( args );
444
445 return total;
446}
447
448
449int OUTPUTFORMATTER::Print( const char* fmt, ... )
450{
451 va_list args;
452
453 va_start( args, fmt );
454
455 int result = 0;
456
457 // no error checking needed, an exception indicates an error.
458 result = vprint( fmt, args );
459
460 va_end( args );
461
462 return result;
463}
464
465
466std::string OUTPUTFORMATTER::Quotes( const std::string& aWrapee ) const
467{
468 std::string ret;
469
470 ret.reserve( aWrapee.size() * 2 + 2 );
471
472 ret += '"';
473
474 for( std::string::const_iterator it = aWrapee.begin(); it != aWrapee.end(); ++it )
475 {
476 switch( *it )
477 {
478 case '\n':
479 ret += '\\';
480 ret += 'n';
481 break;
482 case '\r':
483 ret += '\\';
484 ret += 'r';
485 break;
486 case '\\':
487 ret += '\\';
488 ret += '\\';
489 break;
490 case '"':
491 ret += '\\';
492 ret += '"';
493 break;
494 default:
495 ret += *it;
496 }
497 }
498
499 ret += '"';
500
501 return ret;
502}
503
504
505std::string OUTPUTFORMATTER::Quotew( const wxString& aWrapee ) const
506{
507 // wxStrings are always encoded as UTF-8 as we convert to a byte sequence.
508 // The non-virtual function calls the virtual workhorse function, and if
509 // a different quoting or escaping strategy is desired from the standard,
510 // a derived class can overload Quotes() above, but
511 // should never be a reason to overload this Quotew() here.
512 return Quotes( (const char*) aWrapee.utf8_str() );
513}
514
515
516//-----<STRING_FORMATTER>----------------------------------------------------
517
518void STRING_FORMATTER::write( const char* aOutBuf, int aCount )
519{
520 m_mystring.append( aOutBuf, aCount );
521}
522
523
525{
526 std::string copy = m_mystring;
527
528 m_mystring.clear();
529
530 for( std::string::iterator i = copy.begin(); i != copy.end(); ++i )
531 {
532 if( !isspace( *i ) && *i != ')' && *i != '(' && *i != '"' )
533 {
534 m_mystring += *i;
535 }
536 }
537}
538
539
552{
553public:
554 SIBLING_TEMP_FILE( const wxString& aTargetPath, const wxChar* aMode ) :
555 m_targetPath( aTargetPath )
556 {
557 wxString err;
558
560
561 if( !m_fp )
562 THROW_IO_ERROR( err );
563
564 wxASSERT( !m_tempPath.IsEmpty() );
565 }
566
571
573 {
574 if( m_committed )
575 return;
576
577 Abandon();
578
579 // CommitTempFile() can fail after the rename has already moved the temp onto
580 // the target (directory fsync error), so the temp may already be gone here.
581 // Only remove what is still present, or wxRemoveFile reports an ENOENT error
582 // for an already-clean state.
583 if( !m_tempPath.IsEmpty() && wxFileExists( m_tempPath ) )
584 wxRemoveFile( m_tempPath );
585 }
586
588 FILE* File() { return m_fp; }
589
591 const wxString& Path() const { return m_tempPath; }
592
607 {
608 int ret = 0;
609
610 if( m_fp )
611 {
612 ret = fclose( m_fp );
613 m_fp = nullptr;
614 }
615
616 return ret;
617 }
618
633 bool Commit()
634 {
635 wxCHECK_MSG( m_fp, false, wxT( "Commit() called on an already-used temp file (committed or abandoned)" ) );
636
638 {
639 int err = errno;
640
641 // We're already failing, so we don't care if Abandon()'s own close also
642 // fails (e.g. on NFS); the flush error below is the one to report.
643 Abandon();
644
645 THROW_IO_ERRORF( _( "Cannot flush '%s' to disk: %s" ), m_tempPath,
646 wxString::FromUTF8( strerror( err ) ) );
647 }
648
649 if( Abandon() != 0 )
650 {
651 int err = errno;
652 THROW_IO_ERRORF( _( "Cannot close '%s': %s" ), m_tempPath, wxString::FromUTF8( strerror( err ) ) );
653 }
654
655 wxString commitError;
656
658 THROW_IO_ERROR( commitError );
659
660 m_committed = true;
661 return true;
662 }
663
664private:
665 wxString m_targetPath;
666 wxString m_tempPath;
667 FILE* m_fp = nullptr;
668 bool m_committed = false;
669};
670
671
672FILE_OUTPUTFORMATTER::FILE_OUTPUTFORMATTER( const wxString& aFileName, const wxChar* aMode, char aQuoteChar ) :
673 OUTPUTFORMATTER( OUTPUTFMTBUFZ, aQuoteChar ),
674 m_tempFile( std::make_unique<SIBLING_TEMP_FILE>( KIPLATFORM::IO::ResolveSymlinkTarget( aFileName ), aMode ) )
675{
676}
677
678
680
681
683{
684 return m_tempFile->Commit();
685}
686
687
688void FILE_OUTPUTFORMATTER::write( const char* aOutBuf, int aCount )
689{
690 if( fwrite( aOutBuf, (unsigned) aCount, 1, m_tempFile->File() ) != 1 )
691 THROW_IO_ERROR( strerror( errno ) );
692}
693
694
696 KICAD_FORMAT::FORMAT_MODE aFormatMode,
697 const wxChar* aMode, char aQuoteChar ) :
698 OUTPUTFORMATTER( OUTPUTFMTBUFZ, aQuoteChar ),
699 m_tempFile( std::make_unique<SIBLING_TEMP_FILE>( KIPLATFORM::IO::ResolveSymlinkTarget( aFileName ), aMode ) ),
700 m_mode( aFormatMode )
701{
702 if( ADVANCED_CFG::GetCfg().m_CompactSave && m_mode == KICAD_FORMAT::FORMAT_MODE::NORMAL )
703 m_mode = KICAD_FORMAT::FORMAT_MODE::COMPACT_TEXT_PROPERTIES;
704}
705
706
708
709
711{
712 if( m_tempFile->File() )
713 {
715
716 if( !m_buf.empty() && fwrite( m_buf.c_str(), m_buf.length(), 1, m_tempFile->File() ) != 1 )
717 {
718 int err = errno;
719
720 // Abandon the temp so a mistaken second Finish() cannot flush and persist a
721 // partial file to the target. The destructor discards the file.
722 m_tempFile->Abandon();
723
724 THROW_IO_ERRORF( _( "Write failed to '%s': %s" ), m_tempFile->Path(),
725 wxString::FromUTF8( strerror( err ) ) );
726 }
727 }
728
729 return m_tempFile->Commit();
730}
731
732
733void PRETTIFIED_FILE_OUTPUTFORMATTER::write( const char* aOutBuf, int aCount )
734{
735 m_buf.append( aOutBuf, aCount );
736}
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
~FILE_LINE_READER()
May or may not close the open file, depending on doOwn in constructor.
Definition richio.cpp:179
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:154
FILE * m_fp
I may own this file, but might not.
Definition richio.h:217
char * ReadLine() override
Read a line of text into the buffer and increments the line number counter.
Definition richio.cpp:202
bool m_iOwn
if I own the file, I'll promise to close it, else not.
Definition richio.h:216
long int FileLength()
Definition richio.cpp:186
long int CurPos()
Definition richio.cpp:196
std::unique_ptr< SIBLING_TEMP_FILE > m_tempFile
Definition richio.h:518
FILE_OUTPUTFORMATTER(const wxString &aFileName, const wxChar *aMode=wxT("wt"), char aQuoteChar='"' )
Definition richio.cpp:672
void write(const char *aOutBuf, int aCount) override
sibling temp file, committed by Finish()
Definition richio.cpp:688
bool Finish() override
Flushes the temp file to disk and atomically renames it over the final target path.
Definition richio.cpp:682
wxInputStream * m_stream
The input stream to read. No ownership of this pointer.
Definition richio.h:272
INPUTSTREAM_LINE_READER(wxInputStream *aStream, const wxString &aSource)
Construct a LINE_READER from a wxInputStream object.
Definition richio.cpp:291
char * ReadLine() override
Read a line of text into the buffer and increments the line number counter.
Definition richio.cpp:300
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:98
unsigned m_maxLineLength
maximum allowed capacity using resizing.
Definition richio.h:145
unsigned m_length
no. bytes in line before trailing nul.
Definition richio.h:139
unsigned m_capacity
no. bytes allocated for line.
Definition richio.h:143
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:127
char * m_line
the read line of UTF8 text
Definition richio.h:142
unsigned m_lineNum
Definition richio.h:140
virtual ~LINE_READER()
Definition richio.cpp:121
wxString m_source
origin of text lines, e.g. filename or "clipboard"
Definition richio.h:147
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:404
int Indent(int aNestLevel)
Write the leading whitespace for a nesting level, with no other output.
Definition richio.cpp:416
std::vector< char > m_buffer
Definition richio.h:415
OUTPUTFORMATTER(int aReserve=OUTPUTFMTBUFZ, char aQuoteChar='"' )
Definition richio.h:296
char quoteChar[2]
Definition richio.h:416
int vprint(const char *fmt, va_list ap)
Definition richio.cpp:378
std::string Quotew(const wxString &aWrapee) const
Definition richio.cpp:505
int PRINTF_FUNC_N Print(int nestLevel, const char *fmt,...)
Format and write text to the output stream.
Definition richio.cpp:432
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:338
virtual std::string Quotes(const std::string &aWrapee) const
Check aWrapee input string for a need to be quoted (e.g.
Definition richio.cpp:466
void write(const char *aOutBuf, int aCount) override
Should be coded in the interface implementation (derived) classes.
Definition richio.cpp:733
std::unique_ptr< SIBLING_TEMP_FILE > m_tempFile
< sibling temp file, committed by Finish()
Definition richio.h:553
PRETTIFIED_FILE_OUTPUTFORMATTER(const wxString &aFileName, KICAD_FORMAT::FORMAT_MODE aFormatMode=KICAD_FORMAT::FORMAT_MODE::NORMAL, const wxChar *aMode=wxT("wt"), char aQuoteChar='"' )
Definition richio.cpp:695
bool Finish() override
Runs prettification over the buffered bytes, writes them to the sibling temp file,...
Definition richio.cpp:710
KICAD_FORMAT::FORMAT_MODE m_mode
Definition richio.h:555
A class that owns a sibling temp file, which is created next to the target at construction.
Definition richio.cpp:552
SIBLING_TEMP_FILE(const wxString &aTargetPath, const wxChar *aMode)
Definition richio.cpp:554
SIBLING_TEMP_FILE & operator=(const SIBLING_TEMP_FILE &)=delete
Ditto for assignment: the temp file cannot be shared.
const wxString & Path() const
The temp file's path on disk.
Definition richio.cpp:591
wxString m_targetPath
Definition richio.cpp:665
bool Commit()
Flush, close and atomically rename the temp file over the target.
Definition richio.cpp:633
int Abandon()
Abandons the in-progress save: closes the temp file handle without committing, leaving the file on di...
Definition richio.cpp:606
wxString m_tempPath
Definition richio.cpp:666
FILE * File()
The open temp file to write to. Null once Commit() or Abandon() has run.
Definition richio.cpp:588
SIBLING_TEMP_FILE(const SIBLING_TEMP_FILE &)=delete
Copy is meaningless: the temp file cannot be shared.
void write(const char *aOutBuf, int aCount) override
Should be coded in the interface implementation (derived) classes.
Definition richio.cpp:518
void StripUseless()
Removes whitespace, '(', and ')' from the string.
Definition richio.cpp:524
std::string m_mystring
Definition richio.h:467
std::string m_lines
Definition richio.h:227
STRING_LINE_READER(const std::string &aString, const wxString &aSource)
Construct a string line reader.
Definition richio.cpp:236
char * ReadLine() override
Read a line of text into the buffer and increments the line number counter.
Definition richio.cpp:259
#define _(s)
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
#define THROW_IO_ERRORF(msg,...)
void Prettify(std::string &aSource, FORMAT_MODE aMode)
Pretty-prints s-expression text according to KiCad format rules.
FILE * SeqFOpen(const wxString &aPath, const wxString &mode)
Opens the file like fopen but sets flags (if available) for sequential read hinting.
Definition unix/io.cpp:39
FILE * OpenUniqueSiblingTempFile(const wxString &aTargetPath, const wxString &aMode, wxString *aTempPathOut, wxString *aError=nullptr)
Opens a fresh sibling temp file next to aTargetPath with exclusive-create semantics (POSIX O_CREAT|O_...
Definition common/io.cpp:67
bool CommitTempFile(const wxString &aTempPath, const wxString &aTargetPath, wxString *aError=nullptr)
Completes an atomic save.
bool FlushToDisk(FILE *aFp)
Flushes user-space buffers for aFp and forces the kernel/filesystem to commit the file's data blocks ...
Definition unix/io.cpp:182
STL namespace.
#define NESTWIDTH
#define getc_unlocked
Definition richio.cpp:46
wxString SafeReadFile(const wxString &aFilePath, const wxString &aReadType)
Nominally opens a file and reads it into a string.
Definition richio.cpp:51
#define OUTPUTFMTBUFZ
default buffer size for any OUTPUT_FORMATTER
Definition richio.h:276
#define LINE_READER_LINE_INITIAL_SIZE
Definition richio.h:58
#define LINE_READER_LINE_DEFAULT_MAX
Definition richio.h:57
wxString result
Test unit parsing edge cases and error handling.