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.

215 lines
5.6 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
  5. * Copyright (C) 2013-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. // Something in either <boost/property_tree/ptree.hpp> causes a bunch of compiler
  25. // errors in <wx/msw/winundef.h> version 2.9 on MinGW.
  26. #include <macros.h>
  27. #include <boost/property_tree/ptree.hpp>
  28. #include <cassert>
  29. #include <ptree.h>
  30. typedef PTREE::const_iterator CITER;
  31. typedef PTREE::iterator ITER;
  32. #if defined(DEBUG)
  33. #define D(x) x
  34. #else
  35. #define D(x)
  36. #endif
  37. #define CTL_OMIT_NL (1<<0)
  38. #define CTL_IN_ATTRS (1<<1)
  39. //-----<Scan>------------------------------------------------------------------
  40. /**
  41. * Function scanList
  42. * reads a sexpr list from the input stream into a new node with key
  43. * aLexer->CurText().
  44. */
  45. inline void scanList( PTREE* aTree, DSNLEXER* aLexer )
  46. {
  47. assert( aLexer->CurTok() == DSN_LEFT );
  48. int tok = aLexer->NextTok();
  49. const char* key = aLexer->CurText();
  50. PTREE* list = &aTree->push_back( PTREE::value_type( key, PTREE() ) )->second;
  51. if( tok != DSN_RIGHT )
  52. {
  53. while( ( tok = aLexer->NextTok() ) != DSN_RIGHT )
  54. {
  55. if( tok == DSN_EOF )
  56. aLexer->Unexpected( DSN_EOF );
  57. Scan( list, aLexer );
  58. }
  59. }
  60. }
  61. inline void scanAtom( PTREE* aTree, const DSNLEXER* aLexer )
  62. {
  63. const char* key = aLexer->CurText();
  64. aTree->push_back( PTREE::value_type( key, PTREE() ) );
  65. }
  66. void Scan( PTREE* aTree, DSNLEXER* aLexer )
  67. {
  68. int tok = aLexer->CurTok();
  69. // conditionally read first token.
  70. if( tok == DSN_NONE )
  71. tok = aLexer->NextTok();
  72. if( tok == DSN_EOF )
  73. {
  74. aLexer->Unexpected( DSN_EOF );
  75. }
  76. if( tok == DSN_LEFT )
  77. {
  78. scanList( aTree, aLexer );
  79. }
  80. else
  81. {
  82. scanAtom( aTree, aLexer );
  83. }
  84. }
  85. //-----<Format>------------------------------------------------------------------
  86. inline bool isAtom( const CPTREE& aTree )
  87. {
  88. return aTree.size() == 0 && aTree.data().size() == 0;
  89. }
  90. inline bool isLast( const CPTREE& aTree, CITER it )
  91. {
  92. CITER next = it;
  93. ++next;
  94. return next == aTree.end();
  95. }
  96. inline CITER next( CITER it )
  97. {
  98. CITER n = it;
  99. return ++n;
  100. }
  101. static void formatNode( OUTPUTFORMATTER* out, int aNestLevel, int aCtl,
  102. const std::string& aKey, const CPTREE& aTree );
  103. static void formatList( OUTPUTFORMATTER* out, int aNestLevel, int aCtl, const CPTREE& aTree )
  104. {
  105. for( CITER it = aTree.begin(); it != aTree.end(); ++it )
  106. {
  107. // Processing a tree which was read in with xml_parser?
  108. if( it->first == "<xmlattr>" )
  109. {
  110. formatList( out, aNestLevel, aCtl | CTL_IN_ATTRS, it->second );
  111. continue;
  112. }
  113. int ctl = 0;
  114. if( isLast( aTree, it ) ) // is "it" the last one?
  115. {
  116. //if( !( aCtl & CTL_IN_ATTRS ) )
  117. ctl = CTL_OMIT_NL;
  118. }
  119. else if( isAtom( next( it )->second ) )
  120. {
  121. /* if( !( aCtl & CTL_IN_ATTRS ) ) */
  122. ctl = CTL_OMIT_NL;
  123. }
  124. formatNode( out, aNestLevel+1, ctl, it->first, it->second );
  125. }
  126. }
  127. static void formatNode( OUTPUTFORMATTER* out, int aNestLevel, int aCtl,
  128. const std::string& aKey, const CPTREE& aTree )
  129. {
  130. if( !isAtom( aTree ) ) // is a list, not an atom
  131. {
  132. int ctl = CTL_OMIT_NL;
  133. // aTree is list and its first child is a list
  134. if( aTree.size() && !isAtom( aTree.begin()->second ) && !aTree.data().size() )
  135. ctl = 0;
  136. out->Print( aNestLevel, "(%s%s", out->Quotes( aKey ).c_str(), ctl & CTL_OMIT_NL ? "" : "\n" );
  137. if( aTree.data().size() ) // sexpr format does not use data()
  138. {
  139. out->Print( 0, " %s%s",
  140. out->Quotes( aTree.data() ).c_str(),
  141. aTree.size() ? "\n" : ""
  142. );
  143. }
  144. formatList( out, aNestLevel, aCtl, aTree );
  145. out->Print( 0, ")%s", aCtl & CTL_OMIT_NL ? "" : "\n" );
  146. }
  147. else // is an atom, not a list
  148. {
  149. out->Print( 0, " %s", out->Quotes( aKey ).c_str() );
  150. }
  151. }
  152. void Format( OUTPUTFORMATTER* out, int aNestLevel, int aCtl, const CPTREE& aTree )
  153. {
  154. if( aTree.size() == 1 && !aTree.data().size() )
  155. {
  156. // The topmost node is basically only a container for the document root.
  157. // It anchors the paths which traverse the tree deeper.
  158. CITER it = aTree.begin();
  159. formatNode( out, aNestLevel, aCtl, it->first, it->second );
  160. }
  161. else
  162. {
  163. // This is not expected, neither for sexpr nor xml.
  164. formatNode( out, aNestLevel, aCtl, "", aTree );
  165. }
  166. }