//**************************************************************************************************
//                                        CmdNgSpiceOPT.cpp                                        *
//                                       -------------------                                       *
// Started     : 2006-08-23                                                                        *
// Last Update : 2018-11-12                                                                        *
// Copyright   : (C) 2006-2018 MSWaters                                                            *
//**************************************************************************************************

//**************************************************************************************************
//                                                                                                 *
//      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.                    *
//                                                                                                 *
//**************************************************************************************************

#include "CmdNgSpiceOPT.hpp"

//**************************************************************************************************
// Constructor.

CmdNgSpiceOPT::CmdNgSpiceOPT( void ) : CmdBase( )
{
  bSetDefaults( );
}

//**************************************************************************************************
// Destructor.

CmdNgSpiceOPT::~CmdNgSpiceOPT( )
{
}

//**************************************************************************************************
// Check that the object attributes are valid.
//
// Return Values :
//   true  - Success
//   false - Failure

bool  CmdNgSpiceOPT::bValidate( void )
{
  wxString  os1=wxT("Invalid value for ");
  double    df1;
  long      li1;

  CmdBase::bValidate( );

  if( ! CnvtType::bStrToFlt( m_osABSTOL  , &df1 ) ) SetErrMsg( os1 + wxT("ABSTOL.")   );
  if( ! CnvtType::bStrToFlt( m_osCHGTOL  , &df1 ) ) SetErrMsg( os1 + wxT("CHGTOL.")   );
  if( ! CnvtType::bStrToFlt( m_osCONVABSS, &df1 ) ) SetErrMsg( os1 + wxT("CONVABSS.") );
  if( ! CnvtType::bStrToFlt( m_osCONVSTEP, &df1 ) ) SetErrMsg( os1 + wxT("CONVSTEP.") );
  if( ! CnvtType::bStrToFlt( m_osDEFAD   , &df1 ) ) SetErrMsg( os1 + wxT("DEFAD.")    );
  if( ! CnvtType::bStrToFlt( m_osDEFAS   , &df1 ) ) SetErrMsg( os1 + wxT("DEFAS.")    );
  if( ! CnvtType::bStrToFlt( m_osDEFL    , &df1 ) ) SetErrMsg( os1 + wxT("DEFL.")     );
  if( ! CnvtType::bStrToFlt( m_osDEFW    , &df1 ) ) SetErrMsg( os1 + wxT("DEFW.")     );
  if( ! CnvtType::bStrToFlt( m_osGMIN    , &df1 ) ) SetErrMsg( os1 + wxT("GMIN.")     );
  if( ! CnvtType::bStrToFlt( m_osPIVREL  , &df1 ) ) SetErrMsg( os1 + wxT("PIVREL.")   );
  if( ! CnvtType::bStrToFlt( m_osPIVTOL  , &df1 ) ) SetErrMsg( os1 + wxT("PIVTOL.")   );
  if( ! CnvtType::bStrToFlt( m_osRAMPTIME, &df1 ) ) SetErrMsg( os1 + wxT("RAMPTIME.") );
  if( ! CnvtType::bStrToFlt( m_osRELTOL  , &df1 ) ) SetErrMsg( os1 + wxT("RELTOL.")   );
  if( ! CnvtType::bStrToFlt( m_osRSERIES , &df1 ) ) SetErrMsg( os1 + wxT("RSERIES.")  );
  if( ! CnvtType::bStrToFlt( m_osRSHUNT  , &df1 ) ) SetErrMsg( os1 + wxT("RSHUNT.")   );
  if( ! CnvtType::bStrToFlt( m_osTEMP    , &df1 ) ) SetErrMsg( os1 + wxT("TEMP.")     );
  if( ! CnvtType::bStrToFlt( m_osTNOM    , &df1 ) ) SetErrMsg( os1 + wxT("TNOM.")     );
  if( ! CnvtType::bStrToFlt( m_osTRTOL   , &df1 ) ) SetErrMsg( os1 + wxT("TRTOL.")    );
  if( ! CnvtType::bStrToFlt( m_osVNTOL   , &df1 ) ) SetErrMsg( os1 + wxT("VNTOL.")    );

  if( ! CnvtType::bStrToInt( m_osGMINSTEP, &li1 ) ) SetErrMsg( os1 + wxT("GMINSTEP.") );
  if( ! CnvtType::bStrToInt( m_osITL1    , &li1 ) ) SetErrMsg( os1 + wxT("ITL1.")     );
  if( ! CnvtType::bStrToInt( m_osITL2    , &li1 ) ) SetErrMsg( os1 + wxT("ITL2.")     );
  if( ! CnvtType::bStrToInt( m_osITL3    , &li1 ) ) SetErrMsg( os1 + wxT("ITL3.")     );
  if( ! CnvtType::bStrToInt( m_osITL4    , &li1 ) ) SetErrMsg( os1 + wxT("ITL4.")     );
  if( ! CnvtType::bStrToInt( m_osITL5    , &li1 ) ) SetErrMsg( os1 + wxT("ITL5.")     );
  if( ! CnvtType::bStrToInt( m_osITL6    , &li1 ) ) SetErrMsg( os1 + wxT("ITL6.")     );
  if( ! CnvtType::bStrToInt( m_osMAXEVIT , &li1 ) ) SetErrMsg( os1 + wxT("MAXEVIT.")  );
  if( ! CnvtType::bStrToInt( m_osMAXOPALT, &li1 ) ) SetErrMsg( os1 + wxT("MAXOPALT.") );
  if( ! CnvtType::bStrToInt( m_osMAXORD  , &li1 ) ) SetErrMsg( os1 + wxT("MAXORD.")   );
  if( ! CnvtType::bStrToInt( m_osMAXWARNS, &li1 ) ) SetErrMsg( os1 + wxT("MAXWARNS.") );
  if( ! CnvtType::bStrToInt( m_osSRCSTEPS, &li1 ) ) SetErrMsg( os1 + wxT("SRCSTEPS.") );

  if( m_osMETHOD.IsEmpty( ) )                       SetErrMsg( os1 + wxT("METHOD.")   );

  return( bIsValid( ) );
}

