歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Unix知識 >> 關於Unix >> FreeBSD下寬字節與多字節互相轉換的函數支持

FreeBSD下寬字節與多字節互相轉換的函數支持

日期:2017/2/28 11:19:34   编辑:關於Unix


在FreeBSD下,對多字節語言編碼的處理是通過“多字節字符(mb)與寬字節字符(wc)的互相轉換”來提供支持的。作為系統內部,Freebsd在libc函數級別上對“寬字節wc“提供了很好的支持,所有寬字節處理函數均定義在“/usr/src/include/wchar.h“中。
FreeBSD中對多字節語言編碼進行支持的基本原理是:
1、提供了統一的處理機制,就是寬字節處理,這樣就避免出現“半個字”的問題,所有的字符都是作為一個單獨的對象(寬字節字符)來處理。在freebsd系統中,寬字節字符定義為4個字節,可以容納Unicode的所有字符。在libc中,Freebsd提供了以下函數,來支持wc<=>mb
mb -> wc
字符處理: mbtowc mbrtowc
字符串處理: mbstowcs mbsrtowcs mbsnrtowcs

wc -> mb
字符處理:wctomb wcrtomb
字符串處理:wcstombs wcsrtombs wcsnrtombs

通過這些函數,可以實現系統底層對多字節語言編碼的處理,大致的流程是:
多字節字符首先要轉換成寬字節字符,然後由系統提供的寬字節字符、字符串處理函數進行處理,諸如排序、比較、輸出。根據需要再把處理的結果通過wc -> mb的函數進行轉換,轉換成特定的多字符編碼格式。
2、對特定多字符編碼格式的綁定:
對於漢字處理來說,存在多種編碼格式,諸如UTF-8、GB2312、GBK、GB18030等等,由於編碼方式的不同,在進行wc<->mb轉換的時候,就需要不同的轉換規則對其進行支持。這種綁定從原理上說是通過locale的LC_CTYPE來實現的。
具體的實現,是在/usr/src/lib/libc/locale目錄下,原理是當應用程序調用setlocale函數來設定locale時,系統會對LC_CTYPE進行檢查,並根據LC_CTYPE的值,對wc<->mb處理函數進行切換。例如:
閱讀mbrtowc函數(mbrtowc.c)
size_t
mbrtowc(wchar_t * __restrict pwc, const char * __restrict s,
size_t n, mbstate_t * __restrict ps)
{
static mbstate_t mbs;
if (ps == NULL)
ps = &mbs;
return (__mbrtowc(pwc, s, n, ps));
}

它最終調用的是__mbrtowc(),__mbrtowc是一個函數指針,在setrunelocale.c中,這個指針會根據系統當前的LC_CTYPE進行初始化,如果當前的LC_CTYPE=zh_CN.GB18030,系統會轉向執行GB18030.c中的_GB18030_init()函數,在這個函數裡面,這個函數指針會指向GB18030.c中的_GB18030_mbrtowc()函數:
int
_GB18030_init(_RuneLocale *rl)
{
__mbrtowc = _GB18030_mbrtowc;
__wcrtomb = _GB18030_wcrtomb;
__mbsinit = _GB18030_mbsinit;
_CurrentRuneLocale = rl;
__mb_cur_max = 4;
return (0);
}

而_GB18030_mbrtowc()函數具體實現了GB18030編碼的字符到寬字節字符的轉換:
static size_t
_GB18030_mbrtowc(wchar_t * __restrict pwc, const char * __restrict s,
size_t n, mbstate_t * __restrict ps)
{
_GB18030State *gs;
wchar_t wch;
int ch, len, ocount;
size_t ncopy;
gs = (_GB18030State *)ps;
if (gs->count < 0 || gs->count > sizeof(gs->bytes)) {
errno = EINVAL;
return ((size_t)-1);
}
if (s == NULL) {
s = "";
n = 1;
pwc = NULL;
}
ncopy = MIN(MIN(n, MB_CUR_MAX), sizeof(gs->bytes) - gs->count);
memcpy(gs->bytes + gs->count, s, ncopy);
ocount = gs->count;
gs->count += ncopy;
s = (char *)gs->bytes;
n = gs->count;
if (n == 0)
/* Incomplete multibyte sequence */
return ((size_t)-2);
/*
* Single byte: [00-7f]
* Two byte: [81-fe][40-7e,80-fe]
* Four byte: [81-fe][30-39][81-fe][30-39]
*/
ch = (unsigned char)*s++;
if (ch <= 0x7f) {
len = 1;
wch = ch;
} else if (ch >= 0x81 && ch <= 0xfe) {
wch = ch;
if (n < 2)
return ((size_t)-2);
ch = (unsigned char)*s++;
if ((ch >= 0x40 && ch <= 0x7e) || (ch >= 0x80 && ch <= 0xfe)) {
wch = (wch << 8) | ch;
len = 2;
} else if (ch >= 0x30 && ch <= 0x39) {
/*
* Strip high bit off the wide character we will
* eventually output so that it is positive when
* cast to wint_t on 32-bit twos-complement machines.
*/
wch = ((wch & 0x7f) << 8) | ch;
if (n < 3)
return ((size_t)-2);
ch = (unsigned char)*s++;
if (ch < 0x81 || ch > 0xfe)
goto ilseq;
wch = (wch << 8) | ch;
if (n < 4)
return ((size_t)-2);
ch = (unsigned char)*s++;
if (ch < 0x30 || ch > 0x39)
goto ilseq;
wch = (wch << 8) | ch;
len = 4;
} else
goto ilseq;
} else
goto ilseq;
if (pwc != NULL)
*pwc = wch;
gs->count = 0;
return (wch == L'\0' ? 0 : len - ocount);
ilseq:
errno = EILSEQ;
return ((size_t)-1);
}

Freebsd這種利用Locale的綁定機制,可以非常靈活的對多種多字節編碼字符處理提供支持,我們可以把如下這幾個函數指針當成一個接口,如果要實現對某種多字節編碼的支持,只要實現這幾個函數的實現即可。這種機制很好的體現了Unix系統對I18n的支持,下面是UTF_8的綁定:
__mbrtowc = _UTF8_mbrtowc;
__wcrtomb = _UTF8_wcrtomb;
__mbsinit = _UTF8_mbsinit;
__mbsnrtowcs = _UTF8_mbsnrtowcs;
__wcsnrtombs = _UTF8_wcsnrtombs;

具體的代碼都是在/usr/src/lib/lib/locale目錄下
GB18030.c euc.c utf-8.c gb2312.c等等,分別對幾種漢字的編碼方案提供支持。
由此可見,Freebsd通過locale機制對漢字處理的支持,還是很充分的,也可以看出,直接影響Freebsd對中文字符處理的locale是LC_CTYPE。
Copyright © Linux教程網 All Rights Reserved