|
|
/*
* This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com> * Copyright (C) 2013-2020 KiCad Developers, see AUTHORS.TXT for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, you may find one here: * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
// Something in either <boost/property_tree/ptree.hpp> causes a bunch of compiler
// errors in <wx/msw/winundef.h> version 2.9 on MinGW.
#include <macros.h>
#include <boost/property_tree/ptree.hpp>
#include <cassert>
#include <ptree.h>
typedef PTREE::const_iterator CITER;typedef PTREE::iterator ITER;
#if defined(DEBUG)
#define D(x) x
#else
#define D(x)
#endif
#define CTL_OMIT_NL (1<<0)
#define CTL_IN_ATTRS (1<<1)
//-----<Scan>------------------------------------------------------------------
/**
* Function scanList * reads a sexpr list from the input stream into a new node with key * aLexer->CurText(). */inline void scanList( PTREE* aTree, DSNLEXER* aLexer ){ assert( aLexer->CurTok() == DSN_LEFT );
int tok = aLexer->NextTok();
const char* key = aLexer->CurText();
PTREE* list = &aTree->push_back( PTREE::value_type( key, PTREE() ) )->second;
if( tok != DSN_RIGHT ) { while( ( tok = aLexer->NextTok() ) != DSN_RIGHT ) { if( tok == DSN_EOF ) aLexer->Unexpected( DSN_EOF );
Scan( list, aLexer ); } }}
inline void scanAtom( PTREE* aTree, const DSNLEXER* aLexer ){ const char* key = aLexer->CurText();
aTree->push_back( PTREE::value_type( key, PTREE() ) );}
void Scan( PTREE* aTree, DSNLEXER* aLexer ){ int tok = aLexer->CurTok();
// conditionally read first token.
if( tok == DSN_NONE ) tok = aLexer->NextTok();
if( tok == DSN_EOF ) { aLexer->Unexpected( DSN_EOF ); }
if( tok == DSN_LEFT ) { scanList( aTree, aLexer ); } else { scanAtom( aTree, aLexer ); }}
//-----<Format>------------------------------------------------------------------
inline bool isAtom( const CPTREE& aTree ){ return aTree.size() == 0 && aTree.data().size() == 0;}
inline bool isLast( const CPTREE& aTree, CITER it ){ CITER next = it; ++next; return next == aTree.end();}
inline CITER next( CITER it ){ CITER n = it; return ++n;}
static void formatNode( OUTPUTFORMATTER* out, int aNestLevel, int aCtl, const std::string& aKey, const CPTREE& aTree );
static void formatList( OUTPUTFORMATTER* out, int aNestLevel, int aCtl, const CPTREE& aTree ){ for( CITER it = aTree.begin(); it != aTree.end(); ++it ) { // Processing a tree which was read in with xml_parser?
if( it->first == "<xmlattr>" ) { formatList( out, aNestLevel, aCtl | CTL_IN_ATTRS, it->second ); continue; }
int ctl = 0;
if( isLast( aTree, it ) ) // is "it" the last one?
{ //if( !( aCtl & CTL_IN_ATTRS ) )
ctl = CTL_OMIT_NL; } else if( isAtom( next( it )->second ) ) { /* if( !( aCtl & CTL_IN_ATTRS ) ) */ ctl = CTL_OMIT_NL; }
formatNode( out, aNestLevel+1, ctl, it->first, it->second ); }}
static void formatNode( OUTPUTFORMATTER* out, int aNestLevel, int aCtl, const std::string& aKey, const CPTREE& aTree )
{ if( !isAtom( aTree ) ) // is a list, not an atom
{ int ctl = CTL_OMIT_NL;
// aTree is list and its first child is a list
if( aTree.size() && !isAtom( aTree.begin()->second ) && !aTree.data().size() ) ctl = 0;
out->Print( aNestLevel, "(%s%s", out->Quotes( aKey ).c_str(), ctl & CTL_OMIT_NL ? "" : "\n" );
if( aTree.data().size() ) // sexpr format does not use data()
{ out->Print( 0, " %s%s", out->Quotes( aTree.data() ).c_str(), aTree.size() ? "\n" : "" ); }
formatList( out, aNestLevel, aCtl, aTree );
out->Print( 0, ")%s", aCtl & CTL_OMIT_NL ? "" : "\n" ); }
else // is an atom, not a list
{ out->Print( 0, " %s", out->Quotes( aKey ).c_str() ); }}
void Format( OUTPUTFORMATTER* out, int aNestLevel, int aCtl, const CPTREE& aTree ){ if( aTree.size() == 1 && !aTree.data().size() ) { // The topmost node is basically only a container for the document root.
// It anchors the paths which traverse the tree deeper.
CITER it = aTree.begin(); formatNode( out, aNestLevel, aCtl, it->first, it->second ); } else { // This is not expected, neither for sexpr nor xml.
formatNode( out, aNestLevel, aCtl, "", aTree ); }}
|