//**************************************************************************************************
// Set the object attributes to they're default values.
//
// Return Values :
//   true  - Success
//   false - Failure

bool  CmdNgSpiceOPT::bSetDefaults( void )
{
  CmdBase::bSetDefaults( );

  m_eSimEng    = eSIMR_NGSPICE;
  m_eCmdType   = eCMD_OPT;

  m_osABSTOL   = NGS_ABSTOL;
  m_osCHGTOL   = NGS_CHGTOL;
  m_osCONVABSS = NGS_CONVABSS;
  m_osCONVSTEP = NGS_CONVSTEP;
  m_osDEFAD    = NGS_DEFAD;
  m_osDEFAS    = NGS_DEFAS;
  m_osDEFL     = NGS_DEFL;
  m_osDEFW     = NGS_DEFW;
  m_osGMIN     = NGS_GMIN;
  m_osPIVREL   = NGS_PIVREL;
  m_osPIVTOL   = NGS_PIVTOL;
  m_osRAMPTIME = NGS_RAMPTIME;
  m_osRELTOL   = NGS_RELTOL;
  m_osRSERIES  = NGS_RSERIES;
  m_osRSHUNT   = NGS_RSHUNT;
  m_osTEMP     = NGS_TEMP;
  m_osTNOM     = NGS_TNOM;
  m_osTRTOL    = NGS_TRTOL;
  m_osVNTOL    = NGS_VNTOL;

  m_osGMINSTEP = NGS_GMINSTEP;
  m_osITL1     = NGS_ITL1;
  m_osITL2     = NGS_ITL2;
  m_osITL3     = NGS_ITL3;
  m_osITL4     = NGS_ITL4;
  m_osITL5     = NGS_ITL5;
  m_osITL6     = NGS_ITL6;
  m_osMAXEVIT  = NGS_MAXEVIT;
  m_osMAXOPALT = NGS_MAXOPALT;
  m_osMAXORD   = NGS_MAXORD;
  m_osMAXWARNS = NGS_MAXWARNS;
  m_osNUMDGT   = NGS_NUMDGT;
  m_osSRCSTEPS = NGS_SRCSTEPS;
  m_osWIDTH    = NGS_WIDTH;

  m_osMETHOD   = NGS_METHOD;
  m_osUNITS    = NGS_UNITS;

  m_bBADMOS3   = NGS_BADMOS3;
  m_bINTERP    = NGS_INTERP;
  m_bNOOPAC    = NGS_NOOPAC;
  m_bNOOPALT   = NGS_NOOPALT;
  m_bOPTS      = NGS_OPTS;
  m_bTRYTOCOM  = NGS_TRYTOCOM;
  m_bWARN      = NGS_WARN;

  return( true );
}

