桜、抹茶、白、日記

名古屋市在住のC++使いのcoderの日記だったもの。

続・マルチバイト文字列

d:id:youandi:20070112#p2, d:id:youandi:20060315#p3
前回の内容を書いている時点で気が付いていたが、strncpy()で全角文字の途中でぶった切れ足りする場合に、アプリ内でその文字列をファイルに落としてそれを読み込むと文字列が空になってしまう模様。どうも制御文字っぽくなってしまうようで非常にマズイというかレポートが挙がってきてしまった。
とりあえずVisualC++で言うところの_mbsncpy()的なものを考える。
最初はワイド文字に変換してASCII判定みたいな事を考えたが無駄が多いし、Linux上でiswascii()っぽいのが見つからなかった。結局最近存在を知ったmblen()を使った方法で実装。

wxChar* MbsNCpy( wxChar* pszDst, const wxChar* pszSrc, size_t nDstLen )
{
#if wxUSE_UNICODE
    return ::wxStrncpy( pszDst, pszSrc, nDstLen );
#else
    if ( pszDst == NULL )
    {
        return pszDst;
    }
    if ( pszSrc == NULL )
    {
        (void)::memset( pszDst, 0, sizeof( wxChar ) * nDstLen );
        return pszDst;
    }
    int nCharPos = 0;
    pszDst[ 0 ] = 0;
    const int nSrcLen = ::wxStrlen( pszSrc );
    while ( nCharPos < nSrcLen )
    {
        const int nCharSize = ::mblen( &pszSrc[ nCharPos ], MB_CUR_MAX );
        if ( nCharSize == -1 )
        {
            return ::wxStrncpy( pszDst, pszSrc, nDstLen );
        }
        else if ( nCharSize == 0 )
        {
            break;
        }
        else if ( nDstLen < static_cast<size_t>( nCharPos + nCharSize ) )
        {
            break;
        }

        (void)::memcpy( &pszDst[ nCharPos ],
                        &pszSrc[ nCharPos ],
                        sizeof( wxChar ) * nCharSize );

        nCharPos += nCharSize;
    }

    if ( static_cast<size_t>( nCharPos ) < nDstLen )
    {
        (void)::memset( &pszDst[ nCharPos ],
                        0,
                        sizeof( wxChar ) * ( nDstLen - nCharPos ) );
    }

    return pszDst;
#endif
}

上記関数にバグがありました。上記コードは修正済み。

上記関数にバグがありました。上記コードは修正済み。