//************************************************************************************************** // StrUtils.cpp * // -------------- * // Started : 2008-05-15 * // Last Update : 2016-10-11 * // Copyright : (C) 2008-2016 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 "StrUtils.hpp" //************************************************************************************************** // Compare algorithm for sorting node labels. // // As a general rule node labels are automatically generated and are purely numeric. Where a label // diverges from this form it's often because the user has identified it as having some special // significance. When displayed in a list control on a GUI it's more convenient to have these // labels positioned towards the top. // // Argument List : // rosArg1 - a reference to the first string to be compared // rosArg2 - a reference to the second string to be compared // // Return Values : // If ros1 > ros2 then -1 // If ros1 = ros2 then 0 // If ros1 < ros2 then 1 int iStrCmpNode( const wxString & rosArg1, const wxString & rosArg2 ) { wxChar oc1, oc2; size_t sz1, sz2; long li1, li2; // First look for empty strings sz1 = rosArg1.Len( ); sz2 = rosArg2.Len( ); if( sz1==0 && sz2!=0 ) return( 1 ); if( sz1==0 && sz2==0 ) return( 0 ); if( sz1!=0 && sz2==0 ) return( -1 ); // Now do some simple tests oc1 = rosArg1.at( 0 ); oc2 = rosArg2.at( 0 ); if( wxIsalpha( oc1 ) && wxIsdigit( oc2 ) ) return( -1 ); if( wxIsdigit( oc1 ) && wxIsalpha( oc2 ) ) return( 1 ); // If the node names are purely numeric do the compare if( rosArg1.ToLong( &li1 ) && rosArg2.ToLong( &li2 ) ) { if( li1 > li2 ) return( 1 ); if( li1 == li2 ) return( 0 ); if( li1 < li2 ) return( -1 ); } // It's all got too hard, just compare the labels as component labels return( iStrCmpCpnt( rosArg1, rosArg2 ) ); } //************************************************************************************************** // Compare algorithm for sorting component labels. // // As a rule component labels are comprised of a single letter (signifying the component type) // followed by a number. Where a label diverges from this form it's often because the user has // identified it as having some significance. When displayed in a list control on a GUI it's more // convenient to have these special labels positioned towards the top. Any remaining labels are // simply sorted alphabetically. // // Argument List : // rosArg1 - a reference to the first string to be compared // rosArg2 - a reference to the second string to be compared // // Return Values : // If ros1 > ros2 then -1 // If ros1 = ros2 then 0 // If ros1 < ros2 then 1 int iStrCmpCpnt( const wxString & rosArg1, const wxString & rosArg2 ) { wxString osStr1, osStr2; ulong ulNum1, ulNum2; wxString osEnd1, osEnd2; wxString os1; wxChar oc1; size_t sz1, sz2; // First look for empty strings sz1 = rosArg1.Len( ); sz2 = rosArg2.Len( ); if( sz1==0 && sz2!=0 ) return( 1 ); if( sz1==0 && sz2==0 ) return( 0 ); if( sz1!=0 && sz2==0 ) return( -1 ); // Parse the first alpha and numeric components of the first argument for( sz1=0, osStr1=wxT(""); sz1 sz2 ) return( -1 ); if( sz1 < sz2 ) return( 1 ); // Compare the first numeric component of the two arguments sz1 = osEnd1.Len( ); sz2 = osEnd2.Len( ); if( sz1==0 && sz2==0 ) { if( ulNum1 > ulNum2 ) return( 1 ); if( ulNum1 == ulNum2 ) return( 0 ); if( ulNum2 > ulNum1 ) return( -1 ); } if( sz1 > sz2 ) return( -1 ); else return( 1 ); // If all else fails do it all again //std::cout << "\niStrCmpCpnt( ) : Look out! Re-entrance\n"; return( iStrCmpCpnt( osEnd1, osEnd2 ) ); } //************************************************************************************************** // Compare algorithm for sorting signal source labels. // // Signal source labels form a sub-set of all component labels which, as a general rule, are // comprised of a single letter (signifying the component type) followed by a number. Where a label // diverges from this form it's often because the user has identified it as having some special // significance. When displayed in a list control on a GUI it's more convenient to have these // significant labels positioned towards the top. // // Argument List : // rosArg1 - a reference to the first string to be compared // rosArg2 - a reference to the second string to be compared // // Return Values : // If ros1 > ros2 then -1 // If ros1 = ros2 then 0 // If ros1 < ros2 then 1 int iStrCmpSrc( const wxString & rosArg1, const wxString & rosArg2 ) { eTypeCpnt eCpnt1, eCpnt2; size_t sz1, sz2; // First look for empty strings sz1 = rosArg1.Len( ); sz2 = rosArg2.Len( ); if( sz1==0 && sz2!=0 ) return( 1 ); if( sz1==0 && sz2==0 ) return( 0 ); if( sz1!=0 && sz2==0 ) return( -1 ); // Compare component types eCpnt1 = Component::eGetType( rosArg1 ); eCpnt2 = Component::eGetType( rosArg2 ); switch( eCpnt1 ) { case eCPNT_IVS : sz1 = 5; break; case eCPNT_ICS : sz1 = 4; break; case eCPNT_IND : sz1 = 3; break; case eCPNT_CAP : sz1 = 2; break; case eCPNT_RES : sz1 = 1; break; default : sz1 = 0; break; } switch( eCpnt2 ) { case eCPNT_IVS : sz2 = 5; break; case eCPNT_ICS : sz2 = 4; break; case eCPNT_IND : sz2 = 3; break; case eCPNT_CAP : sz2 = 2; break; case eCPNT_RES : sz2 = 1; break; default : sz2 = 0; break; } if( sz1>0 && sz2>0 ) { if( sz1 > sz2 ) return( -1 ); if( sz1 < sz2 ) return( 1 ); } // It's all got too hard, just compare the labels as component labels return( iStrCmpCpnt( rosArg1, rosArg2 ) ); } //************************************************************************************************** // Reduce a string down so that it can be displayed in a single line. // // (This function is intended for debugging purposes. Multi-line and formated messages can be sent // to std::cout or std::cerr.) // // Argument List : // ros1 - The string to be reformatted // // Return Values : // A reference to string containing a single line const wxString & rosStrToLine( const wxString & ros1 ) { static wxString os1; size_t sz1; char c1; // Copy the input string os1 = ros1; // Remove white-space (space, tab, '\n' & '\r') from both ends of the string os1.Trim( false ); os1.Trim( true ); // Replace '\n' & '\r' within the string with space characters for( sz1=0; sz1 0 ) os1 << wxT(' '); os1 << roas1.Item( sz1 ); } } return( os1 ); } //************************************************************************************************** // Test Utility * //************************************************************************************************** #ifdef TEST_STRUTILS using namespace std; // Function prototypes void Usage( char * psAppName ); void PrintArray( wxArrayString & roas ); //************************************************************************************************** int main( int argc, char * argv[ ] ) { wxArrayString oas1; 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.at( 0 ) == wxT('-') ) { if( os1.at( 1 ) == wxT('h') ) { Usage( argv[0] ); exit( EXIT_SUCCESS ); } else { Usage( argv[0] ); exit( EXIT_FAILURE ); } } } // Display the utility banner cout << "\n StrUtils Test Utility" << "\n Version 1.02 (04/04/2014)\n"; // Exercise the function : iStrCmpCpnt( ) oas1.Empty( ); oas1.Add( wxT("3,1") ); oas1.Add( wxT("2,0") ); std::cout << "\nTest iStrCmpCpnt( ) :\n"; std::cout << " Before : "; PrintArray( oas1 ); oas1.Sort( &iStrCmpCpnt ); std::cout << " After : "; PrintArray( oas1 ); // */ // Exercise the function : iStrCmpNode( ) oas1.Empty( ); oas1.Add( wxT("Vcc") ); oas1.Add( wxT("1") ); oas1.Add( wxT("2") ); oas1.Add( wxT("2SK1058_Drive") ); oas1.Add( wxT("3") ); oas1.Add( wxT("V1") ); std::cout << "\nTest iStrCmpNode( ) :\n"; std::cout << " Before : "; PrintArray( oas1 ); oas1.Sort( &iStrCmpNode ); std::cout << " After : "; PrintArray( oas1 ); // */ // Exercise the function : iStrCmpSrc( ) oas1.Empty( ); oas1.Add( wxT("Iin") ); oas1.Add( wxT("Rin") ); oas1.Add( wxT("Vin") ); oas1.Add( wxT("V2") ); oas1.Add( wxT("I1") ); std::cout << "\nTest iStrCmpSrc( ) :\n"; std::cout << " Before : "; PrintArray( oas1 ); oas1.Sort( &iStrCmpNode ); std::cout << " After : "; PrintArray( oas1 ); // */ std::cout << '\n'; exit( EXIT_SUCCESS ); } //************************************************************************************************** void Usage( char * psAppName ) { cout << "\nUsage : " << psAppName << " [-OPTIONS]" << "\nOptions :" << "\n -h : Print usage (this message)\n"; } //************************************************************************************************** void PrintArray( wxArrayString & roas ) { size_t sz1; for( sz1=0; sz1 0 ) std::cout << " "; std::cout << roas.Item( sz1 ).mb_str( ); } std::cout << '\n'; } //************************************************************************************************** #endif // TEST_STRUTILS