//**************************************************************************************************
// Parse the command string.
//
// Eg.s : .OPTIONS NOPAGE
//        .OPTIONS NOPAGE ABSTOL=1.1p CHGTOL=11.0f CONVABSS=0.2 CONVSTEP=0.5 DEFAD=10.0f DEFAS=10.0f
//                 DEFL=110.0u DEFW=110.0u GMIN=1.1p GMINSTEP=1 ITL1=110 ITL2=60 ITL3=5 ITL4=20
//                 ITL5=2000 ITL6=20 MAXEVIT=6 MAXOPALT=6 MAXORD=3 MAXWARNS=6 PIVREL=2.0m
//                 PIVTOL=110.0f RAMPTIME=1.0 RELTOL=2.0m RSERIES=1.0 RSHUNT=2.0E11 SRCSTEPS=20
//                 TEMP=30.0 TNOM=30.0 TRTOL=8.0 VNTOL=2.0u METHOD=GEAR BADMOS3 INTERP NOOPAC
//                 NOOPALT OPTS TRYTOCOM WARN
//
// Return Values :
//   true  - Success
//   false - Failure

bool  CmdNgSpiceOPT::bParse( void )
{
  wxStringTokenizer  ostk1;
  wxString           os1, os2;
  size_t             sz1;

  // Clear the object attributes
  os1 = (wxString &) *this;
  bSetDefaults( );
  assign( os1 );

  // Tokenize the command string
  ostk1.SetString( *this );
  if( ostk1.CountTokens( ) < 2 ) return( bValidate( ) );

  // Check command type
  os1 = ostk1.GetNextToken( ).Left( 4 ).Upper( );
  if( os1 != wxT(".OPT") )       return( bValidate( ) );

  // Extract each parameter value
  while( ostk1.HasMoreTokens( ) )
  {
    // Extract the field name and the associated value
    os1 = ostk1.GetNextToken( );
    os2 = wxT("");
    if( (sz1=os1.find( wxT("=") )) != wxString::npos )
    {
      os2 = os1.Right( os1.Length( )-sz1-1 );
      os1 = os1.Left( sz1 );
    }

    // Set the attribute value
    if(      os1.StartsWith( wxT("ABSTOL")   ) ) m_osABSTOL   = os2;
    else if( os1.StartsWith( wxT("CHGTOL")   ) ) m_osCHGTOL   = os2;
    else if( os1.StartsWith( wxT("CONVABSS") ) ) m_osCONVABSS = os2;
    else if( os1.StartsWith( wxT("CONVSTEP") ) ) m_osCONVSTEP = os2;
    else if( os1.StartsWith( wxT("DEFAD")    ) ) m_osDEFAD    = os2;
    else if( os1.StartsWith( wxT("DEFAS")    ) ) m_osDEFAS    = os2;
    else if( os1.StartsWith( wxT("DEFL")     ) ) m_osDEFL     = os2;
    else if( os1.StartsWith( wxT("DEFW")     ) ) m_osDEFW     = os2;
    else if( os1.StartsWith( wxT("GMIN")     ) ) m_osGMIN     = os2;
    else if( os1.StartsWith( wxT("PIVREL")   ) ) m_osPIVREL   = os2;
    else if( os1.StartsWith( wxT("PIVTOL")   ) ) m_osPIVTOL   = os2;
    else if( os1.StartsWith( wxT("RAMPTIME") ) ) m_osRAMPTIME = os2;
    else if( os1.StartsWith( wxT("RELTOL")   ) ) m_osRELTOL   = os2;
    else if( os1.StartsWith( wxT("RSERIES")  ) ) m_osRSERIES  = os2;
    else if( os1.StartsWith( wxT("RSHUNT")   ) ) m_osRSHUNT   = os2;
    else if( os1.StartsWith( wxT("TEMP")     ) ) m_osTEMP     = os2;
    else if( os1.StartsWith( wxT("TNOM")     ) ) m_osTNOM     = os2;
    else if( os1.StartsWith( wxT("TRTOL")    ) ) m_osTRTOL    = os2;
    else if( os1.StartsWith( wxT("VNTOL")    ) ) m_osVNTOL    = os2;

    else if( os1.StartsWith( wxT("GMINSTEP") ) ) m_osGMINSTEP = os2;
    else if( os1.StartsWith( wxT("ITL1")     ) ) m_osITL1     = os2;
    else if( os1.StartsWith( wxT("ITL2")     ) ) m_osITL2     = os2;
    else if( os1.StartsWith( wxT("ITL3")     ) ) m_osITL3     = os2;
    else if( os1.StartsWith( wxT("ITL4")     ) ) m_osITL4     = os2;
    else if( os1.StartsWith( wxT("ITL5")     ) ) m_osITL5     = os2;
    else if( os1.StartsWith( wxT("ITL6")     ) ) m_osITL6     = os2;
    else if( os1.StartsWith( wxT("MAXEVIT")  ) ) m_osMAXEVIT  = os2;
    else if( os1.StartsWith( wxT("MAXOPALT") ) ) m_osMAXOPALT = os2;
    else if( os1.StartsWith( wxT("MAXORD")   ) ) m_osMAXORD   = os2;
    else if( os1.StartsWith( wxT("MAXWARNS") ) ) m_osMAXWARNS = os2;
    else if( os1.StartsWith( wxT("SRCSTEPS") ) ) m_osSRCSTEPS = os2;

    else if( os1.StartsWith( wxT("METHOD")   ) ) m_osMETHOD   = os2;

    else if( os1.StartsWith( wxT("BADMOS3")  ) ) m_bBADMOS3   = true;
    else if( os1.StartsWith( wxT("INTERP")   ) ) m_bINTERP    = true;
    else if( os1.StartsWith( wxT("NOOPAC")   ) ) m_bNOOPAC    = true;
    else if( os1.StartsWith( wxT("NOOPALT")  ) ) m_bNOOPALT   = true;
    else if( os1.StartsWith( wxT("OPTS")     ) ) m_bOPTS      = true;
    else if( os1.StartsWith( wxT("TRYTOCOM") ) ) m_bTRYTOCOM  = true;
    else if( os1.StartsWith( wxT("WARN")     ) ) m_bWARN      = true;

    else if( os1.StartsWith( wxT("NOPAGE")   ) ) { ; }
  }

  return( bValidate( ) );
}

