← Back to team overview

kicad-developers team mailing list archive

Re: The problems with wxString

 

On 11/21/2013 02:16 PM, Dick Hollenbeck wrote:
> 
> 1) wx >= 2.9 has these constructors
> 
> 
> 	wxString( const char* )
>  	wxString( std::string )
> 
> whereas wx 2.8 does not.
> 
> Both offer:
> 
> wxString( const char*, wxConvUTF8 );
> 
> but this cannot be used in a default "type promotion" situation, this constructor must be
> invoked explicitly.
> 
> 
> 2) The above type promotion constructors treat the input encoding as that of the current
> locale, rather than UTF8 assuredly.
> 
> 
> The type promotion constructors are important if you want to allow the compiler to promote
> an 8 bit string to a wxString for you without special syntax.
> 
> 
> 3) If you decide to keep 8 bit strings in memory, encoded in the current locale, then
> someday when you load a chinese board file, you will not be able to hold those strings in
> a deficient 8 bit encoding.  (UTF8 is not a deficient 8 bit encoding, some others are.)
> The software breaks at that point.  This argues for using UTF8 always as the internal 8
> bit encoding.  But now the above two constructors are broken, since the current locale's
> encoding cannot be assumed to be UTF8, even though it often is on linux.  You just cannot
> assume it.
> 
> In summary, I don't see any easy immediate relief from the boat anchor we know as
> wxString, even with wx 3.0.  But I will continue to think about it.
> 
> Dick


Attached is a patch needing a good look, that shows off a new class UTF8 that I wrote that
solves the problems addressed above by providing conversion operators to and from
wxString, yet holding UTF8 data in what is basically a std::string.


Please say how it impacts you, realizing its usage scope can be trimmed or expanded from
this sampling.

I am especially interested in:

a) how it compiles on gcc >= 4.8
b) how it compiles using clang.
c) what it does to any benchmarks of sane-ness and speed for stroke_font.h

Lorenzo, Marco, Orson, your feedback in particular is wanted.

class UTF8 will likely allow the removal of many many more calls to TO_UTF8() and
FROM_UTF8(), not in this patch.

Plus code size will likely be reduced because I put the size expensive stuff out of line
in a lean call interface.

Dick


=== modified file 'common/footprint_info.cpp'
--- common/footprint_info.cpp	2013-12-20 09:15:00 +0000
+++ common/footprint_info.cpp	2014-01-01 05:14:33 +0000
@@ -273,8 +273,8 @@
                      wxString::Format( wxT( "'%s' is not a valid FPID." ),
                                        GetChars( aFootprintName ) ) );
 
-        wxString libNickname   = FROM_UTF8( fpid.GetLibNickname().c_str() );
-        wxString footprintName = FROM_UTF8( fpid.GetFootprintName().c_str() );
+        wxString libNickname   = fpid.GetLibNickname();
+        wxString footprintName = fpid.GetFootprintName();
 
         if( libNickname == fp.GetNickname() && footprintName == fp.GetFootprintName() )
             return &fp;

=== modified file 'common/fp_lib_table.cpp'
--- common/fp_lib_table.cpp	2013-12-29 15:12:27 +0000
+++ common/fp_lib_table.cpp	2014-01-01 06:38:41 +0000
@@ -173,7 +173,7 @@
         FPID& fpid = (FPID&) ret->GetFPID();
 
         // Catch any misbehaving plugin, which should be setting internal footprint name properly:
-        wxASSERT( aFootprintName == FROM_UTF8( fpid.GetFootprintName().c_str() ) );
+        wxASSERT( aFootprintName == (wxString) fpid.GetFootprintName() );
 
         // and clearing nickname
         wxASSERT( !fpid.GetLibNickname().size() );
@@ -195,7 +195,7 @@
         // Try loading the footprint to see if it already exists, caller wants overwrite
         // protection, which is atypical, not the default.
 
-        wxString fpname = FROM_UTF8( aFootprint->GetFPID().GetFootprintName().c_str() );
+        wxString fpname = aFootprint->GetFPID().GetFootprintName();
 
         std::auto_ptr<MODULE>   m( row->plugin->FootprintLoad( row->GetFullURI( true ), fpname, row->GetProperties() ) );
 
@@ -480,16 +480,17 @@
 }
 
 
