KiCad PCB EDA Suite
ptree.cpp
Go to the documentation of this file.
1 
2 /*
3  * This program source code file is part of KiCad, a free EDA CAD application.
4  *
5  * Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
6  * Copyright (C) 2013-2020 KiCad Developers, see CHANGELOG.TXT for contributors.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, you may find one here:
20  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21  * or you may search the http://www.gnu.org website for the version 2 license,
22  * or you may write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 
26 // Something in either <boost/property_tree/ptree.hpp> causes a bunch of compiler
27 // errors in <wx/msw/winundef.h> version 2.9 on MinGW.
28 #include <macros.h>
29 
30 #include <boost/property_tree/ptree.hpp>
31 
32 #include <cassert>
33 #include <ptree.h>
34 
35 typedef PTREE::const_iterator CITER;
36 typedef PTREE::iterator ITER;
37 
38 #if defined(DEBUG)
39  #define D(x) x
40 #else
41  #define D(x)
42 #endif
43 
44 #define CTL_OMIT_NL (1<<0)
45 #define CTL_IN_ATTRS (1<<1)
46 
47 
48 //-----<Scan>------------------------------------------------------------------
49 
55 inline void scanList( PTREE* aTree, DSNLEXER* aLexer )
56 {
57  assert( aLexer->CurTok() == DSN_LEFT );
58 
59  int tok = aLexer->NextTok();
60 
61  const char* key = aLexer->CurText();
62 
63  PTREE* list = &aTree->push_back( PTREE::value_type( key, PTREE() ) )->second;
64 
65  if( tok != DSN_RIGHT )
66  {
67  while( ( tok = aLexer->NextTok() ) != DSN_RIGHT )
68  {
69  if( tok == DSN_EOF )
70  aLexer->Unexpected( DSN_EOF );
71 
72  Scan( list, aLexer );
73  }
74  }
75 }
76 
77 
78 inline void scanAtom( PTREE* aTree, DSNLEXER* aLexer )
79 {
80  const char* key = aLexer->CurText();
81 
82  aTree->push_back( PTREE::value_type( key, PTREE() ) );
83 }
84 
85 
86 void Scan( PTREE* aTree, DSNLEXER* aLexer )
87 {
88  int tok = aLexer->CurTok();
89 
90  // conditionally read first token.
91  if( tok == DSN_NONE )
92  tok = aLexer->NextTok();
93 
94  if( tok == DSN_EOF )
95  {
96  aLexer->Unexpected( DSN_EOF );
97  }
98 
99  if( tok == DSN_LEFT )
100  {
101  scanList( aTree, aLexer );
102  }
103  else
104  {
105  scanAtom( aTree, aLexer );
106  }
107 }
108 
109 
110 //-----<Format>------------------------------------------------------------------
111 
112 inline bool isAtom( CPTREE& aTree )
113 {
114  return aTree.size()==0 && aTree.data().size()==0;
115 }
116 
117 
118 inline bool isLast( CPTREE& aTree, CITER it )
119 {
120  CITER next = it;
121  ++next;
122  return next == aTree.end();
123 }
124 
125 
126 inline CITER next( CITER it )
127 {
128  CITER n = it;
129  return ++n;
130 }
131 
132 
133 static void formatNode( OUTPUTFORMATTER* out, int aNestLevel, int aCtl,
134  const std::string& aKey, CPTREE& aTree );
135 
136 
137 static void formatList( OUTPUTFORMATTER* out, int aNestLevel, int aCtl, CPTREE& aTree )
138 
139 {
140  for( CITER it = aTree.begin(); it != aTree.end(); ++it )
141  {
142  // Processing a tree which was read in with xml_parser?
143  if( it->first == "<xmlattr>" )
144  {
145  formatList( out, aNestLevel, aCtl | CTL_IN_ATTRS, it->second );
146  continue;
147  }
148 
149  int ctl = 0;
150 
151  if( isLast( aTree, it ) ) // is "it" the last one?
152  {
153  //if( !( aCtl & CTL_IN_ATTRS ) )
154  ctl = CTL_OMIT_NL;
155  }
156  else if( isAtom( next( it )->second ) )
157  {
158  /* if( !( aCtl & CTL_IN_ATTRS ) ) */
159  ctl = CTL_OMIT_NL;
160  }
161 
162  formatNode( out, aNestLevel+1, ctl, it->first, it->second );
163  }
164 }
165 
166 
167 static void formatNode( OUTPUTFORMATTER* out, int aNestLevel, int aCtl,
168  const std::string& aKey, CPTREE& aTree )
169 
170 {
171  if( !isAtom( aTree ) ) // is a list, not an atom
172  {
173  int ctl = CTL_OMIT_NL;
174 
175  // aTree is list and its first child is a list
176  if( aTree.size() && !isAtom( aTree.begin()->second ) && !aTree.data().size() )
177  ctl = 0;
178 
179  out->Print( aNestLevel, "(%s%s", out->Quotes( aKey ).c_str(), ctl & CTL_OMIT_NL ? "" : "\n" );
180 
181  if( aTree.data().size() ) // sexpr format does not use data()
182  {
183  out->Print( 0, " %s%s",
184  out->Quotes( aTree.data() ).c_str(),
185  aTree.size() ? "\n" : ""
186  );
187  }
188 
189  formatList( out, aNestLevel, aCtl, aTree );
190 
191  out->Print( 0, ")%s", aCtl & CTL_OMIT_NL ? "" : "\n" );
192  }
193 
194  else // is an atom, not a list
195  {
196  out->Print( 0, " %s", out->Quotes( aKey ).c_str() );
197  }
198 }
199 
200 
201 void Format( OUTPUTFORMATTER* out, int aNestLevel, int aCtl, CPTREE& aTree )
202 {
203  if( aTree.size() == 1 && !aTree.data().size() )
204  {
205  // The topmost node is basically only a container for the document root.
206  // It anchors the paths which traverse the tree deeper.
207  CITER it = aTree.begin();
208  formatNode( out, aNestLevel, aCtl, it->first, it->second );
209  }
210  else
211  {
212  // This is not expected, neither for sexpr nor xml.
213  formatNode( out, aNestLevel, aCtl, "", aTree );
214  }
215 }
216 
CITER next(CITER it)
Definition: ptree.cpp:126
void Scan(PTREE *aTree, DSNLEXER *aLexer)
Function Scan fills an empty PTREE with information from a KiCad s-expresion stream.
Definition: ptree.cpp:86
bool isLast(CPTREE &aTree, CITER it)
Definition: ptree.cpp:118
PTREE::iterator ITER
Definition: ptree.cpp:36
void Unexpected(int aTok)
Function Unexpected throws an IO_ERROR exception with an input file specific error message.
Definition: dsnlexer.cpp:342
PTREE::const_iterator CITER
Definition: ptree.cpp:35
OUTPUTFORMATTER is an important interface (abstract class) used to output 8 bit text in a convenient ...
Definition: richio.h:327
static void formatList(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Definition: ptree.cpp:137
bool isAtom(CPTREE &aTree)
Definition: ptree.cpp:112
This file contains miscellaneous commonly used macros and functions.
void scanList(PTREE *aTree, DSNLEXER *aLexer)
Function scanList reads a sexpr list from the input stream into a new node with key aLexer->CurText()...
Definition: ptree.cpp:55
boost::property_tree::ptree PTREE
Definition: ptree.h:54
#define CTL_IN_ATTRS
Definition: ptree.cpp:45
int CurTok()
Function CurTok returns whatever NextTok() returned the last time it was called.
Definition: dsnlexer.h:320
const PTREE CPTREE
Definition: ptree.h:55
void scanAtom(PTREE *aTree, DSNLEXER *aLexer)
Definition: ptree.cpp:78
static void formatNode(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const std::string &aKey, CPTREE &aTree)
Definition: ptree.cpp:167
virtual std::string Quotes(const std::string &aWrapee)
Function Quotes checks aWrapee input string for a need to be quoted (e.g.
Definition: richio.cpp:433
#define CTL_OMIT_NL
Definition: ptree.cpp:44
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:201
int NextTok()
Function NextTok returns the next token found in the input file or DSN_EOF when reaching the end of f...
Definition: dsnlexer.cpp:513
int PRINTF_FUNC Print(int nestLevel, const char *fmt,...)
Function Print formats and writes text to the output stream.
Definition: richio.cpp:404
const char * CurText()
Function CurText returns a pointer to the current token's text.
Definition: dsnlexer.h:488
DSNLEXER implements a lexical analyzer for the SPECCTRA DSN file format.
Definition: dsnlexer.h:79