//**************************************************************************************************
// Format the command string.
//
// Return Values :
//   true  - Success
//   false - Failure

bool  CmdNgSpiceOPT::bFormat( void )
{
  wxString  os1, os2;
  double    df1, df2;
  long      li1, li2;

  os1 = wxT(".OPTIONS NOPAGE");

  CnvtType::bStrToFlt( m_osABSTOL  , &df1 );
  CnvtType::bStrToFlt( NGS_ABSTOL  , &df2 );
  if( df1 != df2 )                  os1 << wxT(" ABSTOL=")   << m_osABSTOL;

  CnvtType::bStrToFlt( m_osCHGTOL  , &df1 );
  CnvtType::bStrToFlt( NGS_CHGTOL  , &df2 );
  if( df1 != df2 )                  os1 << wxT(" CHGTOL=")   << m_osCHGTOL;

  CnvtType::bStrToFlt( m_osCONVABSS, &df1 );
  CnvtType::bStrToFlt( NGS_CONVABSS, &df2 );
  if( df1 != df2 )                  os1 << wxT(" CONVABSS=") << m_osCONVABSS;

  CnvtType::bStrToFlt( m_osCONVSTEP, &df1 );
  CnvtType::bStrToFlt( NGS_CONVSTEP, &df2 );
  if( df1 != df2 )                  os1 << wxT(" CONVSTEP=") << m_osCONVSTEP;

  CnvtType::bStrToFlt( m_osDEFAD   , &df1 );
  CnvtType::bStrToFlt( NGS_DEFAD   , &df2 );
  if( df1 != df2 )                  os1 << wxT(" DEFAD=")    << m_osDEFAD;

  CnvtType::bStrToFlt( m_osDEFAS   , &df1 );
  CnvtType::bStrToFlt( NGS_DEFAS   , &df2 );
  if( df1 != df2 )                  os1 << wxT(" DEFAS=")    << m_osDEFAS;

  CnvtType::bStrToFlt( m_osDEFL    , &df1 );
  CnvtType::bStrToFlt( NGS_DEFL    , &df2 );
  if( df1 != df2 )                  os1 << wxT(" DEFL=")     << m_osDEFL;

  CnvtType::bStrToFlt( m_osDEFW    , &df1 );
  CnvtType::bStrToFlt( NGS_DEFW    , &df2 );
  if( df1 != df2 )                  os1 << wxT(" DEFW=")     << m_osDEFW;

  CnvtType::bStrToFlt( m_osGMIN    , &df1 );
  CnvtType::bStrToFlt( NGS_GMIN    , &df2 );
  if( df1 != df2 )                  os1 << wxT(" GMIN=")     << m_osGMIN;

  CnvtType::bStrToFlt( m_osPIVREL  , &df1 );
  CnvtType::bStrToFlt( NGS_PIVREL  , &df2 );
  if( df1 != df2 )                  os1 << wxT(" PIVREL=")   << m_osPIVREL;

  CnvtType::bStrToFlt( m_osPIVTOL  , &df1 );
  CnvtType::bStrToFlt( NGS_PIVTOL  , &df2 );
  if( df1 != df2 )                  os1 << wxT(" PIVTOL=")   << m_osPIVTOL;

  CnvtType::bStrToFlt( m_osRAMPTIME, &df1 );
  CnvtType::bStrToFlt( NGS_RAMPTIME, &df2 );
  if( df1 != df2 )                  os1 << wxT(" RAMPTIME=") << m_osRAMPTIME;

  CnvtType::bStrToFlt( m_osRELTOL  , &df1 );
  CnvtType::bStrToFlt( NGS_RELTOL  , &df2 );
  if( df1 != df2 )                  os1 << wxT(" RELTOL=")   << m_osRELTOL;

  CnvtType::bStrToFlt( m_osRSERIES , &df1 );
  CnvtType::bStrToFlt( NGS_RSERIES , &df2 );
  if( df1 != df2 )                  os1 << wxT(" RSERIES=")  << m_osRSERIES;

  CnvtType::bStrToFlt( m_osRSHUNT  , &df1 );
  CnvtType::bStrToFlt( NGS_RSHUNT  , &df2 );
  if( df1 != df2 )                  os1 << wxT(" RSHUNT=")   << m_osRSHUNT;

  CnvtType::bStrToFlt( m_osTEMP    , &df1 );
  CnvtType::bStrToFlt( NGS_TEMP    , &df2 );
  if( df1 != df2 )                  os1 << wxT(" TEMP=")     << m_osTEMP;

  CnvtType::bStrToFlt( m_osTNOM    , &df1 );
  CnvtType::bStrToFlt( NGS_TNOM    , &df2 );
  if( df1 != df2 )                  os1 << wxT(" TNOM=")     << m_osTNOM;

  CnvtType::bStrToFlt( m_osTRTOL   , &df1 );
  CnvtType::bStrToFlt( NGS_TRTOL   , &df2 );
  if( df1 != df2 )                  os1 << wxT(" TRTOL=")    << m_osTRTOL;

  CnvtType::bStrToFlt( m_osVNTOL   , &df1 );
  CnvtType::bStrToFlt( NGS_VNTOL   , &df2 );
  if( df1 != df2 )                  os1 << wxT(" VNTOL=")    << m_osVNTOL;

  CnvtType::bStrToInt( m_osGMINSTEP, &li1 );
  CnvtType::bStrToInt( NGS_GMINSTEP, &li2 );
  if( li1 != li2 )                  os1 << wxT(" GMINSTEP=") << m_osGMINSTEP;

  CnvtType::bStrToInt( m_osITL1    , &li1 );
  CnvtType::bStrToInt( NGS_ITL1    , &li2 );
  if( li1 != li2 )                  os1 << wxT(" ITL1=")     << m_osITL1;

  CnvtType::bStrToInt( m_osITL2    , &li1 );
  CnvtType::bStrToInt( NGS_ITL2    , &li2 );
  if( li1 != li2 )                  os1 << wxT(" ITL2=")     << m_osITL2;

  CnvtType::bStrToInt( m_osITL3    , &li1 );
  CnvtType::bStrToInt( NGS_ITL3    , &li2 );
  if( li1 != li2 )                  os1 << wxT(" ITL3=")     << m_osITL3;

  CnvtType::bStrToInt( m_osITL4    , &li1 );
  CnvtType::bStrToInt( NGS_ITL4    , &li2 );
  if( li1 != li2 )                  os1 << wxT(" ITL4=")     << m_osITL4;

  CnvtType::bStrToInt( m_osITL5    , &li1 );
  CnvtType::bStrToInt( NGS_ITL5    , &li2 );
  if( li1 != li2 )                  os1 << wxT(" ITL5=")     << m_osITL5;

  CnvtType::bStrToInt( m_osITL6    , &li1 );
  CnvtType::bStrToInt( NGS_ITL6    , &li2 );
  if( li1 != li2 )                  os1 << wxT(" ITL6=")     << m_osITL6;

  CnvtType::bStrToInt( m_osMAXEVIT , &li1 );
  CnvtType::bStrToInt( NGS_MAXEVIT , &li2 );
  if( li1 != li2 )                  os1 << wxT(" MAXEVIT=")  << m_osMAXEVIT;

  CnvtType::bStrToInt( m_osMAXOPALT, &li1 );
  CnvtType::bStrToInt( NGS_MAXOPALT, &li2 );
  if( li1 != li2 )                  os1 << wxT(" MAXOPALT=") << m_osMAXOPALT;

  CnvtType::bStrToInt( m_osMAXORD  , &li1 );
  CnvtType::bStrToInt( NGS_MAXORD  , &li2 );
  if( li1 != li2 )                  os1 << wxT(" MAXORD=")   << m_osMAXORD;

  CnvtType::bStrToInt( m_osMAXWARNS, &li1 );
  CnvtType::bStrToInt( NGS_MAXWARNS, &li2 );
  if( li1 != li2 )                  os1 << wxT(" MAXWARNS=") << m_osMAXWARNS;

  CnvtType::bStrToInt( m_osNUMDGT  , &li1 );
  CnvtType::bStrToInt( NGS_NUMDGT  , &li2 );
  if( li1 != li2 )                  os1 << wxT(" NUMDGT=")   << m_osNUMDGT;

  CnvtType::bStrToInt( m_osSRCSTEPS, &li1 );
  CnvtType::bStrToInt( NGS_SRCSTEPS, &li2 );
  if( li1 != li2 )                  os1 << wxT(" SRCSTEPS=") << m_osSRCSTEPS;

  CnvtType::bStrToInt( m_osWIDTH   , &li1 );
  CnvtType::bStrToInt( NGS_WIDTH   , &li2 );
  if( li1 != li2 )                  os1 << wxT(" WIDTH=")    << m_osWIDTH;

  os2 = m_osMETHOD.Upper( );
  if( os2.CmpNoCase( NGS_METHOD ) ) os1 << wxT(" METHOD=")   << os2;

  os2 = m_osUNITS .Upper( );
  if( os2.CmpNoCase( NGS_UNITS  ) ) os1 << wxT(" UNITS=")    << os2;

  if( m_bBADMOS3  != NGS_BADMOS3  ) os1 << wxT(" BADMOS3");
  if( m_bINTERP   != NGS_INTERP   ) os1 << wxT(" INTERP");
  if( m_bNOOPAC   != NGS_NOOPAC   ) os1 << wxT(" NOOPAC");
  if( m_bNOOPALT  != NGS_NOOPALT  ) os1 << wxT(" NOOPALT");
  if( m_bOPTS     != NGS_OPTS     ) os1 << wxT(" OPTS");
  if( m_bTRYTOCOM != NGS_TRYTOCOM ) os1 << wxT(" TRYTOCOM");
  if( m_bWARN     != NGS_WARN     ) os1 << wxT(" WARN");

  assign( os1 );

  return( bValidate( ) );
}

