FreeBSDのwcwidth

wcwidth()は /usr/include/wchar.h に定義されている。定義部分は

#if __XSI_VISIBLE
int     wcswidth(const wchar_t *, size_t);
int     wcwidth(wchar_t);
#define wcwidth(_c)     __wcwidth(_c)
#endif

gcc -E で展開した結果を見る限り、__XSI_VISIBLEは有効になっている。

さらにそこから、/usr/include/_ctype.hを呼び出している。実体は__wcwidth()。_ctype.hの中に定義されている__wcwidth()は以下の通り。

static __inline int
__wcwidth(__ct_rune_t _c)
{
        unsigned int _x;

        if (_c == 0)
                return (0);
        _x = (unsigned int)__maskrune(_c, _CTYPE_SWM|_CTYPE_R);
        if ((_x & _CTYPE_SWM) != 0)
                return ((_x & _CTYPE_SWM) >> _CTYPE_SWS);
        return ((_x & _CTYPE_R) != 0 ? 1 : -1);
}

さらに、__maskrune()は、やはり!_ctype.h中に定義がある。

static __inline int
__maskrune(__ct_rune_t _c, unsigned long _f)
{
        return ((_c < 0 || _c >= _CACHED_RUNES) ? ___runetype(_c) :
                _CurrentRuneLocale->__runetype[_c]) & _f;
}

___runetype()が実際に判別する関数。これは、/usr/src/sys/lib/libc/locale/runetype.c に実体がある。

unsigned long
___runetype(__ct_rune_t c)
{
        size_t lim;
        _RuneRange *rr = &_CurrentRuneLocale->__runetype_ext;
        _RuneEntry *base, *re;

        if (c < 0 || c == EOF)
                return(0L);

        /* Binary search -- see bsearch.c for explanation. */
        base = rr->__ranges;
        for (lim = rr->__nranges; lim != 0; lim >>= 1) {
                re = base + (lim >> 1);
                if (re->__min <= c && c <= re->__max) {
                        if (re->__types)
                            return(re->__types[c - re->__min]);
                        else
                            return(re->__map);
                } else if (c > re->__max) {
                        base = re + 1;
                        lim--;
                }
        }

        return(0L);
}

ここで、!_CurrentRuneLocaleやRuneEntry,RuneRangeは、/usr/include/runetype.hに定義がある。_CurrentRuneLocaleは、/usr/src/lib/libcの下を検索してみると、たとえばlibc/locale/utf_8.c の!_utf8_init()で、LC_CTYPEファイルから読み込まれている。LC_CTYPEは、mklocaleコマンドで作成される。そのソースは/usr/src/share/mklocale/UTF-8.srcである。これが、wcwidth()関数で、文字幅を定義してある実体。その構造は、先のrunetype.hに定義がある。またman mklocaleにも記述がある。