1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2007-2010 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
5  * Copyright (C) 2016-2020 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 #ifndef RICHIO_H_
26 #define RICHIO_H_
27 
28 // This file defines 3 classes useful for working with DSN text files and is named
29 // "richio" after its author, Richard Hollenbeck, aka Dick Hollenbeck.
30 
31 
32 #include <vector>
33 #include <utf8.h>
34 
35 // I really did not want to be dependent on wxWidgets in richio
36 // but the errorText needs to be wide char so wxString rules.
37 #include <cstdio>
38 #include <wx/string.h>
39 #include <wx/stream.h>
40 
41 #include <ki_exception.h>
42 
43 
44 /**
45  * This is like sprintf() but the output is appended to a std::string instead of to a
46  * character array.
47  *
48  * @param aResult is the string to append to, previous text is not clear()ed.
49  * @param aFormat is a printf() style format string.
50  * @return the count of bytes appended to the result string, no terminating nul is included.
51  */
52 int
53 #if defined(__GNUG__)
54     __attribute__ ((format (printf, 2, 3)))
55 #endif
56     StrPrintf( std::string* aResult, const char* aFormat, ... );
57 
58 
59 /**
60  * This is like sprintf() but the output is returned in a std::string instead of to a
61  * character array.
62  *
63  * @param format is a printf() style format string.
64  * @return std::string - the result of the sprintf().
65  */
66 std::string
67 #if defined(__GNUG__)
68     __attribute__ ((format (printf, 1, 2)))
69 #endif
70     StrPrintf( const char* format, ... );
71 
72 
73 #define LINE_READER_LINE_DEFAULT_MAX        1000000
74 #define LINE_READER_LINE_INITIAL_SIZE       5000
75 
76 /**
77  * An abstract class from which implementation specific LINE_READERs may be derived to
78  * read single lines of text and manage a line number counter.
79  */
80 class LINE_READER
81 {
82 public:
83 
84     /**
85      * Build a line reader and fixes the length of the maximum supported line length
86      * to @a aMaxLineLength.
87      */
88     LINE_READER( unsigned aMaxLineLength = LINE_READER_LINE_DEFAULT_MAX );
89 
90     virtual ~LINE_READER();
91 
92     /**
93      * Read a line of text into the buffer and increments the line number counter.
94      *
95      * If the line is larger than the maximum length passed to the constructor, then an
96      * exception is thrown.  The line is nul terminated.
97      *
98      * @return The beginning of the read line, or NULL if EOF.
99      * @throw IO_ERROR when a line is too long.
100      */
101     virtual char* ReadLine() = 0;
102 
103     /**
104      * Returns the name of the source of the lines in an abstract sense.
105      *
106      * This may be a file or it may be the clipboard or any other source of lines of text.
107      * The returned string is useful for reporting error messages.
108      */
GetSource()109     virtual const wxString& GetSource() const
110     {
111         return m_source;
112     }
113 
114     /**
115      * Return a pointer to the last line that was read in.
116      */
Line()117     char* Line() const
118     {
119         return m_line;
120     }
121 
122     /**
123      * A casting operator that returns a char* pointer to the start of the line buffer.
124      */
125     operator char* () const
126     {
127         return Line();
128     }
129 
130     /**
131      * Return the line number of the last line read from this LINE_READER.
132      *
133      * Lines start from 1.
134      */
LineNumber()135     virtual unsigned LineNumber() const
136     {
137         return m_lineNum;
138     }
139 
140     /**
141      * Return the number of bytes in the last line read from this LINE_READER.
142      */
Length()143     unsigned Length() const
144     {
145         return m_length;
146     }
147 
148 protected:
149     /**
150      * Will expand the capacity of @a line up to maxLineLength but not greater, so
151      * be careful about making assumptions of @a capacity after calling this.
152      */
153     void        expandCapacity( unsigned aNewsize );
154 
155     unsigned    m_length;         ///< no. bytes in line before trailing nul.
156     unsigned    m_lineNum;
157 
158     char*       m_line;           ///< the read line of UTF8 text
159     unsigned    m_capacity;       ///< no. bytes allocated for line.
160 
161     unsigned    m_maxLineLength;  ///< maximum allowed capacity using resizing.
162 
163     wxString    m_source;         ///< origin of text lines, e.g. filename or "clipboard"
164 };
165 
166 
167 /**
168  * A LINE_READER that reads from an open file.
169  *
170  * File must be already open so that this class can exist without any UI policy.
171  */
172 class FILE_LINE_READER : public LINE_READER
173 {
174 public:
175     /**
176      * Take @a aFileName and the size of the desired line buffer and opens the file and
177      * assumes the obligation to close it.
178      *
179      * @param aFileName is the name of the file to open and to use for error reporting purposes.
180      * @param aStartingLineNumber is the initial line number to report on error, and is
181      *  accessible here for the case where multiple DSNLEXERs are reading from the
182      *  same file in sequence, all from the same open file (with @a doOwn = false).
183      *  Internally it is incremented by one after each ReadLine(), so the first
184      *  reported line number will always be one greater than what is provided here.
185      * @param aMaxLineLength is the number of bytes to use in the line buffer.
186      *
187      * @throw IO_ERROR if @a aFileName cannot be opened.
188      */
189     FILE_LINE_READER( const wxString& aFileName, unsigned aStartingLineNumber = 0,
190                       unsigned aMaxLineLength = LINE_READER_LINE_DEFAULT_MAX );
191 
192     /**
193      * Take an open FILE and the size of the desired line buffer and takes ownership of
194      * the open file, i.e. assumes the obligation to close it.
195      *
196      * @param aFile is an open file.
197      * @param aFileName is the name of the file for error reporting purposes.
198      * @param doOwn if true, means I should close the open file, else not.
199      * @param aStartingLineNumber is the initial line number to report on error, and is
200      *  accessible here for the case where multiple DSNLEXERs are reading from the
201      *  same file in sequence, all from the same open file (with @a doOwn = false).
202      *  Internally it is incremented by one after each ReadLine(), so the first
203      *  reported line number will always be one greater than what is provided here.
204      * @param aMaxLineLength is the number of bytes to use in the line buffer.
205      */
206     FILE_LINE_READER( FILE* aFile, const wxString& aFileName, bool doOwn = true,
207                       unsigned aStartingLineNumber = 0,
208                       unsigned aMaxLineLength = LINE_READER_LINE_DEFAULT_MAX );
209 
210     /**
211      * May or may not close the open file, depending on @a doOwn in constructor.
212      */
213     ~FILE_LINE_READER();
214 
215     char* ReadLine() override;
216 
217     /**
218      * Rewind the file and resets the line number back to zero.
219      *
220      * Line number will go to 1 on first ReadLine().
221      */
Rewind()222     void Rewind()
223     {
224         rewind( m_fp );
225         m_lineNum = 0;
226     }
227 
228     long int FileLength();
229     long int CurPos();
230 
231 protected:
232     bool    m_iOwn; ///< if I own the file, I'll promise to close it, else not.
233     FILE*   m_fp;   ///< I may own this file, but might not.
234 };
235 
236 
237 /**
238  * Is a #LINE_READER that reads from a multiline 8 bit wide std::string
239  */
240 class STRING_LINE_READER : public LINE_READER
241 {
242 protected:
243     std::string     m_lines;
244     size_t          m_ndx;
245 
246 public:
247 
248     /**
249      * Construct a string line reader.
250      *
251      * @param aString is a source string consisting of one or more lines
252      * of text, where multiple lines are separated with a '\n' character.
253      * The last line does not necessarily need a trailing '\n'.
254      * @param aSource describes the source of aString for error reporting purposes
255      *  can be anything meaningful, such as wxT( "clipboard" ).
256      */
257     STRING_LINE_READER( const std::string& aString, const wxString& aSource );
258 
259     /**
260      * Construct a string line reader.
261      *
262      * Allows for a continuation of the reading of a stream started by another
263      * STRING_LINE_READER.  Any stream offset and source name are used from
264      */
265     STRING_LINE_READER( const STRING_LINE_READER& aStartingPoint );
266 
267     char* ReadLine() override;
268 };
269 
270 
271 /**
272  * A #LINE_READER that reads from a wxInputStream object.
273  */
274 class INPUTSTREAM_LINE_READER : public LINE_READER
275 {
276 public:
277     /**
278      * Construct a #LINE_READER from a wxInputStream object.
279      *
280      * @param aStream A pointer to a wxInputStream object to read.
281      * @param aSource The name of the stream source, for error reporting purposes.
282      */
283     INPUTSTREAM_LINE_READER( wxInputStream* aStream, const wxString& aSource );
284 
285     char* ReadLine() override;
286 
287 protected:
288     wxInputStream* m_stream;   //< The input stream to read.  No ownership of this pointer.
289 };
290 
291 
292 #define OUTPUTFMTBUFZ    500        ///< default buffer size for any OUTPUT_FORMATTER
293 
294 /**
295  * An interface used to output 8 bit text in a convenient way.
296  *
297  * The primary interface is "printf() - like" but with support for indentation control.  The
298  * destination of the 8 bit wide text is up to the implementer.
299  * <p>
300  * The implementer only has to implement the write() function, but can also optionally
301  * re-implement GetQuoteChar().
302  * <p>
303  * If you want to output a wxString, then use TO_UTF8() on it before passing it as an
304  * argument to Print().
305  * <p>
306  * Since this is an abstract interface, only classes derived from this one may actually be
307  * used.
308  */
309 class OUTPUTFORMATTER
310 {
311 protected:
312     OUTPUTFORMATTER( int aReserve = OUTPUTFMTBUFZ, char aQuoteChar = '"' ) :
313             m_buffer( aReserve, '\0' )
314     {
315         quoteChar[0] = aQuoteChar;
316         quoteChar[1] = '\0';
317     }
318 
~OUTPUTFORMATTER()319     virtual ~OUTPUTFORMATTER() {}
320 
321     /**
322      * Perform quote character need determination according to the Specctra DSN specification.
323 
324      * @param wrapee A string that might need wrapping on each end.
325      * @param quote_char A single character C string which provides the current
326      *                   quote character, should it be needed by the wrapee.
327      *
328      * @return the quote_char as a single character string, or "" if the wrapee does not need
329      *         to be wrapped.
330      */
331     static const char* GetQuoteChar( const char* wrapee, const char* quote_char );
332 
333     /**
334      * Should be coded in the interface implementation (derived) classes.
335      *
336      * @param aOutBuf is the start of a byte buffer to write.
337      * @param aCount  tells how many bytes to write.
338      * @throw IO_ERROR, if there is a problem outputting, such as a full disk.
339      */
340     virtual void write( const char* aOutBuf, int aCount ) = 0;
341 
342 #if defined(__GNUG__)   // The GNU C++ compiler defines this
343 
344     // When used on a C++ function, we must account for the "this" pointer,
345     // so increase the STRING-INDEX and FIRST-TO_CHECK by one.
346     // See http://docs.freebsd.org/info/gcc/gcc.info.Function_Attributes.html
347     // Then to get format checking during the compile, compile with -Wall or -Wformat
348 #define PRINTF_FUNC __attribute__( ( format( printf, 3, 4 ) ) )
349 #else
350 #define PRINTF_FUNC       // nothing
351 #endif
352 
353 public:
354     /**
355      * Format and write text to the output stream.
356      *
357      * @param nestLevel The multiple of spaces to precede the output with.
358      * @param fmt A printf() style format string.
359      * @param ... a variable list of parameters that will get blended into
360      *  the output under control of the format string.
361      * @return int - the number of characters output.
362      * @throw IO_ERROR, if there is a problem outputting, such as a full disk.
363      */
364     int PRINTF_FUNC Print( int nestLevel, const char* fmt, ... );
365 
366     /**
367      * Perform quote character need determination.
368      *
369      * It returns the quote character as a single character string for a given input wrapee
370      * string.  If the wrappee does not need to be quoted, the return value is "" (the null
371      * string), such as when there are no delimiters in the input wrapee string.  If you want
372      * the quote_char to be assuredly not "", then pass in "(" as the wrappee.
373      * <p>
374      * Implementations are free to override the default behavior, which is to call the static
375      * function of the same name.
376      *
377      * @param wrapee A string that might need wrapping on each end.
378      * @return the quote_char as a single character string, or "" if the wrapee does not need
379      *         to be wrapped.
380      */
381     virtual const char* GetQuoteChar( const char* wrapee ) const;
382 
383     /**
384      * Check \a aWrapee input string for a need to be quoted (e.g. contains a ')' character
385      * or a space), and for \" double quotes within the string that need to be escaped such
386      * that the DSNLEXER will correctly parse the string from a file later.
387      *
388      * @param aWrapee is a string that might need wrapping in double quotes, and it might need
389      *                to have its internal content escaped, or not.
390      * @return a std::string- whose c_str() function can be called for passing to printf()
391      *         style functions that output UTF8 encoded s-expression streams.
392      *
393      * @throw IO_ERROR, if there is any kind of problem with the input string.
394      */
395      virtual std::string Quotes( const std::string& aWrapee ) const;
396 
397      std::string Quotew( const wxString& aWrapee ) const;
398 
399 private:
400     std::vector<char>   m_buffer;
401     char                quoteChar[2];
402 
403     int sprint( const char* fmt, ... );
404     int vprint( const char* fmt, va_list ap );
405 
406 };
407 
408 
409 /**
410  * Implement an #OUTPUTFORMATTER to a memory buffer.
411  *
412  * After Print()ing the string is available through GetString()
413  */
414 class STRING_FORMATTER : public OUTPUTFORMATTER
415 {
416 public:
417     /**
418      * Reserve space in the buffer.
419      */
420     STRING_FORMATTER( int aReserve = OUTPUTFMTBUFZ, char aQuoteChar = '"' ) :
OUTPUTFORMATTER(aReserve,aQuoteChar)421         OUTPUTFORMATTER( aReserve, aQuoteChar )
422     {
423     }
424 
425     /**
426      * Clear the buffer and empties the internal string.
427      */
Clear()428     void Clear()
429     {
430         m_mystring.clear();
431     }
432 
433     /**
434      * Removes whitespace, '(', and ')' from the string.
435      */
436     void StripUseless();
437 
GetString()438     const std::string& GetString()
439     {
440         return m_mystring;
441     }
442 
443 protected:
444     void write( const char* aOutBuf, int aCount ) override;
445 
446 private:
447     std::string m_mystring;
448 };
449 
450 
451 /**
452  * Used for text file output.
453  *
454  * It is about 8 times faster than STREAM_OUTPUTFORMATTER for file streams.
455  */
456 class FILE_OUTPUTFORMATTER : public OUTPUTFORMATTER
457 {
458 public:
459 
460     /**
461      * @param aFileName is the full filename to open and save to as a text file.
462      * @param aMode is what you would pass to wxFopen()'s mode, defaults to wxT( "wt" )
463      *              for text files that are to be created here and now.
464      * @param aQuoteChar is a char used for quoting problematic strings (with whitespace or
465      *                   special characters in them).
466      * @throw IO_ERROR if the file cannot be opened.
467      */
468     FILE_OUTPUTFORMATTER( const wxString& aFileName, const wxChar* aMode = wxT( "wt" ),
469                           char aQuoteChar = '"' );
470 
471     ~FILE_OUTPUTFORMATTER();
472 
473 protected:
474     void write( const char* aOutBuf, int aCount ) override;
475 
476     FILE*       m_fp;               ///< takes ownership
477     wxString    m_filename;
478 };
479 
480 
481 /**
482  * Implement an #OUTPUTFORMATTER to a wxWidgets wxOutputStream.
483  *
484  * The stream is neither opened nor closed by this class.
485  */
486 class STREAM_OUTPUTFORMATTER : public OUTPUTFORMATTER
487 {
488     wxOutputStream& m_os;
489 
490 public:
491     /**
492      * This can take any number of wxOutputStream derivations, so it can write to a file,
493      * socket, or zip file.
494      */
495     STREAM_OUTPUTFORMATTER( wxOutputStream& aStream, char aQuoteChar = '"' ) :
OUTPUTFORMATTER(OUTPUTFMTBUFZ,aQuoteChar)496         OUTPUTFORMATTER( OUTPUTFMTBUFZ, aQuoteChar ),
497         m_os( aStream )
498     {
499     }
500 
501 protected:
502     void write( const char* aOutBuf, int aCount ) override;
503 };
504 
505 #endif // RICHIO_H_
506