//**************************************************************************************************
// Copy the contents of a CmdGnuCapAC object.
//
// Argument List :
//   roCmdOPT - A reference to a CmdGnuCapOPT object
//
// Return Values :
//   A reference to this object

CmdNgSpiceOPT & CmdNgSpiceOPT::operator = ( const CmdGnuCapOPT & roCmdOPT )
{
  (CmdBase &) *this = (CmdBase &) roCmdOPT;

  m_osABSTOL   = roCmdOPT.m_osABSTOL;
  m_osCHGTOL   = roCmdOPT.m_osCHGTOL;
//m_osCONVABSS = roCmdOPT.m_osCONVABSS;
//m_osCONVSTEP = roCmdOPT.m_osCONVSTEP;
  m_osDEFAD    = roCmdOPT.m_osDEFAD;
  m_osDEFAS    = roCmdOPT.m_osDEFAS;
  m_osDEFL     = roCmdOPT.m_osDEFL;
  m_osDEFW     = roCmdOPT.m_osDEFW;
  m_osGMIN     = roCmdOPT.m_osGMIN;
//m_osRAMPTIME = roCmdOPT.m_osRAMPTIME;
  m_osRELTOL   = roCmdOPT.m_osRELTOL;
//m_osRSERIES  = roCmdOPT.m_osRSERIES;
//m_osRSHUNT   = roCmdOPT.m_osRSHUNT;
  m_osTEMP     = roCmdOPT.m_osTEMP;
  m_osTNOM     = roCmdOPT.m_osTNOM;
  m_osTRTOL    = roCmdOPT.m_osTRTOL;
  m_osVNTOL    = roCmdOPT.m_osVNTOL;

//m_osGMINSTEP = roCmdOPT.m_osGMINSTEP;
  m_osITL1     = roCmdOPT.m_osITL1;
  m_osITL2     = roCmdOPT.m_osITL2;
  m_osITL3     = roCmdOPT.m_osITL3;
  m_osITL4     = roCmdOPT.m_osITL4;
  m_osITL5     = roCmdOPT.m_osITL5;
  m_osITL6     = roCmdOPT.m_osITL6;
//m_osMAXEVIT  = roCmdOPT.m_osMAXEVIT;
//m_osMAXOPALT = roCmdOPT.m_osMAXOPALT;
//m_osMAXORD   = roCmdOPT.m_osMAXORD;
//m_osMAXWARNS = roCmdOPT.m_osMAXWARNS;
//m_osSRCSTEPS = roCmdOPT.m_osSRCSTEPS;

  m_osMETHOD   = roCmdOPT.m_osMETHOD;

//m_bBADMOS3   = roCmdOPT.m_bBADMOS3;
//m_bINTERP    = roCmdOPT.m_bINTERP;
//m_bNOOPAC    = roCmdOPT.m_bNOOPAC;
//m_bNOOPALT   = roCmdOPT.m_bNOOPALT;
  m_bOPTS      = roCmdOPT.m_bOPTS;
//m_bTRYTOCOM  = roCmdOPT.m_bTRYTOCOM;
//m_bWARN      = roCmdOPT.m_bWARN;

  bFormat( );

  return( *this );
}

