kicad/pcb_calculator/datafile_read_write.cpp

322 lines
8.7 KiB
C++

/**
* @file datafile_read_write.cpp
*/
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 Jean-Pierre Charras
* Copyright (C) 1992-2021 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 3
* 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, see <http://www.gnu.org/licenses/>.
*/
#include <wx/app.h>
#include <wx/msgdlg.h>
#include <build_version.h>
#include <calculator_panels/panel_regulator.h>
#include <class_regulator_data.h>
#include <datafile_read_write.h>
#include <string_utils.h>
#include <locale_io.h>
#include <macros.h>
#include <pcb_calculator_datafile_lexer.h>
#include <pcb_calculator_frame.h>
#include <pgm_base.h>
using namespace PCBCALC_DATA_T;
static const char* getTokenName( T aTok )
{
return PCB_CALCULATOR_DATAFILE_LEXER::TokenName( aTok );
}
bool PANEL_REGULATOR::ReadDataFile()
{
FILE* file = wxFopen( GetDataFilename(), wxT( "rt" ) );
if( file == nullptr )
return false;
// Switch the locale to standard C (needed to read/write floating point numbers)
LOCALE_IO toggle;
m_RegulatorList.Clear();
PCB_CALCULATOR_DATAFILE* datafile = new PCB_CALCULATOR_DATAFILE( &m_RegulatorList );
// dataReader dtor will close file
FILE_LINE_READER dataReader( file, GetDataFilename() );
PCB_CALCULATOR_DATAFILE_PARSER datafile_parser( &dataReader );
try
{
datafile_parser.Parse( datafile );
}
catch( const IO_ERROR& ioe )
{
delete datafile;
wxString msg = ioe.What();
msg += wxChar('\n');
msg += _("Data file error.");
wxMessageBox( msg );
return false;
}
m_choiceRegulatorSelector->Clear();
m_choiceRegulatorSelector->Append( m_RegulatorList.GetRegList() );
SelectLastSelectedRegulator();
delete datafile;
return true;
}
bool PANEL_REGULATOR::WriteDataFile()
{
// Switch the locale to standard C (needed to read/write floating point numbers)
LOCALE_IO toggle;
auto datafile = std::make_unique<PCB_CALCULATOR_DATAFILE>( &m_RegulatorList );
try
{
FILE_OUTPUTFORMATTER formatter( GetDataFilename() );
int nestlevel = datafile->WriteHeader( &formatter );
datafile->Format( &formatter, nestlevel );
while( nestlevel-- )
formatter.Print( nestlevel, ")\n" );
}
catch( const IO_ERROR& )
{
return false;
}
m_RegulatorListChanged = false;
return true;
}
PCB_CALCULATOR_DATAFILE::PCB_CALCULATOR_DATAFILE( REGULATOR_LIST * aList )
{
m_list = aList;
}
static const char* regtype_str[] =
{
"normal", "3terminal"
};
int PCB_CALCULATOR_DATAFILE::WriteHeader( OUTPUTFORMATTER* aFormatter ) const
{
int nestlevel = 0;
aFormatter->Print( nestlevel++, "(datafile\n");
aFormatter->Print( nestlevel++, "(version 2)\n" );
aFormatter->Print( nestlevel++, "(date %s)\n",
aFormatter->Quotew( GetISO8601CurrentDateTime() ).c_str() );
aFormatter->Print( nestlevel++, "(tool %s)\n",
aFormatter->Quotew( Pgm().App().GetAppName() +
wxChar(' ') + GetBuildVersion() ).c_str() );
return nestlevel;
}
void PCB_CALCULATOR_DATAFILE::Format( OUTPUTFORMATTER* aFormatter,
int aNestLevel ) const
{
// Write regulators list:
aFormatter->Print( aNestLevel++, "(%s\n", getTokenName( T_regulators ) );
for( REGULATOR_DATA* item : m_list->m_List )
{
aFormatter->Print( aNestLevel, "(%s %s\n", getTokenName( T_regulator ),
aFormatter->Quotew( item->m_Name ).c_str() );
aFormatter->Print( aNestLevel + 1, "(%s %g)\n", getTokenName( T_reg_vref_min ),
item->m_VrefMin );
aFormatter->Print( aNestLevel + 1, "(%s %g)\n", getTokenName( T_reg_vref_typ ),
item->m_VrefTyp );
aFormatter->Print( aNestLevel + 1, "(%s %g)\n", getTokenName( T_reg_vref_max ),
item->m_VrefMax );
if( item->m_Type == 1 )
{
aFormatter->Print( aNestLevel + 1, "(%s %g)\n", getTokenName( T_reg_iadj_typ ),
item->m_IadjTyp );
aFormatter->Print( aNestLevel + 1, "(%s %g)\n", getTokenName( T_reg_iadj_max ),
item->m_IadjMax );
}
aFormatter->Print( aNestLevel+1, "(%s %s)\n", getTokenName( T_reg_type ),
regtype_str[item->m_Type] );
aFormatter->Print( aNestLevel, ")\n" );
}
aFormatter->Print( --aNestLevel, ")\n" );
}
void PCB_CALCULATOR_DATAFILE::Parse( PCB_CALCULATOR_DATAFILE_PARSER* aParser )
{
aParser->Parse( this );
}
PCB_CALCULATOR_DATAFILE_PARSER::PCB_CALCULATOR_DATAFILE_PARSER( LINE_READER* aReader ) :
PCB_CALCULATOR_DATAFILE_LEXER( aReader )
{
}
PCB_CALCULATOR_DATAFILE_PARSER::PCB_CALCULATOR_DATAFILE_PARSER( char* aLine,
const wxString& aSource ) :
PCB_CALCULATOR_DATAFILE_LEXER( aLine, aSource )
{
}
void PCB_CALCULATOR_DATAFILE_PARSER::Parse( PCB_CALCULATOR_DATAFILE* aDataList )
{
T token;
while( ( token = NextTok() ) != T_EOF)
{
if( token == T_LEFT )
{
token = NextTok();
if( token == T_regulators )
{
ParseRegulatorDescr( aDataList );
continue;
}
}
}
}
void PCB_CALCULATOR_DATAFILE_PARSER::ParseRegulatorDescr( PCB_CALCULATOR_DATAFILE* aDataList )
{
T token;
wxString name;
double vrefmin, vreftyp, vrefmax = 0.0;
double iadjtyp, iadjmax = 0.0;
auto parseToken = [&]()
{
double val;
token = NextTok();
if( token != T_NUMBER )
Expecting( T_NUMBER );
sscanf( CurText(), "%lf", &val );
NeedRIGHT();
return val;
};
int type;
while( ( token = NextTok() ) != T_RIGHT )
{
if( token == T_EOF)
Unexpected( T_EOF );
if( token == T_LEFT )
token = NextTok();
if( token == T_regulator )
{
type = 0;
vrefmin = 0.0;
vreftyp = 0.0;
vrefmax = 0.0;
iadjtyp = 0.0;
iadjmax = 0.0;
// Read name
token = NextTok();
name = From_UTF8( CurText() );
while( ( token = NextTok() ) != T_RIGHT )
{
if( token == T_EOF)
Unexpected( T_EOF );
if( token == T_LEFT )
token = NextTok();
switch( token )
{
// Parse legacy entry
case T_reg_vref:
vreftyp = parseToken();
vrefmin = vreftyp;
vrefmax = vreftyp;
break;
case T_reg_vref_min: vrefmin = parseToken(); break;
case T_reg_vref_typ: vreftyp = parseToken(); break;
case T_reg_vref_max: vrefmax = parseToken(); break;
// Parse legacy entry
case T_reg_iadj:
iadjtyp = parseToken();
iadjmax = iadjtyp;
break;
case T_reg_iadj_typ: iadjtyp = parseToken(); break;
case T_reg_iadj_max: iadjmax = parseToken(); break;
case T_reg_type: // type: normal or 3 terminal reg
token = NextTok();
if( strcasecmp( CurText(), regtype_str[0] ) == 0 )
type = 0;
else if( strcasecmp( CurText(), regtype_str[1] ) == 0 )
type = 1;
else
Unexpected( CurText() );
NeedRIGHT();
break;
default:
Unexpected( CurText() );
break;
}
}
if( ! name.IsEmpty() )
{
REGULATOR_DATA* new_item = new REGULATOR_DATA( name, vrefmin, vreftyp, vrefmax,
type, iadjtyp, iadjmax );
aDataList->m_list->Add( new_item );
}
}
}
}