-std::string FP_LIB_TABLE::FormatOptions( const PROPERTIES* aProperties )
+UTF8 FP_LIB_TABLE::FormatOptions( const PROPERTIES* aProperties )
 {
-    std::string ret;
+    UTF8 ret;
 
     if( aProperties )
     {
         for( PROPERTIES::const_iterator it = aProperties->begin();  it != aProperties->end();  ++it )
         {
             const std::string& name  = it->first;
-            const std::string& value = it->second;
+
+            const UTF8& value = it->second;
 
             if( ret.size() )
                 ret += OPT_SEP;
@@ -741,7 +742,7 @@
                 {
                     if( aReporter )
                     {
-                        msg.Printf( _( "Cannot find footprint library file \"%s\" in any of the "
+                        msg.Printf( _( "Cannot find footprint library file '%s' in any of the "
                                        "KiCad legacy library search paths.\n" ),
                                     GetChars( fn.GetFullPath() ) );
                         aReporter->Report( msg );
@@ -751,8 +752,7 @@
                     continue;
                 }
 
-                module = pi->FootprintLoad( libPath,
-                                            FROM_UTF8( component->GetFPID().GetFootprintName().c_str() ) );
+                module = pi->FootprintLoad( libPath, component->GetFPID().GetFootprintName() );
 
                 if( module )
                 {
@@ -766,10 +766,10 @@
         {
             if( aReporter )
             {
-                msg.Printf( _( "Component `%s` footprint <%s> was not found in any legacy "
+                msg.Printf( _( "Component `%s` footprint '%s' was not found in any legacy "
                                "library.\n" ),
                             GetChars( component->GetReference() ),
-                            GetChars( FROM_UTF8( component->GetFPID().Format().c_str() ) ) );
+                            GetChars( component->GetFPID().Format() ) );
                 aReporter->Report( msg );
             }
 
@@ -811,10 +811,10 @@
             {
                 if( aReporter )
                 {
-                    msg.Printf( _( "Component `%s` footprint <%s> legacy library path <%s > "
+                    msg.Printf( _( "Component `%s` footprint '%s' legacy library path <%s > "
                                    "was not found in the footprint library table.\n" ),
                                 GetChars( component->GetReference() ),
-                                GetChars( FROM_UTF8( component->GetFPID().Format().c_str() ) ) );
+                                GetChars( component->GetFPID().Format() ) );
                     aReporter->Report( msg );
                 }
 
@@ -830,9 +830,9 @@
                 {
                     if( aReporter )
                     {
-                        msg.Printf( _( "Component `%s` FPID <%s> is not valid.\n" ),
+                        msg.Printf( _( "Component `%s` FPID '%s' is not valid.\n" ),
                                     GetChars( component->GetReference() ),
-                                    GetChars( FROM_UTF8( newFPID.Format().c_str() ) ) );
+                                    GetChars( newFPID.Format() ) );
                         aReporter->Report( msg );
                     }
 
@@ -860,7 +860,7 @@
     else
         path = aPath.GetPath();
 
-    wxLogTrace( traceFpLibTable, wxT( "Setting env %s to <%s>." ),
+    wxLogTrace( traceFpLibTable, wxT( "Setting env %s to '%s'." ),
                 GetChars( ProjectPathEnvVariableName() ), GetChars( path ) );
     wxSetEnv( ProjectPathEnvVariableName(), path );
 }
@@ -899,7 +899,7 @@
         fn.SetName( defaultFileName );
     }
 
-    wxLogTrace( traceFpLibTable, wxT( "Project specific footprint library table file <%s>." ),
+    wxLogTrace( traceFpLibTable, wxT( "Project specific footprint library table file '%s'." ),
                 GetChars( fn.GetFullPath() ) );
 
     return fn.GetFullPath();
@@ -917,7 +917,7 @@
 
         if( !fn.DirExists() && !fn.Mkdir( 0x777, wxPATH_MKDIR_FULL ) )
         {
-            THROW_IO_ERROR( wxString::Format( _( "Cannot create global library table path <%s>." ),
+            THROW_IO_ERROR( wxString::Format( _( "Cannot create global library table path '%s'." ),
                                               GetChars( fn.GetPath() ) ) );
         }
 
@@ -954,7 +954,7 @@
 
     fn.SetName( GetFileName() );
 
-    wxLogTrace( traceFpLibTable, wxT( "Global footprint library table file <%s>." ),
+    wxLogTrace( traceFpLibTable, wxT( "Global footprint library table file '%s'." ),
                 GetChars( fn.GetFullPath() ) );
 
     return fn.GetFullPath();

=== modified file 'common/fpid.cpp'
--- common/fpid.cpp	2013-09-17 00:52:08 +0000
+++ common/fpid.cpp	2014-01-01 05:14:33 +0000
@@ -265,9 +265,9 @@
 }
 
 
-std::string FPID::Format() const
+UTF8 FPID::Format() const
 {
-    std::string  ret;
+    UTF8    ret;
 
     if( nickname.size() )
     {
@@ -287,9 +287,9 @@
 }
 
 
-std::string FPID::GetFootprintNameAndRev() const
+UTF8 FPID::GetFootprintNameAndRev() const
 {
-    std::string ret;
+    UTF8 ret;
 
     if( revision.size() )
     {
@@ -301,11 +301,11 @@
 }
 
 
-std::string FPID::Format( const std::string& aLogicalLib, const std::string& aFootprintName,
+UTF8 FPID::Format( const std::string& aLogicalLib, const std::string& aFootprintName,
                           const std::string& aRevision )
     throw( PARSE_ERROR )
 {
-    std::string  ret;
+    UTF8    ret;
     int     offset;
 
     if( aLogicalLib.size() )

=== modified file 'common/gal/stroke_font.cpp'
--- common/gal/stroke_font.cpp	2013-12-22 16:07:47 +0000
+++ common/gal/stroke_font.cpp	2014-01-01 06:14:20 +0000
@@ -147,7 +147,7 @@
 }
 
 
-void STROKE_FONT::Draw( const wxString& aText, const VECTOR2D& aPosition, double aRotationAngle )
+void STROKE_FONT::Draw( const UTF8& aText, const VECTOR2D& aPosition, double aRotationAngle )
 {
     // Context needs to be saved before any transformations
     m_gal->Save();
@@ -192,7 +192,7 @@
     {
         size_t length = newlinePos - begin;
 
-        drawSingleLineText( aText.Mid( begin, length ) );
+        drawSingleLineText( aText.substr( begin, length ) );
         m_gal->Translate( VECTOR2D( 0.0, lineHeight ) );
 
         begin = newlinePos + 1;
@@ -200,20 +200,20 @@
     }
 
     // Draw the last (or the only one) line
-    if( !aText.IsEmpty() )
-        drawSingleLineText( aText.Mid( begin ) );
+    if( !aText.empty() )
+        drawSingleLineText( aText.substr( begin ) );
 
     m_gal->Restore();
 }
 
 
-void STROKE_FONT::drawSingleLineText( const wxString& aText )
+void STROKE_FONT::drawSingleLineText( const UTF8& aText )
 {
     // By default the overbar is turned off
     m_overbar = false;
 
-    double xOffset;
-    VECTOR2D glyphSize( m_glyphSize );
+    double      xOffset;
+    VECTOR2D    glyphSize( m_glyphSize );
 
     // Compute the text size
     VECTOR2D textSize = computeTextSize( aText );
@@ -254,12 +254,12 @@
         xOffset = 0.0;
     }
 
-    for( wxString::const_iterator chIt = aText.begin(); chIt != aText.end(); ++chIt )
+    for( UTF8::uni_iter chIt = aText.ubegin(), end = aText.uend(); chIt < end; ++chIt )
     {
         // Toggle overbar
         if( *chIt == '~' )
         {
-            if( ++chIt == aText.end() )
+            if( ++chIt >= end )
                 break;
 
             if( *chIt != '~' )      // It was a single tilda, it toggles overbar
@@ -274,13 +274,14 @@
             dd = '?' - ' ';
 
         GLYPH& glyph = m_glyphs[dd];
-        BOX2D& bbox = m_glyphBoundingBoxes[dd];
+        BOX2D& bbox  = m_glyphBoundingBoxes[dd];
 
         if( m_overbar )
         {
             VECTOR2D startOverbar( xOffset, -getInterline() * OVERBAR_HEIGHT );
             VECTOR2D endOverbar( xOffset + glyphSize.x * bbox.GetEnd().x,
                                  -getInterline() * OVERBAR_HEIGHT );
+
             m_gal->DrawLine( startOverbar, endOverbar );
         }
 
@@ -317,25 +318,25 @@
 }
 
 
-VECTOR2D STROKE_FONT::computeTextSize( const wxString& aText ) const
+VECTOR2D STROKE_FONT::computeTextSize( const UTF8& aText ) const
 {
     VECTOR2D result = VECTOR2D( 0.0, m_glyphSize.y );
 
-    for( wxString::const_iterator chIt = aText.begin(); chIt != aText.end(); ++chIt )
+    for( UTF8::uni_iter it = aText.ubegin(), end = aText.uend(); it < end; ++it )
     {
-        wxASSERT_MSG( *chIt != '\n',
+        wxASSERT_MSG( *it != '\n',
                       wxT( "This function is intended to work with single line strings" ) );
 
         // If it is double tilda, then it is displayed as a single tilda
         // If it is single tilda, then it is toggling overbar, so we need to skip it
-        if( *chIt == '~' )
+        if( *it == '~' )
         {
-            if( ++chIt == aText.end() )
+            if( ++it >= end )
                 break;
         }
 
         // Index in the bounding boxes table
-        unsigned dd = *chIt - ' ';
+        unsigned dd = *it - ' ';
 
         if( dd >= m_glyphBoundingBoxes.size() || dd < 0 )
             dd = '?' - ' ';

=== modified file 'common/utf8.cpp'
--- common/utf8.cpp	2013-12-09 18:09:58 +0000
+++ common/utf8.cpp	2014-01-01 06:32:16 +0000
@@ -24,7 +24,7 @@
 
 #include <utf8.h>
 
-/* THROW_IO_ERROR needs this, but it will soon be including this file, so until some
+/* THROW_IO_ERROR needs this, but it includes this file, so until some
     factoring of THROW_IO_ERROR into a separate header, defer and use the asserts.
 #include <richio.h>
 */
@@ -33,7 +33,7 @@
 
 /*
     These are not inlined so that code space is saved by encapsulating the
-    creation of intermediate objects and referencing wxConvUTF8.
+    creation of intermediate objects and the referencing of wxConvUTF8.
 */
 
 

=== modified file 'include/fp_lib_table.h'
--- include/fp_lib_table.h	2013-12-20 09:15:00 +0000
+++ include/fp_lib_table.h	2014-01-01 05:41:53 +0000
@@ -339,7 +339,7 @@
      * @param aProperties is the PROPERTIES to format or NULL.  If NULL the returned
      *  string will be empty.
      */
-    static std::string FormatOptions( const PROPERTIES* aProperties );
+    static UTF8 FormatOptions( const PROPERTIES* aProperties );
 
     /**
      * Function Format

=== modified file 'include/fpid.h'
--- include/fpid.h	2013-09-17 00:52:08 +0000
+++ include/fpid.h	2014-01-01 05:14:33 +0000
@@ -27,7 +27,7 @@
 #define _FPID_H_
 
 #include <richio.h>
-
+#include <utf8.h>
 
 /**
  * Class FPID
@@ -53,7 +53,7 @@
  *
  * @author Dick Hollenbeck
  */
-class FPID  // aka GUID
+class FPID
 {
 public:
 
@@ -88,7 +88,7 @@
      * Function GetLibNickname
      * returns the logical library name  portion of a FPID.
      */
-    const std::string& GetLibNickname() const
+    const UTF8& GetLibNickname() const
     {
         return nickname;
     }
@@ -108,7 +108,7 @@
      * Function GetFootprintName
      * returns the footprint name, i.e. footprintName.
      */
-    const std::string& GetFootprintName() const { return footprint; }
+    const UTF8& GetFootprintName() const { return footprint; }
 
     /**
      * Function SetFootprintName
@@ -120,15 +120,15 @@
 
     int SetRevision( const std::string& aRevision );
 
-    const std::string& GetRevision() const { return revision; }
+    const UTF8& GetRevision() const { return revision; }
 
-    std::string GetFootprintNameAndRev() const;
+    UTF8 GetFootprintNameAndRev() const;
 
     /**
      * Function Format
      * returns the fully formatted text of the FPID.
      */
-    std::string Format() const;
+    UTF8 Format() const;
 
     /**
      * Function Format
@@ -137,7 +137,7 @@
      *
      * @throw PARSE_ERROR if any of the pieces are illegal.
      */
-    static std::string Format( const std::string& aLibNickname, const std::string& aFootprintName,
+    static UTF8 Format( const std::string& aLibNickname, const std::string& aFootprintName,
                                const std::string& aRevision )
         throw( PARSE_ERROR );
 
@@ -182,8 +182,8 @@
      */
     int compare( const FPID& aFPID ) const;
 
-    bool operator <( const FPID& aFPID ) const { return this->compare( aFPID ) < 0; }
-    bool operator >( const FPID& aFPID ) const { return this->compare( aFPID ) > 0; }
+    bool operator < ( const FPID& aFPID ) const { return this->compare( aFPID ) < 0; }
+    bool operator > ( const FPID& aFPID ) const { return this->compare( aFPID ) > 0; }
     bool operator ==( const FPID& aFPID ) const { return this->compare( aFPID ) == 0; }
     bool operator !=( const FPID& aFPID ) const { return !(*this == aFPID); }
 
@@ -192,9 +192,9 @@
 #endif
 
 protected:
-    std::string    nickname;       ///< The nickname of the footprint library or empty.
-    std::string    footprint;      ///< The name of the footprint in the logical library.
-    std::string    revision;       ///< The footprint revision.
+    UTF8    nickname;       ///< The nickname of the footprint library or empty.
+    UTF8    footprint;      ///< The name of the footprint in the logical library.
+    UTF8    revision;       ///< The footprint revision.
 };
 
 

=== modified file 'include/gal/stroke_font.h'
--- include/gal/stroke_font.h	2013-12-20 09:15:00 +0000
+++ include/gal/stroke_font.h	2014-01-01 06:11:28 +0000
@@ -29,8 +29,8 @@
 #ifndef STROKE_FONT_H_
 #define STROKE_FONT_H_
 
-#include <string>
 #include <deque>
+#include <utf8.h>
 
 #include <eda_text.h>
 
@@ -70,7 +70,7 @@
      * @param aPosition is the text position in world coordinates.
      * @param aRotationAngle is the text rotation angle.
      */
-    void Draw( const wxString& aText, const VECTOR2D& aPosition, double aRotationAngle );
+    void Draw( const UTF8& aText, const VECTOR2D& aPosition, double aRotationAngle );
 
     /**
      * @brief Set the glyph size.
@@ -173,7 +173,7 @@
      *
      * @param aText is the text to be drawn.
      */
-    void drawSingleLineText( const wxString& aText );
+    void drawSingleLineText( const UTF8& aText );
 
     /**
      * @brief Compute the size of a given text.
@@ -181,20 +181,19 @@
      * @param aText is the text string.
      * @return is the text size.
      */
-    VECTOR2D computeTextSize( const wxString& aText ) const;
+    VECTOR2D computeTextSize( const UTF8& aText ) const;
 
     /**
      * @brief Returns number of lines for a given text.
      *
      * @param aText is the text to be checked.
-     * @return Number of lines of aText.
+     * @return unsigned - The number of lines in aText.
      */
-    unsigned int linesCount( const wxString& aText ) const
+    unsigned linesCount( const UTF8& aText ) const
     {
-        wxString::const_iterator it, itEnd;
-        unsigned int lines = 1;
+        unsigned lines = 1;
 
-        for( it = aText.begin(), itEnd = aText.end(); it != itEnd; ++it )
+        for( UTF8::const_iterator it = aText.begin(), itEnd = aText.end(); it != itEnd; ++it )
         {
             if( *it == '\n' )
                 ++lines;
@@ -214,4 +213,4 @@
 };
 } // namespace KIGFX
 
-#endif /* STROKE_FONT_H_ */
+#endif // STROKE_FONT_H_

=== modified file 'include/richio.h'
--- include/richio.h	2013-12-20 09:15:00 +0000
+++ include/richio.h	2014-01-01 05:21:54 +0000
@@ -29,8 +29,8 @@
 // "richio" after its author, Richard Hollenbeck, aka Dick Hollenbeck.
 
 
-#include <string>
 #include <vector>
+#include <utf8.h>
 
 // I really did not want to be dependent on wxWidgets in richio
 // but the errorText needs to be wide char so wxString rules.

=== modified file 'include/utf8.h'
--- include/utf8.h	2013-12-24 19:09:41 +0000
+++ include/utf8.h	2014-01-01 06:01:01 +0000
@@ -83,6 +83,23 @@
         return *this;
     }
 
+    UTF8& operator=( const char* s )
+    {
+        std::string::operator=( s );
+        return *this;
+    }
+
+    UTF8& operator=( char c )
+    {
+        std::string::operator=( c );
+        return *this;
+    }
+
+    UTF8 substr( size_t pos = 0, size_t len = npos ) const
+    {
+        return std::string::substr( pos, len );
+    }
+
     operator wxString () const;
 
     /// This one is not in std::string, and one wonders why... might be a solid

=== modified file 'pcbnew/class_board.cpp'
--- pcbnew/class_board.cpp	2013-12-20 09:15:00 +0000
+++ pcbnew/class_board.cpp	2014-01-01 05:14:33 +0000
@@ -2447,7 +2447,7 @@
             msg.Printf( _( "Checking netlist component footprint \"%s:%s:%s\".\n" ),
                         GetChars( component->GetReference() ),
                         GetChars( component->GetTimeStamp() ),
-                        GetChars( FROM_UTF8( component->GetFPID().Format().c_str() ) ) );
+                        GetChars( component->GetFPID().Format() ) );
             aReporter->Report( msg );
         }
 
@@ -2465,7 +2465,7 @@
                     msg.Printf( _( "Adding new component \"%s:%s\" footprint \"%s\".\n" ),
                                 GetChars( component->GetReference() ),
                                 GetChars( component->GetTimeStamp() ),
-                                GetChars( FROM_UTF8( component->GetFPID().Format().c_str() ) ) );
+                                GetChars( component->GetFPID().Format() ) );
 
                     if( aReporter->ReportWarnings() )
                         aReporter->Report( msg );
@@ -2476,7 +2476,7 @@
                                    "footprint \"%s\".\n" ),
                                 GetChars( component->GetReference() ),
                                 GetChars( component->GetTimeStamp() ),
-                                GetChars( FROM_UTF8( component->GetFPID().Format().c_str() ) ) );
+                                GetChars( component->GetFPID().Format() ) );
 
                     if( aReporter->ReportErrors() )
                         aReporter->Report( msg );
@@ -2509,8 +2509,8 @@
                                            "\"%s\".\n" ),
                                         GetChars( footprint->GetReference() ),
                                         GetChars( footprint->GetPath() ),
-                                        GetChars( FROM_UTF8( footprint->GetFPID().Format().c_str() ) ),
-                                        GetChars( FROM_UTF8( component->GetFPID().Format().c_str() ) ) );
+                                        GetChars( footprint->GetFPID().Format() ),
+                                        GetChars( component->GetFPID().Format() ) );
 
                             if( aReporter->ReportWarnings() )
                                 aReporter->Report( msg );
@@ -2521,7 +2521,7 @@
                                            "footprint \"%s\".\n" ),
                                         GetChars( footprint->GetReference() ),
                                         GetChars( footprint->GetPath() ),
-                                        GetChars( FROM_UTF8( component->GetFPID().Format().c_str() ) ) );
+                                        GetChars( component->GetFPID().Format() ) );
 
                             if( aReporter->ReportErrors() )
                                 aReporter->Report( msg );
@@ -2755,7 +2755,7 @@
                 msg.Printf( _( "** Error: Component \"%s\" pad '%s' not found in footprint \"%s\" **\n" ),
                             GetChars( component->GetReference() ),
                             GetChars( padname ),
-                            footprint->GetFPID().Format().c_str() );
+                            GetChars( footprint->GetFPID().Format() ) );
                 aReporter->Report( msg );
             }
         }

=== modified file 'pcbnew/dialogs/dialog_edit_module_for_Modedit.cpp'
--- pcbnew/dialogs/dialog_edit_module_for_Modedit.cpp	2013-12-20 09:15:00 +0000
+++ pcbnew/dialogs/dialog_edit_module_for_Modedit.cpp	2014-01-01 05:14:33 +0000
@@ -117,7 +117,7 @@
     m_ReferenceCtrl->SetValue( m_referenceCopy->GetText() );
     m_ValueCtrl->SetValue( m_valueCopy->GetText() );
     m_ValueCtrl->SetValue( m_valueCopy->GetText() );
-    m_FootprintNameCtrl->SetValue( FROM_UTF8( m_currentModule->GetFPID().Format().c_str() ) );
+    m_FootprintNameCtrl->SetValue( m_currentModule->GetFPID().Format() );
 
     m_AttributsCtrl->SetItemToolTip( 0, _( "Use this attribute for most non SMD components" ) );
     m_AttributsCtrl->SetItemToolTip( 1,

=== modified file 'pcbnew/dialogs/dialog_fp_plugin_options.cpp'
--- pcbnew/dialogs/dialog_fp_plugin_options.cpp	2013-12-27 11:44:40 +0000
+++ pcbnew/dialogs/dialog_fp_plugin_options.cpp	2014-01-01 05:40:43 +0000
@@ -84,7 +84,7 @@
             for( PROPERTIES::const_iterator it = props->begin();  it != props->end();  ++it, ++row )
             {
                 m_grid->SetCellValue( row, 0, FROM_UTF8( it->first.c_str() ) );
-                m_grid->SetCellValue( row, 1, FROM_UTF8( it->second.c_str() ) );
+                m_grid->SetCellValue( row, 1, it->second );
             }
 
             delete props;
@@ -184,7 +184,7 @@
         for( int row = 0;  row<rowCount;  ++row )
         {
             string  name  = TO_UTF8( m_grid->GetCellValue( row, 0 ).Trim( false ).Trim() );
-            string  value = TO_UTF8( m_grid->GetCellValue( row, 1 ).Trim( false ).Trim() );
+            UTF8    value = m_grid->GetCellValue( row, 1 ).Trim( false ).Trim();
 
             if( name.size() )
             {
@@ -192,9 +192,7 @@
             }
         }
 
-        string  options = FP_LIB_TABLE::FormatOptions( &props );
-
-        return FROM_UTF8( options.c_str() );
+        return FP_LIB_TABLE::FormatOptions( &props );
     }
 
     void saveColSizes()
@@ -261,11 +259,11 @@
         if( event.IsSelection() )
         {
             string  option = TO_UTF8( event.GetString() );
-            string  help_text;
+            UTF8    help_text;
 
             if( m_choices.Value( option.c_str(), &help_text ) )
             {
-                wxString page = FROM_UTF8( help_text.c_str() );
+                wxString page = help_text;
 
                 m_html->SetPage( page );
             }

=== modified file 'pcbnew/eagle_plugin.cpp'
--- pcbnew/eagle_plugin.cpp	2013-12-24 19:09:41 +0000
+++ pcbnew/eagle_plugin.cpp	2014-01-01 05:26:38 +0000
@@ -2711,8 +2711,8 @@
 {
     if( m_props )
     {
-        string page_width;
-        string page_height;
+        UTF8 page_width;
+        UTF8 page_height;
 
         if( m_props->Value( "page_width",  &page_width ) &&
             m_props->Value( "page_height", &page_height ) )
@@ -2873,10 +2873,10 @@
     PLUGIN::FootprintLibOptions( aListToAppendTo );
 
     /*
-    (*aListToAppendTo)["ignore_duplicates"] = wxString( _(
+    (*aListToAppendTo)["ignore_duplicates"] = UTF8( _(
         "Ignore duplicately named footprints within the same Eagle library. "
         "Only the first similarly named footprint will be loaded."
-        )).utf8_str();
+        ));
     */
 }
 

=== modified file 'pcbnew/gen_modules_placefile.cpp'
--- pcbnew/gen_modules_placefile.cpp	2013-12-20 09:15:00 +0000
+++ pcbnew/gen_modules_placefile.cpp	2014-01-01 05:14:33 +0000
@@ -479,9 +479,11 @@
     for( int ii = 0; ii < moduleCount; ii++ )
     {
         wxPoint  module_pos;
+
         const wxString& ref = list[ii].m_Reference;
         const wxString& val = list[ii].m_Value;
-        const wxString& pkg = FROM_UTF8( list[ii].m_Module->GetFPID().Format().c_str() );
+        const wxString& pkg = list[ii].m_Module->GetFPID().Format();
+
         sprintf( line, "%-8.8s %-16.16s %-16.16s",
                  TO_UTF8( ref ), TO_UTF8( val ), TO_UTF8( pkg ) );
 

=== modified file 'pcbnew/github/github_plugin.cpp'
--- pcbnew/github/github_plugin.cpp	2013-12-20 09:15:00 +0000
+++ pcbnew/github/github_plugin.cpp	2014-01-01 05:50:23 +0000
@@ -166,7 +166,7 @@
         }
     }
 
-    string fp_name = TO_UTF8( aFootprintName );
+    UTF8 fp_name = aFootprintName;
 
     MODULE_CITER it = m_gh_cache->find( fp_name );
 
@@ -321,20 +321,20 @@
     // inherit options supported by all PLUGINs.
     PLUGIN::FootprintLibOptions( aListToAppendTo );
 
-    (*aListToAppendTo)[ PRETTY_DIR ] = wxString( _(
+    (*aListToAppendTo)[ PRETTY_DIR ] = UTF8( _(
         "Set this property to a directory where footprints are to be written as pretty "
         "footprints when saving to this library. Anything saved will take precedence over "
         "footprints by the same name in the github repo.  These saved footprints can then "
         "be sent to the library maintainer as updates. "
         "<p>The directory <b>must</b> have a <b>.pretty</b> file extension because the "
         "format of the save is pretty.</p>"
-        )).utf8_str();
+        ));
 
     /*
-    (*aListToAppendTo)["cache_github_zip_in_this_dir"] = wxString( _(
+    (*aListToAppendTo)["cache_github_zip_in_this_dir"] = UTF8( _(
         "Set this property to a directory where the github *.zip file will be cached. "
         "This should speed up subsequent visits to this library."
-        )).utf8_str();
+        ));
     */
 }
 
@@ -356,11 +356,11 @@
 
         if( aProperties )
         {
-            string  pretty_dir;
+            UTF8  pretty_dir;
 
             if( aProperties->Value( PRETTY_DIR, &pretty_dir ) )
             {
-                wxString    wx_pretty_dir = FROM_UTF8( pretty_dir.c_str() );
+                wxString    wx_pretty_dir = pretty_dir;
 
                 wx_pretty_dir = FP_LIB_TABLE::ExpandSubstitutions( wx_pretty_dir );
 
@@ -409,7 +409,7 @@
 
             if( fn.GetExt() == kicad_mod )
             {
-                string fp_name = TO_UTF8( fn.GetName() );   // omit extension & path
+                UTF8 fp_name = fn.GetName();    // omit extension & path
 
                 m_gh_cache->insert( fp_name, entry );
             }

=== modified file 'pcbnew/io_mgr.cpp'
--- pcbnew/io_mgr.cpp	2013-11-11 08:01:04 +0000
+++ pcbnew/io_mgr.cpp	2014-01-01 05:24:52 +0000
@@ -44,7 +44,7 @@
 
 
 // is there a better place for this function?
-bool PROPERTIES::Value( const char* aName, std::string* aFetchedValue ) const
+bool PROPERTIES::Value( const char* aName, UTF8* aFetchedValue ) const
 {
     PROPERTIES::const_iterator it = find( aName );
 

=== modified file 'pcbnew/io_mgr.h'
--- pcbnew/io_mgr.h	2013-12-20 09:15:00 +0000
+++ pcbnew/io_mgr.h	2014-01-01 05:17:08 +0000
@@ -38,7 +38,7 @@
  * is a name/value tuple with unique names and optional values.  The names
  * may be iterated alphabetically.
  */
-class PROPERTIES : public std::map< std::string, std::string >
+class PROPERTIES : public std::map< std::string, UTF8 >
 {
     // alphabetical tuple of name and value hereby defined.
 
@@ -53,7 +53,7 @@
      *  exists and aFetchedValue is not NULL.
      * @return bool - true if property is found, else false.
      */
-    bool Value( const char* aName, std::string* aFetchedValue = NULL ) const;
+    bool Value( const char* aName, UTF8* aFetchedValue = NULL ) const;
 };
 
 

=== modified file 'pcbnew/kicad_plugin.cpp'
--- pcbnew/kicad_plugin.cpp	2013-12-20 09:15:00 +0000
+++ pcbnew/kicad_plugin.cpp	2014-01-01 05:14:33 +0000
@@ -1782,8 +1782,7 @@
     MODULE_MAP& mods = m_cache->GetModules();
 
     // Quietly overwrite module and delete module file from path for any by same name.
-    wxFileName fn( aLibraryPath, FROM_UTF8( aFootprint->GetFPID().GetFootprintName().c_str() ),
-                   KiCadFootprintFileExtension );
+    wxFileName fn( aLibraryPath, aFootprint->GetFPID().GetFootprintName(), KiCadFootprintFileExtension );
 
     if( !fn.IsOk() )
     {

=== modified file 'pcbnew/legacy_plugin.cpp'
--- pcbnew/legacy_plugin.cpp	2013-12-20 09:15:00 +0000
+++ pcbnew/legacy_plugin.cpp	2014-01-01 05:14:33 +0000
@@ -1144,8 +1144,9 @@
         }
     }
 
-    wxString msg = wxString::Format( wxT( "Missing '$EndMODULE' for MODULE '%s'" ),
-                                     aModule->GetFPID().GetFootprintName().c_str() );
+    wxString msg = wxString::Format(
+        wxT( "Missing '$EndMODULE' for MODULE '%s'" ),
+        GetChars( aModule->GetFPID().GetFootprintName() ) );
 
     THROW_IO_ERROR( msg );
 }
@@ -1200,7 +1201,7 @@
                                 padchar,
                                 padchar,
                                 m_reader->LineNumber(),
-                                aModule->GetFPID().GetFootprintName().c_str()
+                                GetChars( aModule->GetFPID().GetFootprintName() )
                     );
                 THROW_IO_ERROR( m_error );
             }
@@ -1401,7 +1402,7 @@
                         (unsigned char) line[1],
                         (unsigned char) line[1],
                         m_reader->LineNumber(),
-                        aModule->GetFPID().GetFootprintName().c_str()
+                        GetChars( aModule->GetFPID().GetFootprintName() )
                         );
         THROW_IO_ERROR( m_error );
     }

=== modified file 'pcbnew/librairi.cpp'
--- pcbnew/librairi.cpp	2013-12-20 09:15:00 +0000
+++ pcbnew/librairi.cpp	2014-01-01 05:14:33 +0000
@@ -285,7 +285,7 @@
     if( aModule == NULL )
         return;
 
-    fn.SetName( FROM_UTF8( aModule->GetFPID().GetFootprintName().c_str() ) );
+    fn.SetName( aModule->GetFPID().GetFootprintName() );
 
     wxString    wildcard = wxGetTranslation( KiCadFootprintLibFileWildcard );
 
@@ -485,7 +485,7 @@
         return false;
 
     FPID        fpid( fpid_txt );
-    wxString    fpname = FROM_UTF8( fpid.GetFootprintName().c_str() );
+    wxString    fpname = fpid.GetFootprintName();
 
     // Confirmation
     wxString msg = wxString::Format( FMT_OK_DELETE, fpname.GetData(), nickname.GetData() );
@@ -581,7 +581,7 @@
     SetMsgPanel( aModule );
 
     // Ask what to use as the footprint name in the library
-    wxString footprintName = FROM_UTF8( aModule->GetFPID().GetFootprintName().c_str() );
+    wxString footprintName = aModule->GetFPID().GetFootprintName();
 
     if( aDisplayDialog )
     {

=== modified file 'pcbnew/loadcmp.cpp'
--- pcbnew/loadcmp.cpp	2013-12-20 09:15:00 +0000
+++ pcbnew/loadcmp.cpp	2014-01-01 05:14:33 +0000
@@ -451,8 +451,8 @@
     wxCHECK_MSG( m_footprintLibTable != NULL, NULL,
                  wxT( "Cannot look up FPID in NULL FP_LIB_TABLE." ) );
 
-    wxString   nickname = FROM_UTF8( aFootprintId.GetLibNickname().c_str() );
-    wxString   fpname   = FROM_UTF8( aFootprintId.GetFootprintName().c_str() );
+    wxString   nickname = aFootprintId.GetLibNickname();
+    wxString   fpname   = aFootprintId.GetFootprintName();
 
     if( nickname.size() )
     {

=== modified file 'pcbnew/plugin.cpp'
--- pcbnew/plugin.cpp	2013-12-20 09:15:00 +0000
+++ pcbnew/plugin.cpp	2014-01-01 05:20:25 +0000
@@ -114,34 +114,34 @@
 {
     // disable all these in another couple of months, after everyone has seen them:
 #if 1
-    (*aListToAppendTo)["debug_level"] = wxString( _(
+    (*aListToAppendTo)["debug_level"] = UTF8( _(
         "Enable <b>debug</b> logging for Footprint*() functions in this PLUGIN."
-        )).utf8_str();
+        ));
 
-    (*aListToAppendTo)["read_filter_regex"] = wxString( _(
+    (*aListToAppendTo)["read_filter_regex"] = UTF8( _(
         "Regular expression <b>footprint name</b> filter."
-        )).utf8_str();
+        ));
 
-    (*aListToAppendTo)["enable_transaction_logging"] = wxString( _(
+    (*aListToAppendTo)["enable_transaction_logging"] = UTF8( _(
         "Enable transaction logging.  The mere presence of this option turns on the "
         " logging, no need to set a Value."
-        )).utf8_str();
+        ));
 
-    (*aListToAppendTo)["username"] = wxString( _(
+    (*aListToAppendTo)["username"] = UTF8( _(
         "User name for <b>login</b> to some special library server."
-        )).utf8_str();
+        ));
 
-    (*aListToAppendTo)["password"] = wxString( _(
+    (*aListToAppendTo)["password"] = UTF8( _(
         "Password for <b>login</b> to some special library server."
-        )).utf8_str();
+        ));
 #endif
 
 #if 1
     // Suitable for a C++ to python PLUGIN::Footprint*() adapter, move it to the adapter
     // if and when implemented.
-    (*aListToAppendTo)["python_footprint_plugin"] = wxString( _(
+    (*aListToAppendTo)["python_footprint_plugin"] = UTF8( _(
         "Enter the python module which implements the PLUGIN::Footprint*() functions."
-        )).utf8_str();
+        ));
 #endif
 }
 

=== modified file 'pcbnew/xchgmod.cpp'
--- pcbnew/xchgmod.cpp	2013-12-20 09:15:00 +0000
+++ pcbnew/xchgmod.cpp	2014-01-01 05:14:33 +0000
@@ -394,8 +394,8 @@
                  aNewFootprintFPID.Format().c_str() );
     m_WinMessages->AppendText( line );
 
-    wxString moduleName = FROM_UTF8( aNewFootprintFPID.GetFootprintName().c_str() );
-    wxString libName = FROM_UTF8( aNewFootprintFPID.GetLibNickname().c_str() );
+    wxString moduleName = aNewFootprintFPID.GetFootprintName();
+    wxString libName    = aNewFootprintFPID.GetLibNickname();
 
     newModule = m_parent->LoadFootprint( aNewFootprintFPID );
 


Follow ups

References