//**************************************************************************************************
// Print the object attributes.
//
// Argument List :
//   rosPrefix - A prefix to every line displayed (usually just spaces)

void  CmdNgSpiceOPT::Print( const wxString & rosPrefix )
{
  CmdBase::Print( rosPrefix + wxT("CmdBase::") );

  std::cout << rosPrefix.mb_str( ) << "m_osABSTOL   : " << m_osABSTOL  .mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osCHGTOL   : " << m_osCHGTOL  .mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osCONVABSS : " << m_osCONVABSS.mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osCONVSTEP : " << m_osCONVSTEP.mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osDEFAD    : " << m_osDEFAD   .mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osDEFAS    : " << m_osDEFAS   .mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osDEFL     : " << m_osDEFL    .mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osDEFW     : " << m_osDEFW    .mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osGMIN     : " << m_osGMIN    .mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osPIVREL   : " << m_osPIVREL  .mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osPIVTOL   : " << m_osPIVTOL  .mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osRAMPTIME : " << m_osRAMPTIME.mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osRELTOL   : " << m_osRELTOL  .mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osRSERIES  : " << m_osRSERIES .mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osRSHUNT   : " << m_osRSHUNT  .mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osTEMP     : " << m_osTEMP    .mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osTNOM     : " << m_osTNOM    .mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osTRTOL    : " << m_osTRTOL   .mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osVNTOL    : " << m_osVNTOL   .mb_str( ) << '\n';

  std::cout << rosPrefix.mb_str( ) << "m_osGMINSTEP : " << m_osGMINSTEP.mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osITL1     : " << m_osITL1    .mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osITL2     : " << m_osITL2    .mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osITL3     : " << m_osITL3    .mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osITL4     : " << m_osITL4    .mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osITL5     : " << m_osITL5    .mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osITL6     : " << m_osITL6    .mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osMAXEVIT  : " << m_osMAXEVIT .mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osMAXOPALT : " << m_osMAXOPALT.mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osMAXORD   : " << m_osMAXORD  .mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osMAXWARNS : " << m_osMAXWARNS.mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osSRCSTEPS : " << m_osSRCSTEPS.mb_str( ) << '\n';

  std::cout << rosPrefix.mb_str( ) << "m_osMETHOD   : " << m_osMETHOD  .mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_bBADMOS3   : " << (m_bBADMOS3  ? "true" : "false") << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_bINTERP    : " << (m_bINTERP   ? "true" : "false") << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_bNOOPAC    : " << (m_bNOOPAC   ? "true" : "false") << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_bNOOPALT   : " << (m_bNOOPALT  ? "true" : "false") << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_bOPTS      : " << (m_bOPTS     ? "true" : "false") << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_bTRYTOCOM  : " << (m_bTRYTOCOM ? "true" : "false") << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_bWARN      : " << (m_bWARN     ? "true" : "false") << '\n';
}

