You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

589 lines
19 KiB

15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
16 years ago
16 years ago
16 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
  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) 2007 Kicad Developers, see change_log.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. #ifndef RICHIO_H_
  25. #define RICHIO_H_
  26. // This file defines 3 classes useful for working with DSN text files and is named
  27. // "richio" after its author, Richard Hollenbeck, aka Dick Hollenbeck.
  28. #include <string>
  29. #include <vector>
  30. // I really did not want to be dependent on wxWidgets in richio
  31. // but the errorText needs to be wide char so wxString rules.
  32. #include <wx/wx.h>
  33. #include <stdio.h>
  34. /**
  35. * @ingroup exception_types
  36. * @{
  37. */
  38. #define IO_FORMAT _( "IO_ERROR: %s\n from %s : %s" )
  39. #define PARSE_FORMAT _( "PARSE_ERROR: %s in input/source \"%s\", line %d, offset %d\n from %s : %s" )
  40. // references:
  41. // http://stackoverflow.com/questions/2670816/how-can-i-use-the-compile-time-constant-line-in-a-string
  42. #define STRINGIFY(x) #x
  43. #define TOSTRING(x) STRINGIFY(x)
  44. // use one of the following __LOC__ defs, depending on whether your
  45. // compiler supports __func__ or not, and how it handles __LINE__
  46. #define __LOC__ ((std::string(__func__) + "() : line ") + TOSTRING(__LINE__)).c_str()
  47. //#define __LOC__ TOSTRING(__LINE__)
  48. /// macro which captures the "call site" values of __FILE_ & __LOC__
  49. #define THROW_IO_ERROR( msg ) throw IO_ERROR( __FILE__, __LOC__, msg )
  50. /**
  51. * Struct IO_ERROR
  52. * is a class used to hold an error message and may be used to throw exceptions
  53. * containing meaningful error messages.
  54. * @author Dick Hollenbeck
  55. */
  56. struct IO_ERROR // : std::exception
  57. {
  58. wxString errorText;
  59. /**
  60. * Constructor
  61. *
  62. * @param aThrowersFile is the __FILE__ preprocessor macro but generated
  63. * at the source file of thrower.
  64. *
  65. * @param aThrowersLoc can be either a function name, such as __func__
  66. * or a stringified __LINE__ preprocessor macro but generated
  67. * at the source function of the thrower, or concatonation. Use macro
  68. * THROW_IO_ERROR() to wrap a call to this constructor at the call site.
  69. *
  70. * @param aMsg is error text that will be streamed through wxString.Printf()
  71. * using the format string IO_FORMAT above.
  72. */
  73. IO_ERROR( const char* aThrowersFile,
  74. const char* aThrowersLoc,
  75. const wxString& aMsg )
  76. {
  77. init( aThrowersFile, aThrowersLoc, aMsg );
  78. }
  79. IO_ERROR( const char* aThrowersFile,
  80. const char* aThrowersLoc,
  81. const std::string& aMsg )
  82. {
  83. init( aThrowersFile, aThrowersLoc, wxString::FromUTF8( aMsg.c_str() ) );
  84. }
  85. /**
  86. * handles the case where _() is passed as aMsg.
  87. */
  88. IO_ERROR( const char* aThrowersFile,
  89. const char* aThrowersLoc,
  90. const wxChar* aMsg )
  91. {
  92. init( aThrowersFile, aThrowersLoc, wxString( aMsg ) );
  93. }
  94. void init( const char* aThrowersFile, const char* aThrowersLoc, const wxString& aMsg )
  95. {
  96. errorText.Printf( IO_FORMAT, aMsg.GetData(),
  97. wxString::FromUTF8( aThrowersFile ).GetData(),
  98. wxString::FromUTF8( aThrowersLoc ).GetData() );
  99. }
  100. IO_ERROR() {}
  101. ~IO_ERROR() throw ( /*none*/ ){}
  102. };
  103. /**
  104. * Class PARSE_ERROR
  105. * contains a filename or source description, a problem input line, a line number,
  106. * a byte offset, and an error message which contains the the caller's report and his
  107. * call site information: CPP source file, function, and line number.
  108. * @author Dick Hollenbeck
  109. */
  110. struct PARSE_ERROR : public IO_ERROR
  111. {
  112. // wxString errorText is still public from IO_ERROR
  113. int lineNumber; ///< at which line number, 1 based index.
  114. int byteIndex; ///< at which character position within the line, 1 based index
  115. /// problem line of input [say, from a LINE_READER].
  116. /// this is brought up in original byte format rather than wxString form, incase
  117. /// there was a problem with the encoding, in which case converting to wxString is
  118. /// not reliable in this context.
  119. std::string inputLine;
  120. /**
  121. * Constructor
  122. * which is normally called via the macro THROW_PARSE_ERROR so that
  123. * __FILE__ and __LOC__ can be captured from the call site.
  124. */
  125. PARSE_ERROR( const char* aThrowersFile, const char* aThrowersLoc,
  126. const wxString& aMsg, const wxString& aSource,
  127. const char* aInputLine,
  128. int aLineNumber, int aByteIndex ) :
  129. IO_ERROR()
  130. {
  131. init( aThrowersFile, aThrowersLoc, aMsg, aSource, aInputLine, aLineNumber, aByteIndex );
  132. }
  133. void init( const char* aThrowersFile, const char* aThrowersLoc,
  134. const wxString& aMsg, const wxString& aSource,
  135. const char* aInputLine,
  136. int aLineNumber, int aByteIndex )
  137. {
  138. // save inpuLine, lineNumber, and offset for UI (.e.g. Sweet text editor)
  139. inputLine = aInputLine;
  140. lineNumber = aLineNumber;
  141. byteIndex = aByteIndex;
  142. errorText.Printf( PARSE_FORMAT, aMsg.GetData(), aSource.GetData(),
  143. aLineNumber, aByteIndex,
  144. wxString::FromUTF8( aThrowersFile ).GetData(),
  145. wxString::FromUTF8( aThrowersLoc ).GetData() );
  146. }
  147. ~PARSE_ERROR() throw ( /*none*/ ){}
  148. };
  149. #define THROW_PARSE_ERROR( aMsg, aSource, aInputLine, aLineNumber, aByteIndex ) \
  150. throw PARSE_ERROR( __FILE__, __LOC__, aMsg, aSource, aInputLine, aLineNumber, aByteIndex )
  151. /** @} exception_types */
  152. #define LINE_READER_LINE_DEFAULT_MAX 100000
  153. #define LINE_READER_LINE_INITIAL_SIZE 5000
  154. /**
  155. * Class LINE_READER
  156. * is an abstract class from which implementation specific LINE_READERs may
  157. * be derived to read single lines of text and manage a line number counter.
  158. */
  159. class LINE_READER
  160. {
  161. protected:
  162. unsigned length; ///< no. bytes in line before trailing nul.
  163. unsigned lineNum;
  164. char* line; ///< the read line of UTF8 text
  165. unsigned capacity; ///< no. bytes allocated for line.
  166. unsigned maxLineLength; ///< maximum allowed capacity using resizing.
  167. wxString source; ///< origin of text lines, e.g. filename or "clipboard"
  168. /**
  169. * Function expandCapacity
  170. * will exand the capacity of @a line up to maxLineLength but not greater, so
  171. * be careful about making assumptions of @a capacity after calling this.
  172. */
  173. void expandCapacity( unsigned newsize );
  174. public:
  175. /**
  176. * Constructor LINE_READER
  177. * builds a line reader and fixes the length of the maximum supported
  178. * line length to @a aMaxLineLength.
  179. */
  180. LINE_READER( unsigned aMaxLineLength = LINE_READER_LINE_DEFAULT_MAX );
  181. virtual ~LINE_READER()
  182. {
  183. delete[] line;
  184. }
  185. /**
  186. * Function ReadLine
  187. * reads a line of text into the buffer and increments the line number
  188. * counter. If the line is larger than aMaxLineLength passed to the
  189. * constructor, then an exception is thrown. The line is nul terminated.
  190. * @return unsigned - The number of bytes read, 0 at end of file.
  191. * @throw IO_ERROR when a line is too long.
  192. */
  193. virtual unsigned ReadLine() throw( IO_ERROR ) = 0;
  194. /**
  195. * Function GetSource
  196. * returns the name of the source of the lines in an abstract sense.
  197. * This may be a file or it may be the clipboard or any other source
  198. * of lines of text. The returned string is useful for reporting error
  199. * messages.
  200. */
  201. virtual const wxString& GetSource() const
  202. {
  203. return source;
  204. }
  205. /**
  206. * Function Line
  207. * returns a pointer to the last line that was read in.
  208. */
  209. virtual char* Line() const
  210. {
  211. return line;
  212. }
  213. /**
  214. * Operator char*
  215. * is a casting operator that returns a char* pointer to the start of the
  216. * line buffer.
  217. */
  218. operator char* () const
  219. {
  220. return Line();
  221. }
  222. /**
  223. * Function Line Number
  224. * returns the line number of the last line read from this LINE_READER. Lines
  225. * start from 1.
  226. */
  227. virtual unsigned LineNumber() const
  228. {
  229. return lineNum;
  230. }
  231. /**
  232. * Function Length
  233. * returns the number of bytes in the last line read from this LINE_READER.
  234. */
  235. virtual unsigned Length() const
  236. {
  237. return length;
  238. }
  239. };
  240. /**
  241. * Class FILE_LINE_READER
  242. * is a LINE_READER that reads from an open file. File must be already open
  243. * so that this class can exist without any UI policy.
  244. */
  245. class FILE_LINE_READER : public LINE_READER
  246. {
  247. protected:
  248. bool iOwn; ///< if I own the file, I'll promise to close it, else not.
  249. FILE* fp; ///< I may own this file, but might not.
  250. public:
  251. /**
  252. * Constructor FILE_LINE_READER
  253. * takes an open FILE and the size of the desired line buffer and takes
  254. * ownership of the open file, i.e. assumes the obligation to close it.
  255. *
  256. * @param aFile is an open file.
  257. * @param aFileName is the name of the file for error reporting purposes.
  258. * @param doOwn if true, means I should close the open file, else not.
  259. * @param aStartingLineNumber is the initial line number to report on error, and is
  260. * accessible here for the case where multiple DSNLEXERs are reading from the
  261. * same file in sequence, all from the same open file (with @a doOwn = false).
  262. * Internally it is incremented by one after each ReadLine(), so the first
  263. * reported line number will always be one greater than what is provided here.
  264. * @param aMaxLineLength is the number of bytes to use in the line buffer.
  265. */
  266. FILE_LINE_READER( FILE* aFile, const wxString& aFileName, bool doOwn = true,
  267. unsigned aStartingLineNumber = 0,
  268. unsigned aMaxLineLength = LINE_READER_LINE_DEFAULT_MAX );
  269. /**
  270. * Destructor
  271. * may or may not close the open file, depending on @a doOwn in constructor.
  272. */
  273. ~FILE_LINE_READER();
  274. unsigned ReadLine() throw( IO_ERROR ); // see LINE_READER::ReadLine() description
  275. /**
  276. * Function Rewind
  277. * rewinds the file and resets the line number back to zero. Line number
  278. * will go to 1 on first ReadLine().
  279. */
  280. void Rewind()
  281. {
  282. rewind( fp );
  283. lineNum = 0;
  284. }
  285. };
  286. /**
  287. * Class STRING_LINE_READER
  288. * is a LINE_READER that reads from a multiline 8 bit wide std::string
  289. */
  290. class STRING_LINE_READER : public LINE_READER
  291. {
  292. protected:
  293. std::string lines;
  294. size_t ndx;
  295. public:
  296. /**
  297. * Constructor STRING_LINE_READER( const std::string&, const wxString& )
  298. *
  299. * @param aString is a source string consisting of one or more lines
  300. * of text, where multiple lines are separated with a '\n' character.
  301. * The last line does not necessarily need a trailing '\n'.
  302. *
  303. * @param aSource describes the source of aString for error reporting purposes
  304. * can be anything meaninful, such as wxT( "clipboard" ).
  305. */
  306. STRING_LINE_READER( const std::string& aString, const wxString& aSource );
  307. /**
  308. * Constructor STRING_LINE_READER( const STRING_LINE_READER& )
  309. * allows for a continuation of the reading of a stream started by another
  310. * STRING_LINE_READER. Any stream offset and source name are used from
  311. * @a aStartingPoint.
  312. */
  313. STRING_LINE_READER( const STRING_LINE_READER& aStartingPoint );
  314. unsigned ReadLine() throw( IO_ERROR ); // see LINE_READER::ReadLine() description
  315. };
  316. /**
  317. * Class OUTPUTFORMATTER
  318. * is an important interface (abstract) class used to output UTF8 text in
  319. * a convenient way. The primary interface is "printf() - like" but
  320. * with support for indentation control. The destination of the 8 bit
  321. * wide text is up to the implementer.
  322. * <p>
  323. * The implementer only has to implement the write() function, but can
  324. * also optionally re-implement GetQuoteChar().
  325. * <p>
  326. * If you want to output a wxString, then use CONV_TO_UTF8() on it
  327. * before passing it as an argument to Print().
  328. * <p>
  329. * Since this is an abstract interface, only classes derived from
  330. * this one may actually be used.
  331. */
  332. class OUTPUTFORMATTER
  333. {
  334. std::vector<char> buffer;
  335. int sprint( const char* fmt, ... ) throw( IO_ERROR );
  336. int vprint( const char* fmt, va_list ap ) throw( IO_ERROR );
  337. protected:
  338. OUTPUTFORMATTER( int aReserve = 300 ) :
  339. buffer( aReserve, '\0' )
  340. {
  341. }
  342. virtual ~OUTPUTFORMATTER() {}
  343. /**
  344. * Function GetQuoteChar
  345. * performs quote character need determination according to the Specctra DSN
  346. * specification.
  347. * @param wrapee A string that might need wrapping on each end.
  348. * @param quote_char A single character C string which provides the current
  349. * quote character, should it be needed by the wrapee.
  350. *
  351. * @return const char* - the quote_char as a single character string, or ""
  352. * if the wrapee does not need to be wrapped.
  353. */
  354. static const char* GetQuoteChar( const char* wrapee, const char* quote_char );
  355. /**
  356. * Function write
  357. * should be coded in the interface implementation (derived) classes.
  358. *
  359. * @param aOutBuf is the start of a byte buffer to write.
  360. * @param aCount tells how many bytes to write.
  361. * @throw IO_ERROR, if there is a problem outputting, such as a full disk.
  362. */
  363. virtual void write( const char* aOutBuf, int aCount ) throw( IO_ERROR ) = 0;
  364. #if defined(__GNUG__) // The GNU C++ compiler defines this
  365. // When used on a C++ function, we must account for the "this" pointer,
  366. // so increase the STRING-INDEX and FIRST-TO_CHECK by one.
  367. // See http://docs.freebsd.org/info/gcc/gcc.info.Function_Attributes.html
  368. // Then to get format checking during the compile, compile with -Wall or -Wformat
  369. #define PRINTF_FUNC __attribute__ ((format (printf, 3, 4)))
  370. #else
  371. #define PRINTF_FUNC // nothing
  372. #endif
  373. public:
  374. //-----<interface functions>------------------------------------------
  375. /**
  376. * Function Print
  377. * formats and writes text to the output stream.
  378. *
  379. * @param nestLevel The multiple of spaces to precede the output with.
  380. * @param fmt A printf() style format string.
  381. * @param ... a variable list of parameters that will get blended into
  382. * the output under control of the format string.
  383. * @return int - the number of characters output.
  384. * @throw IO_ERROR, if there is a problem outputting, such as a full disk.
  385. */
  386. int PRINTF_FUNC Print( int nestLevel, const char* fmt, ... ) throw( IO_ERROR );
  387. /**
  388. * Function GetQuoteChar
  389. * performs quote character need determination.
  390. * It returns the quote character as a single character string for a given
  391. * input wrapee string. If the wrappee does not need to be quoted,
  392. * the return value is "" (the null string), such as when there are no
  393. * delimiters in the input wrapee string. If you want the quote_char
  394. * to be assuredly not "", then pass in "(" as the wrappee.
  395. * <p>
  396. * Implementations are free to override the default behavior, which is to
  397. * call the static function of the same name.
  398. * @param wrapee A string that might need wrapping on each end.
  399. * @return const char* - the quote_char as a single character string, or ""
  400. * if the wrapee does not need to be wrapped.
  401. */
  402. virtual const char* GetQuoteChar( const char* wrapee )
  403. {
  404. return GetQuoteChar( wrapee, "\"" );
  405. }
  406. /**
  407. * Function Quotes
  408. * checks \a aWrapee input string for a need to be quoted
  409. * (e.g. contains a ')' character or a space), and for \" double quotes
  410. * within the string that need to be escaped such that the DSNLEXER
  411. * will correctly parse the string from a file later.
  412. *
  413. * @param aWrapee is a string that might need wraping in double quotes,
  414. * and it might need to have its internal content escaped, or not.
  415. *
  416. * @return std::string - whose c_str() function can be called for passing
  417. * to printf() style functions that output UTF8 encoded s-expression streams.
  418. *
  419. * @throw IO_ERROR, if there is any kind of problem with the input string.
  420. */
  421. virtual std::string Quotes( const std::string& aWrapee ) throw( IO_ERROR );
  422. std::string Quotew( const wxString& aWrapee ) throw( IO_ERROR );
  423. //-----</interface functions>-----------------------------------------
  424. };
  425. /**
  426. * Class STRING_FORMATTER
  427. * implements OUTPUTFORMATTER to a memory buffer. After Print()ing the
  428. * string is available through GetString()
  429. */
  430. class STRING_FORMATTER : public OUTPUTFORMATTER
  431. {
  432. std::string mystring;
  433. public:
  434. /**
  435. * Constructor STRING_FORMATTER
  436. * reserves space in the buffer
  437. */
  438. STRING_FORMATTER( int aReserve = 300 ) :
  439. OUTPUTFORMATTER( aReserve )
  440. {
  441. }
  442. /**
  443. * Function Clear
  444. * clears the buffer and empties the internal string.
  445. */
  446. void Clear()
  447. {
  448. mystring.clear();
  449. }
  450. /**
  451. * Function StripUseless
  452. * removes whitespace, '(', and ')' from the mystring.
  453. */
  454. void StripUseless();
  455. std::string GetString()
  456. {
  457. return mystring;
  458. }
  459. //-----<OUTPUTFORMATTER>------------------------------------------------
  460. protected:
  461. void write( const char* aOutBuf, int aCount ) throw( IO_ERROR );
  462. //-----</OUTPUTFORMATTER>-----------------------------------------------
  463. };
  464. /**
  465. * Class STREAM_OUTPUTFORMATTER
  466. * implements OUTPUTFORMATTER to a wxWidgets wxOutputStream. The stream is
  467. * neither opened nor closed by this class.
  468. */
  469. class STREAM_OUTPUTFORMATTER : public OUTPUTFORMATTER
  470. {
  471. wxOutputStream& os;
  472. char quoteChar[2];
  473. public:
  474. /**
  475. * Constructor STREAM_OUTPUTFORMATTER
  476. * can take any number of wxOutputStream derivations, so it can write
  477. * to a file, socket, or zip file.
  478. */
  479. STREAM_OUTPUTFORMATTER( wxOutputStream& aStream, char aQuoteChar = '"' ) :
  480. os( aStream )
  481. {
  482. quoteChar[0] = aQuoteChar;
  483. quoteChar[1] = 0;
  484. }
  485. //-----<OUTPUTFORMATTER>------------------------------------------------
  486. const char* GetQuoteChar( const char* wrapee );
  487. protected:
  488. void write( const char* aOutBuf, int aCount ) throw( IO_ERROR );
  489. //-----</OUTPUTFORMATTER>-----------------------------------------------
  490. };
  491. #endif // RICHIO_H_