//**************************************************************************************************
//                                          Test Utility                                           *
//**************************************************************************************************

#ifdef TEST_CMDNGSPICEOPT

using  namespace  std;

// Function prototypes

void  Usage( char * psAppName );

//**************************************************************************************************

int  main( int argc, char * argv[ ] )
{
  wxString  osCmd;
  wxString  os1;

  // Validate the argument count passed to the application
  if( argc > 2 )           { Usage( argv[ 0 ] ); exit( EXIT_FAILURE ); }

  // Process the command line arguments
  os1 = wxConvLibc.cMB2WC( argv[ 1 ] );
  if( argc > 1 )
  {
    if( os1 == wxT("-h") ) { Usage( argv[ 0 ] ); exit( EXIT_SUCCESS ); }
    else                   { Usage( argv[ 0 ] ); exit( EXIT_FAILURE ); }
  }

  // Display the utility banner
  cout << "\n  Class CmdNgSpiceOPT Test Utility"
       << "\n     Version 1.04 (2015-01-03)\n";

  // Create a NG-SPICE OPTIONS command object
  CmdNgSpiceOPT  oCmd_OPT;

  // Use the following command example to check the formatter and the parser :
  osCmd << wxT(".OPTIONS NOPAGE ABSTOL=1.1p CHGTOL=11.0f CONVABSS=0.2 CONVSTEP=0.5 DEFAD=10.0f ")
        << wxT("DEFAS=10.0f DEFL=110.0u DEFW=110.0u GMIN=1.1p GMINSTEP=1 ITL1=110 ITL2=60 ITL3=5 ")
        << wxT("ITL4=20 ITL5=2000 ITL6=20 MAXEVIT=6 MAXOPALT=6 MAXORD=3 MAXWARNS=6 PIVREL=2.0m ")
        << wxT("PIVTOL=110.0f RAMPTIME=1.0 RELTOL=2.0m RSERIES=1.0 RSHUNT=2.0E11 SRCSTEPS=20 ")
        << wxT("TEMP=30.0 TNOM=30.0 TRTOL=8.0 VNTOL=2.0u METHOD=GEAR BADMOS3 INTERP NOOPAC ")
        << wxT("NOOPALT OPTS TRYTOCOM WARN");

  // Set things up for a formatter test
  oCmd_OPT.m_osABSTOL   = wxT("1.1p");
  oCmd_OPT.m_osCHGTOL   = wxT("11.0f");
  oCmd_OPT.m_osCONVABSS = wxT("0.2");
  oCmd_OPT.m_osCONVSTEP = wxT("0.5");
  oCmd_OPT.m_osDEFAD    = wxT("10.0f");
  oCmd_OPT.m_osDEFAS    = wxT("10.0f");
  oCmd_OPT.m_osDEFL     = wxT("110.0u");
  oCmd_OPT.m_osDEFW     = wxT("110.0u");
  oCmd_OPT.m_osGMIN     = wxT("1.1p");
  oCmd_OPT.m_osGMINSTEP = wxT("1");
  oCmd_OPT.m_osITL1     = wxT("110");
  oCmd_OPT.m_osITL2     = wxT("60");
  oCmd_OPT.m_osITL3     = wxT("5");
  oCmd_OPT.m_osITL4     = wxT("20");
  oCmd_OPT.m_osITL5     = wxT("2000");
  oCmd_OPT.m_osITL6     = wxT("20");
  oCmd_OPT.m_osMAXEVIT  = wxT("6");
  oCmd_OPT.m_osMAXOPALT = wxT("6");
  oCmd_OPT.m_osMAXORD   = wxT("3");
  oCmd_OPT.m_osMAXWARNS = wxT("6");
  oCmd_OPT.m_osPIVREL   = wxT("2.0m");
  oCmd_OPT.m_osPIVTOL   = wxT("110.0f");
  oCmd_OPT.m_osRAMPTIME = wxT("1.0");
  oCmd_OPT.m_osRELTOL   = wxT("2.0m");
  oCmd_OPT.m_osRSERIES  = wxT("1.0");
  oCmd_OPT.m_osRSHUNT   = wxT("2.0E11");
  oCmd_OPT.m_osSRCSTEPS = wxT("20");
  oCmd_OPT.m_osTEMP     = wxT("30.0");
  oCmd_OPT.m_osTNOM     = wxT("30.0");
  oCmd_OPT.m_osTRTOL    = wxT("8.0");
  oCmd_OPT.m_osVNTOL    = wxT("2.0u");
  oCmd_OPT.m_osMETHOD   = wxT("GEAR");
  oCmd_OPT.m_bBADMOS3   = true;
  oCmd_OPT.m_bINTERP    = true;
  oCmd_OPT.m_bNOOPAC    = true;
  oCmd_OPT.m_bNOOPALT   = true;
  oCmd_OPT.m_bOPTS      = true;
  oCmd_OPT.m_bTRYTOCOM  = true;
  oCmd_OPT.m_bWARN      = true;
  cout << "\nRun Formatter     : " << ( oCmd_OPT.bFormat( ) ? "OK" : "FAULT" );
  cout << "\nTest Cmd Format   : " << ( oCmd_OPT == osCmd   ? "OK" : "FAULT" );
  cout << "\nExample Command   : " << osCmd   .mb_str( );
  cout << "\noCmd_OPT Contents : " << oCmd_OPT.mb_str( ) << '\n';

  // Set things up for a parser test
  oCmd_OPT.bSetString( osCmd );
  cout << "\nRun Parser        : " << ( oCmd_OPT.bParse( ) ? "OK" : "FAULT" );
  oCmd_OPT.bFormat( );
  cout << "\nTest Cmd Format   : " << ( oCmd_OPT == osCmd  ? "OK" : "FAULT" );
  cout << "\nExample Command   : " << osCmd   .mb_str( );
  cout << "\noCmd_OPT Contents : " << oCmd_OPT.mb_str( ) << '\n';

  cout << '\n';

  exit( EXIT_SUCCESS );
}

//**************************************************************************************************

void  Usage( char * psAppName )
{
  cout << "\nUsage   : " << psAppName << " [-OPTIONS]"
       << "\nOptions :"
       << "\n  -h : Print usage (this message)\n";
}

#endif // TEST_CMDNGSPICEOPT

//**************************************************************************************************
