6    ロケールの作成

この章では,ロケールの作成方法について説明します。 ロケールは,母国語,文化的データ,オペレーティング・システム上のコードセットの特定の組み合わせをサポートするデータのセットです。 localedef コマンドを使用して,以下のファイルからロケールを作成できます。

デスクトップ・アプリケーションで新しいロケールを使用するために変更しなければならないファイルの一覧は,第 5 章を参照してください。

6.1    ロケールに対応した文字マップ・ソース・ファイルの作成

charmap ファイルは,文字のバイナリ・コードにシンボルを定義します。 localedef コマンドは charmap ファイルを使用して,ロケール・ソース・ファイル内の文字シンボルを文字コードにマップします。 例 6-1 は,この章で作成する fr_FR.ISO8859-1@example ロケール用のソース・ファイル,ISO8859-1.cmap の一部です。 D.1 節 には,このファイルの内容がすべて示されています。

例 6-1:  サンプル・ロケール用の charmap ファイル

#      [1]
#     Charmap for ISO 8859-1 codeset     [1]
#      [1]
 
<code_set_name>                 "ISO8859-1"     [2]
<mb_cur_max>                    1      [2]
<mb_cur_min>                    1      [2]
<escape_char>                   \      [2]
<comment_char>                  #      [2]
 
CHARMAP      [3]
 
#  Portable characters and other standard     [1]
#  control characters                         [1]
 
<NUL>                           \x00      [4]
<SOH>                           \x01
<STX>                           \x02
<ETX>                           \x03
<EOT>                           \x04
<ENQ>                           \x05
<ACK>                           \x06
<BEL>                           \x07
<alert>                         \x07
<backspace>                     \x08
<tab>                           \x09
<newline>                       \x0a
<vertical-tab>                  \x0b
<form-feed>                     \x0c
<carriage-return>               \x0d
<SO>                            \x0e

.
.
.
<zero> \x30 [4] <one> \x31 <two> \x32 <three> \x33 <A> \x41 <B> \x42 <C> \x43 <D> \x44
.
.
.
<underscore> \x5f [4] <low-line> \x5f <grave-accent> \x60 <a> \x61 <b> \x62 <c> \x63 <d> \x64
.
.
.
# Extended control characters [1] # (names taken from ISO 6429) [1]   <PAD> \x80 [4] <HOP> \x81 <BPH> \x82 <NBH> \x83 <IND> \x84
.
.
.
# Other graphic characters [1]   <nobreakspace> \xa0 [4] <inverted-exclamation-mark> \xa1
.
.
.
END CHARMAP [5]    

  1. コメント行

    省略時のコメント文字は番号記号 (#) です。 省略時の指定は,<comment_char> 定義 (例 6-1 を参照) を使用して変更できます。 [例に戻る]

  2. キーワード宣言

    この例では,有効な宣言をすべて示し,<code_set_name> を除くすべてのエントリに省略時の値を指定します。 一般に,省略時の値を変更したい場合にのみ,宣言を指定します。 この例では,<comment_char><escape_char> 宣言により,コメント文字とエスケープ文字の省略時の値を指定しています。 <mb_cur_max> の値,つまりバイト単位での文字の最大の長さは,この charmap ファイルでは 1 です。 <mb_cur_min> の値,つまりバイト単位での文字の最小の長さは,すべてのロケールの charmap ファイルで 1 でなければなりません (すべてのロケールには,シングルバイト文字を定義するポータブル文字セットの文字が含まれています)。

    <code_set_name> の値は,実行時にロケールにバインドされるアプリケーションから呼び出される nl_langinfo(CODESET) によって返される値になります。 [例に戻る]

  3. 文字マップの開始を示すヘッダ [例に戻る]

  4. 文字のシンボルからコードへのマップ

    個々の文字マップは,シンボリック名とコード値から構成されます。 名前とコード値は,1 つ以上のスペースで区切られます。

    シンボリック名は,左山カッコ (<) で始まり,右山カッコ (>) で終わります。 山カッコで囲まれる文字には,制御文字とスペース文字を除く,ポータブル文字セット中の任意の文字を使用できます。 名前に複数の右山カッコ (>) が含まれている場合,最後の山カッコを除くすべての山カッコの前に <escape_character> の値を付けなければなりません。 シンボリック名の長さは,128 バイトを超えることはできません。

    コード値は,1 つまたは複数の 10 進数,8 進数,あるいは 16 進数の定数です (複数の定数はマルチバイトのコード値に対応します)。 定数のフォーマットは次のとおりです。

    同じ文字 (コード値) に対して (各々,異なるシンボリック名で) 複数の文字マップ・エントリを定義できます。 この例では,同じコード値に対して複数のシンボリック名は定義していません。 [例に戻る]

  5. 文字マップの終わりを示すトレイラ [例に戻る]

マルチバイト文字を含むコードセット用のソース・ファイルは,より複雑な文字マップを含みます。 例 6-2 は,日本語の SJIS コードセット用のソース・ファイルに含まれる文字マップ・エントリの一部です。 このソース・ファイルには,同じコードセット中でサポートしなければならない複数の文字セットのエントリが指定されています。

例 6-2:  マルチバイト・コードセット用の charmap ファイルの一部

# SJIS charmap
#
<code_set_name> "SJIS"   [1]
<mb_cur_min>    1    [2]
<mb_cur_max>    2    [3]
CHARMAP
#
# CS0: ASCII
#

.
.
.
<commercial-at> \x40 [4] <A> \x41 [4] <B> \x42 [4]
.
.
.
# # CS1: JIS X0208-1983 for ShiftJIS. # <zenkaku-space> \x81\x40 [5] <j0101>...<j0163> \x81\x40 [5] <j0164>...<j0194> \x81\x80 [5]
.
.
.
# # UDC Area in JIS X0208 plane # <u8501>...<u8563> \xeb\x40 [6] <u8564>...<u8594> \xeb\x80 [6] <u8601>...<u8663> \xeb\x9f [6]
.
.
.
# # CS2: JIS X0201 (so-called Hankaku-Kana) # <kana-fullstop> \xa1 [7]
.
.
.
<kana-conjunctive> \xa5 [7] <kana-WO> \xa6 [7] <kana-a> \xa7 [7]
.
.
.
END CHARMAP

  1. コードセット名 [例に戻る]

  2. 1 文字の最小バイト数

    この値は 1 でなければなりません。 [例に戻る]

  3. 1 文字の最大バイト数

    SJIS では,マルチバイト文字の最大長は 2 バイトです。 [例に戻る]

  4. ASCII 文字のシンボルとコード値 [例に戻る]

  5. SJIS 文字のシンボルとコード値

    文字シンボルを範囲として指定している点と,2 つの 16 進数値で 2 バイト文字のコード値を指定している点に注意してください。

    シンボルがシンボル値の範囲として指定された場合,指定された文字コード値は,その範囲内の最初のシンボルに適用されます。 localedef コマンドは,シンボル値とコード値の両方を自動的にインクリメントして,その範囲内のすべての文字のシンボル値とコード値を作成します。 [例に戻る]

  6. SJIS コードセット中の UDC 用のマップ

    これらのマップは,ユーザが後で文字を定義できるようにするための,コード値の範囲を設定します。 [例に戻る]

  7. 半角カナ文字セット用のシングルバイト文字のマップ [例に戻る]

文字マップ・ソース・ファイルに適用される規則の完全なリストについては, charmap(4) のリファレンス・ページを参照してください。

注意

文字マップ・ソース・ファイル内の文字のシンボリック名に関しては,標準化作業が進行中です。 X/Open UNIX 標準の将来のリビジョンでは,文字に関して長いシンボリック名と短いシンボリック名の両方が規定される予定です。

この例の文字のシンボリック名は,必ずしも各種の標準化団体が提唱している名前と一致しているわけではではありません。

6.2    ロケール定義ソース・ファイルの作成

ロケール定義ソース・ファイルは,特定の言語と地域に固有のデータを定義します。 ソース・ファイルはセクションに分けられており,定義するロケール・データのカテゴリごとに 1 つのセクションがあります。 次のロケール・カテゴリがあります。

例 6-3 に,ロケール定義ソース・ファイルの構成を擬似コードで示します。

例 6-3:  ロケール・ソース定義ファイルの構成

# comment-line    [1]
 
comment_char      <char_symbol1>   [2]
escape_char       <char_symbol2>   [3]
 
CATEGORY_NAME    [4]
 
category_definition-statement   [5]
category_definition-statement   [5]

.
.
.
END CATEGORY_NAME [6]
.
.
.
[7]

  1. コメント行

    番号記号 (#) は,省略時のコメント文字です。 行の最初のカラムにコメント文字を置くことにより,その行全体をコメントとして指定できます。 ロケール・ソース・ファイル内では,定義文と同じ行にコメントを置くことはできません。 ロケール・ソース・ファイルは,この点で文字マップ・ソース・ファイルと異なります。 [例に戻る]

  2. コメント文字の再定義

    省略時のコメント文字は,comment_char キーワードで始まり,その後に使用したいコメント文字のシンボルが続くエントリ行で置き換えることができます。 文字シンボルは,ロケールの文字マップ (charmap) ソース・ファイルで定義されています。 [例に戻る]

  3. エスケープ文字の再定義

    省略時のエスケープ文字は,バックスラッシュ (\) です。 この文字は,10 進,16 進,および 8 進の定数で使用され,定義文がソース・ファイルの次の行に続くことを示します。 省略時のエスケープ文字は,escape_char キーワードで始まり,その後に 1 つまたは複数の空白文字,さらにその後に使用したいエスケープ文字のシンボルが続くエントリ行で置き換えることができます。 文字シンボルは,そのロケールの文字マップソース・ファイルで定義されています。 [例に戻る]

  4. ロケール・カテゴリ・セクションのヘッダ

    セクション・ヘッダは,LC_CTYPELC_COLLATELC_NUMERICLC_MONETARYLC_MESSAGES,および LC_TIME の各カテゴリ名に対応しています。 [例に戻る]

  5. カテゴリの定義文

    これらの文のフォーマットは,カテゴリによって異なります。 一般に,定義文はキーワードで始まり,その後に 1 つまたは複数のスペースあるいはタブが続き,最後に定義そのものが続きます。

    カテゴリ定義文の代りに copy 文を記述して,他のロケール・ソース・ファイル内の定義文を取り込むことができます。 たとえば,次のように記述します。

    copy en_US.ISO8859-1
    

    copy 文を記述するときには,カテゴリ内には他の文を記述しないでください。 [例に戻る]

  6. ロケール・カテゴリ・セクションのトレイラ

    セクション・トレイラは END キーワードで始まり,その後にカテゴリ名が続きます。 [例に戻る]

  7. すべてのロケール・カテゴリのセクションを含めることも,一部のカテゴリのセクションだけを含めることもできます。 ソース・ファイルでロケール・カテゴリのセクションを省略した場合,省略したカテゴリの定義は,省略時のロケール (POSIX または C ロケール) と同じになります。 [例に戻る]

以下の項では,特定のロケール・カテゴリに着目し,fr_FR.ISO8859-1@example.src ロケール・ソース・ファイルの個々の部分について説明します。 D.2 節 に,このソース・ファイル全体を示しています。

6.2.1    LC_CTYPE ロケール・カテゴリの定義

ロケール・ソース・ファイルのLC_CTYPE セクションは,文字クラスと,大文字と小文字の変換などの操作に使用される文字属性を定義します。 例 6-4 に,LC_CTYPE セクションの定義を示します。

例 6-4:  LC_CTYPE カテゴリの定義

#############
LC_CTYPE     [1]
#############
 
upper   <A>;<B>;<C>;<D>;<E>;<F>;<G>;<H>;<I>;<J>;<K>;<L>;<M>;\
        <N>;<O>;<P>;<Q>;<R>;<S>;<T>;<U>;<V>;<W>;<X>;<Y>;<Z>;\
        <A-grave>;\

.
.
.
<U-diaeresis> [2]   lower <a>;<b>;<c>;<d>;<e>;<f>;<g>;<h>;<i>;<j>;<k>;<l>;<m>;\ <n>;<o>;<p>;<q>;<r>;<s>;<t>;<u>;<v>;<w>;<x>;<y>;<z>;\ <a-grave>;\
.
.
.
<u-diaeresis> [2]   space <tab>;<newline>;<vertical-tab>;<form-feed>;\ <carriage-return>;<space> [2]   cntrl <NUL>;<SOH>;<STX>;<ETX>;<EOT>;<ENQ>;<ACK>;\ <alert>;<backspace>;<tab>;<newline>;<vertical-tab>;\ <form-feed>;<carriage-return>;\
.
.
.
<SOS>;<SGCI>;<SCI>;<CSI>;<ST>;<OSC>;<PM>;<APC> [2]   graph <exclamation-mark>;<quotation-mark>;<number-sign>;\
.
.
.
<u-circumflex>;<u-diaeresis>;<y-acute>;<thorn-icelandic>;<y-diaeresis> [2]   # print class includes everything in the graph class above, plus <space>.   print <exclamation-mark>;<quotation-mark>;<number-sign>;\
.
.
.
<u-circumflex>;<u-diaeresis>;<y-acute>;<thorn-icelandic>;<y-diaeresis>;\ <space> [2]   punct <exclamation-mark>;<quotation-mark>;<number-sign>;\ <dollar-sign>;<percent-sign>;<ampersand>;<apostrophe>;\ <left-parenthesis>;<right-parenthesis>;<asterisk>;\ <plus-sign>;<comma>;<hyphen>;<period>;<slash>;\ <colon>;<semicolon>;<less-than-sign>;<equals-sign>;\ <greater-than-sign>;<question-mark>;<commercial-at>;\ <left-square-bracket>;<backslash>;<right-square-bracket>;\ <circumflex>;<underscore>;<grave-accent>;<left-brace>;\ <vertical-line>;<right-brace>;<tilde> [2]   digit <zero>;<one>;<two>;<three>;<four>;\ <five>;<six>;<seven>;<eight>;<nine> [2]   xdigit <zero>;<one>;<two>;<three>;<four>;\ <five>;<six>;<seven>;<eight>;<nine>;\ <A>;<B>;<C>;<D>;<E>;<F>;\ <a>;<b>;<c>;<d>;<e>;<f> [2]   blank <space>;<tab> [2]   toupper (<a>,<A>);(<b>,<B>);(<c>,<C>);(<d>,<D>);(<e>,<E>);\ (<f>,<F>);(<g>,<G>);(<h>,<H>);(<i>,<I>);(<j>,<J>);\ (<k>,<K>);(<l>,<L>);(<m>,<M>);(<n>,<N>);(<o>,<O>);\ (<p>,<P>);(<q>,<Q>);(<r>,<R>);(<s>,<S>);(<t>,<T>);\ (<u>,<U>);(<v>,<V>);(<w>,<W>);(<x>,<X>);(<y>,<Y>);\ (<z>,<Z>);\ (<a-grave>,<A-grave>);\ (<a-circumflex>,<A-circumflex>);\ (<ae-ligature>,<AE-ligature>);\ (<c-cedilla>,<C-cedilla>);\ (<e-grave>,<E-grave>);\ (<e-acute>,<E-acute>);\ (<e-circumflex>,<E-circumflex>);\ (<e-diaeresis>,<E-diaeresis>);\ (<i-circumflex>,<I-circumflex>);\ (<i-diaeresis>,<I-diaeresis>);\ (<o-circumflex>,<O-circumflex>);\ (<u-grave>,<U-grave>);\ (<u-circumflex>,<U-circumflex>);\ (<u-diaeresis>,<U-diaeresis>) [3]   # tolower class is the inverse of toupper.   tolower (<A>,<a>);(<B>,<b>);(<C>,<c>);(<D>,<d>);(<E>,<e>);\ (<F>,<f>);(<G>,<g>);(<H>,<h>);(<I>,<i>);(<J>,<j>);\ (<K>,<k>);(<L>,<l>);(<M>,<m>);(<N>,<n>);(<O>,<o>);\ (<P>,<p>);(<Q>,<q>);(<R>,<r>);(<S>,<s>);(<T>,<t>);\ (<U>,<u>);(<V>,<v>);(<W>,<w>);(<X>,<x>);(<Y>,<y>);\ (<Z>,<z>);\ (<A-grave>,<a-grave>);\ (<A-circumflex>,<a-circumflex>);\ (<AE-ligature>,<ae-ligature>);\ (<C-cedilla>,<c-cedilla>);\ (<E-grave>,<e-grave>);\ (<E-acute>,<e-acute>);\ (<E-circumflex>,<e-circumflex>);\ (<E-diaeresis>,<e-diaeresis>);\ (<I-circumflex>,<i-circumflex>);\ (<I-diaeresis>,<i-diaeresis>);\ (<O-circumflex>,<o-circumflex>);\ (<U-grave>,<u-grave>);\ (<U-circumflex>,<u-circumflex>);\ (<U-diaeresis>,<u-diaeresis>) [3]   END LC_CTYPE [4]

  1. セクション・ヘッダ [例に戻る]

  2. 文字クラスの定義

    これらの定義は,文字クラスを表すキーワード (プロパティとも呼ぶ) で始まり,その後に 1 つまたは複数のブランク文字と,そのクラスに含まれるすべての文字シンボルのリストが続きます。 文字シンボルではなくコード値を指定することもできますが,その場合には,ロケール・ソース・ファイルの可読性が損われ,複数のコードセットで使用できなくなります。

    例には示していませんが,水平方向の省略記号 (...) を使用して文字の範囲を表すことができます。 たとえば文字列 <NUL>;...;<tab> では,省略記号 (...) は,コード値がシンボル <NUL> からシンボル <tab> までの範囲にあるすべての文字を表します。 シンボルとそのコード値は,そのロケールの charmap ファイルで定義されています。

    X/Open UNIX 標準で定義された文字クラスは,次のキーワードで表します。

    アプリケーションの観点からは,alnum というクラスも存在します。 このクラスは,alpha クラスと digit クラスの文字を合わせたものと定義されているため,ロケールで定義されることは稀です。

    Unicode (*.UTF-8) ロケールは,Unicode 標準で定義されている文字クラスを含みます。 Unicode の文字分類についての詳細は, locale(4) を参照してください。

    日本語などのアジア系言語のロケールでは,標準以外の文字クラスも定義されています。 [例に戻る]

  3. 英字の大文字/小文字変換の定義

    大文字/小文字変換の定義は,キーワード touppertolower で始まり,シンボルを個別に指定するのではなく対として指定します。 この例の toupper の定義では,対の最初のシンボルが英字の小文字を,2 番目のシンボルが英字の大文字を表します。 この定義は,関数 towupper()towlower() がテキスト・データの大文字/小文字変換を実行するときの,変換対象の英字を定義します。

    標準以外の文字クラスを定義するロケールでは,wctrans()towctrans() 関数が使用する,その他のプロパティ変換も定義される場合があります。

    [例に戻る]

  4. セクション・トレイラ [例に戻る]

上記の例は,LC_CTYPE カテゴリを定義するときに使用できるすべてのオプションを示しているわけではありません。 その他のオプションを使用して,次の作業を行うこともできます。

アプリケーションでは wctype()iswctype() 関数を使用して,すべての文字クラス (ユーザ定義の文字クラスも含む) を判別し,テストできます。 また,標準文字クラスのテストには,クラス固有の関数 iswalpha()iswpunct() などを使用できます。

注意

fr_FR.ISO8859-1@example ロケールの LC_CTYPE カテゴリは,フランス語の文字に限定されています。 一部のロケール開発者は,ISO 8859-1 文字セットでサポートされているすべての言語の文字を含めた文字クラスを定義しようとします。 これによって,copy 文を使うことで,複数の西ヨーロッパ言語で同じ LC_CTYPE ソース定義を使用することができます。

LC_CTYPE カテゴリの定義に適用されるその他の規則と制約については, locale(4) のリファレンス・ページを参照してください。

6.2.2    LC_COLLATE ロケール・カテゴリの定義

ロケール・ソース・ファイルの LC_COLLATE セクションには,文字と文字列の照合方法を指定します。 例 6-5 は,LC_COLLATE セクションの一部です。

例 6-5:  LC_COLLATE カテゴリの定義

LC_COLLATE       [1]
order_start             forward;backward;forward   [2]
<NUL>     [3]
<SOH>
<STX>
<ETX>
<EOT>
<ENQ>
<ACK>
<alert>
<backspace>
<tab>

.
.
.
<APC> [3] <space> <space>;<space>;<space> <exclamation-mark> <exclamation-mark>;<exclamation-mark>;<exclamation-mark> <quotation-mark> <quotation-mark>;<quotation-mark>;<quotation-mark>
.
.
.
<a> <a>;<a>;<a> [3] <A> <a>;<a>;<A> <feminine> <a>;<feminine>;<feminine> <a-acute> <a>;<a-acute>;<a-acute> <A-acute> <a>;<a-acute>;<A-acute> <a-grave> <a>;<a-grave>;<a-grave> <A-grave> <a>;<a-grave>;<A-grave> <a-circumflex> <a>;<a-circumflex>;<a-circumflex> <A-circumflex> <a>;<a-circumflex>;<A-circumflex> <a-ring> <a>;<a-ring>;<a-ring> <A-ring> <a>;<a-ring>;<A-ring> <a-diaeresis> <a>;<a-diaeresis>;<a-diaeresis> <A-diaeresis> <a>;<a-diaeresis>;<A-diaeresis> <a-tilde> <a>;<a-tilde>;<a-tilde> <A-tilde> <a>;<a-tilde>;<A-tilde> <ae-ligature> <a>;<a><e>;<a><e> <AE-ligature> <a>;<a><e>;<A><E> <b> <b>;<b>;<b> <B> <b>;<b>;<B> <c> <c>;<c>;<c> <C> <c>;<c>;<C> <c-cedilla> <c>;<c-cedilla>;<c-cedilla> <C-cedilla> <c>;<c-cedilla>;<C-cedilla>
.
.
.
<z> <z>;<z>;<z> [3] <Z> <z>;<z>;<Z> UNDEFINED [4] order_end [5]   END LC_COLLATE [6]

  1. セクション・ヘッダ [例に戻る]

  2. 要素に照合重みを割り当てる文が記述されているセクションの開始を示す order_start キーワード

    order_start キーワードの行には,各ソート・パスに適用される,セミコロン (;) で区切られたソート・ディレクティブが続きます。 ソート・ディレクティブには次のキーワードを指定できます。

    ソート・ディレクティブの数は,それ以降の文で各照合要素に割り当てられる重みの数に対応します。

    各ソート・ディレクティブと関連する重みのセットは,文字列比較の 1 回のパスあるいはレベルの情報を指定します。 1 番目のディレクティブは,文字列比較操作で 1 次重みが適用されるときに使用され,2 番目のディレクティブは操作で 2 次重みが適用されるときに使用されます (3 番目以降のディレクティブについても同様)。 文字列を正しく照合するのに必要なレベル数は,言語と文化習慣に依存するため,ロケールごとに異なります。 また,レベル数には,limits.hsys/localedef.h ファイルの COLL_WEIGHTS_MAX の設定によって決まる最大値があります。 Tru64 UNIX システムでは,最大照合レベル (ソート・ディレクティブ) は 6 に制限されています。

    backward ディレクティブは多くの言語で使用されるディレクティブであり,比較対象の文字列が等価な場合に,アクセントの付いた文字をアクセントの付かない文字の後に置くために使用します。

    position ディレクティブは,西ヨーロッパ言語のハイフン (-) のように,単語内での位置によって意味が変わる文字を扱うために頻繁に使用されます。 このディレクティブの使用例としては,"o-ring" という単語を単語リストの中で "or-ing" の前に並べたいが,ハイフンを考慮するのは,すべての文字列を英字だけでソートした後にしたい場合が挙げられます。 このような順序にソートするためには,2 つのソート・ディレクティブと,それに関連する重み指定子のセットが必要です。 最初の比較操作では,ソート・ディレクティブとして forward を指定し,すべての英字について英字を最初の重みとして使用して,ハイフン文字の重みとしては IGNORE を指定します。 2 回目,あるいはそれ以降の比較操作では,ソート・ディレクティブとして forward position を指定し,すべての英字について IGNORE を重みとして使用して,ハイフン文字の重みとしてハイフンを指定します。

    ソート・ディレクティブを指定しない場合,省略時のディレクティブには forward が使用されます。 [例に戻る]

  3. 要素のための照合順序文

    これらの文は,文字シンボルの後に,1 つまたは複数のブランク文字 (スペースまたはタブ) を指定し,さらにその後にソートの各段階で同じ重みを持つ文字のシンボルを指定します。

    この例では,ソート順序は,制御文字,区切り文字と数字,英字の順です。 英字は複数のパスでソートされ,最初のパスでは判別記号と大文字/小文字の区別は無視され,2 番目のパスで判別記号が有効になり,3 番目のパスで大文字/小文字の区別が有効になります。 [例に戻る]

  4. 未定義文字のための照合順序文

    UNDEFINED キーワードは,ロケールの charmap ファイルでは定義されているが,他の照合順序文では指定されていないすべての文字に適用される照合順序文を開始します。 UNDEFINED カテゴリに対応する文字は,正規表現では,同じ等価クラスに属するものと見なされます。

    UNDEFINED 照合順序文は必ず指定しておきます。 指定しない場合には,localedef コマンドは未定義文字を照合順序の最後に含め,警告を出します。

    また,UNDEFINED 文を最後の照合順序文として指定すると,localedef コマンドは,すべての未定義文字を 1 つのエントリに圧縮できる場合があります。 これにより,ロケールのサイズを小さくできます。

    このロケールは,ロケールの charmap ファイルに指定された任意の (ただし,他の照合順序文で扱わない) 文字の照合順序を最後に位置づけるように指定します。

    UNDEFINED 文は,オペランドを持つことができます。 たとえば,IGNORE キーワードを指定すると,他の照合順序文に指定されていない文字は,IGNORE が指定されているソート・パスで無視されます。 この例に次のような UNDEFINED 文があったとすると,この文で指定されているソート・パスでは,他の照合順序文に指定されていない文字は無視されます。

    UNDEFINED    IGNORE;IGNORE;IGNORE
     
    

    [例に戻る]

  5. 照合順序文の終わりを示すトレイラ [例に戻る]

  6. LC_COLLATE セクションの終わりを示すトレイラ [例に戻る]

例 6-5 は,LC_COLLATE カテゴリを定義するときに使用できるすべてのオプションを示しているわけではありません。 他のオプションを使用すると,次のような使い方も可能です。

Unicode ロケールと dense コード・ロケールは等価なため,Unicode ロケールと dense コード・ロケールの両方で同じ charmap とロケール・ソースを使用することができます。 ただし,charmap に定義されていて,LC_COLLATE セクションに定義されていない Unicode 文字と dense コード文字は,異なる方法でソートされることがあります。

LC_COLLATE カテゴリの定義についての詳細は, locale(4) のリファレンス・ページを参照してください。

6.2.3    LC_MESSAGES ロケール・カテゴリの定義

ロケール・ソース・ファイルの LC_MESSAGES セクションには,ユーザからの肯定応答と否定応答に使用する文字列を定義します。 例 6-6 は,LC_MESSAGES セクションです。

例 6-6:  LC_MESSAGES カテゴリの定義

LC_MESSAGES    [1]
 
# yes expression. The following designates:
# "^([oO]|[oO][uU][iI])"
 
yesexpr       "<circumflex><left-parenthesis>\
<left-square-bracket><o><O><right-square-bracket>\
<vertical-line><left-square-bracket><o><O>\
<right-square-bracket><left-square-bracket><u><U>\
<right-square-bracket><left-square-bracket><i><I>\
<right-square-bracket><right-parenthesis>"    [2]
 
# no expression. The following designates:
# "^([nN]|[nN][oO][nN])"
 
noexpr        "<circumflex><left-parenthesis>\
<left-square-bracket><n><N><right-square-bracket>\
<vertical-line><left-square-bracket><n><N>\
<right-square-bracket><left-square-bracket><o><O>\
<right-square-bracket><left-square-bracket><n><N>\
<right-square-bracket><right-parenthesis>"    [3]
 
# yes string. The following designates: "oui:o:O"
 
yesstr        "<o><u><i><colon><o><colon><O>"    [4]
 
# no string. The following designates: "non:n:N"
 
nostr         "<n><o><n><colon><n><colon><N>"    [5]
END LC_MESSAGES    [6]

  1. セクション・ヘッダ [例に戻る]

  2. 肯定応答として有効な表現の定義

    このエントリは,yesexpr キーワードと,その後に続く 1 つまたは複数のスペースあるいはタブ,さらにその後に続く二重引用符で区切られた拡張正規表現で構成します。

    この表現は,このロケールでは "oui" や "o" (大文字/小文字は無視される) が有効な肯定応答であることを指定しています。 yesexpr の正規表現は,ロケールの charmap ファイルで定義されているシンボルを用いて,個々の文字を指定しています。 [例に戻る]

  3. 否定応答として有効な表現の定義

    このエントリは,noexpr キーワードと,その後に続く 1 つまたは複数のスペースあるいはタブ,さらにその後に続く二重引用符で区切られた拡張正規表現で構成します。

    この表現は,このロケールでは "non" や "n" (大文字/小文字は無視される) が有効な否定応答であることを指定しています。 [例に戻る]

  4. 肯定応答として有効な文字列の定義

    このエントリは,yesstr キーワードと,その後に続く 1 つまたは複数のスペースあるいはタブ,さらにその後に続く二重引用符で区切られた文字列で構成します。

    X/Open の UNIX 標準では,yesstr エントリは廃止される予定ですが,一部のアプリケーションやシステム・ソフトウェアではまだ,yesexpr ではなく yesstr が使用されている可能性があります。 ロケールで yesstr を定義しておくことにより,そのようなソフトウェアでもロケールが使用できるようにしておくことが好ましい手法です。 X/Open UNIX 標準では yesstr に対して固定文字列を 1 つだけ定義しています。 複数の固定文字列を区切る区切り文字のコロン (:) は,標準仕様に対する拡張です。 [例に戻る]

  5. 否定応答として有効な文字列の定義

    このエントリは,nostr キーワードと,その後に続く 1 つまたは複数のスペースあるいはタブ,さらにその後に続く二重引用符で区切られた文字列で構成します。

    X/Open の UNIX 標準では,nostr エントリは廃止される予定ですが,一部のアプリケーションやシステム・ソフトウェアではまだ,noexpr ではなく nostr が使用されている可能性があります。 ロケールで nostr を定義しておくことにより,そのようなソフトウェアでもロケールが使用できるようにしておくことが好ましい手法です。 X/Open UNIX 標準では nostr に対して固定文字列を 1 つだけ定義しています。 複数の固定文字列を区切る区切り文字のコロン (:) は,標準仕様に対する拡張です。 [例に戻る]

  6. セクション・トレイラ [例に戻る]

シンボル定義を指定する代わりに,セクション・ヘッダとトレイラ間で copy 文を使用して,既存のロケールの LC_MESSAGES カテゴリの定義をコピーできます。 copy 文はカテゴリの完全な定義であり,明示的なシンボル定義とともに使用することはできません。

6.2.4    LC_MONETARY ロケール・カテゴリの定義

ロケール・ソース・ファイルの LC_MONETARY セクションには,金額値の書式に使用する規則とシンボルを定義します。 アプリケーション開発者は localeconv()nl_langinfo() 関数を使用して,このセクションで定義されている情報を取得し,strfmon() 関数により書式規則を適用します。 例 6-7 は,LC_MONETARY セクションです。

例 6-7:  LC_MONETARY カテゴリの定義

LC_MONETARY   [1]
 
int_curr_symbol   "<F><R><F><space>"   [2]
currency_symbol   "<F>"    [2]
mon_decimal_point "<comma>"    [2]
mon_thousands_sep ""    [2]
mon_grouping      3;0    [2]
positive_sign     ""    [2]
negative_sign     "<hyphen>"    [2]

.
.
.
END LC_MONETARY [3]

  1. セクション・ヘッダ [例に戻る]

  2. シンボル定義

    上記の例のエントリは,次の指定を行います。

    [例に戻る]

  3. セクション・トレイラ [例に戻る]

LC_MONETARY セクションで定義可能なシンボル名を,以下に示します。

シンボル定義を指定する代わりに,セクション・ヘッダとトレイラの間で copy 文を使用して,既存のロケールの LC_MONETARY 定義をコピーできます。 copy 文はカテゴリの完全な定義であり,明示的なシンボル定義とともに使用することはできません。

LC_MONETARY の定義には,ユーロを完全にサポートしている UTF-8 および ISO8859-15 ロケールの言語のユーロ文字が設定されています。 ユーロ文字は Latin-1 に入っていないため,ISO8859-1 ロケールの言語は,ユーロを採用していても,ユーロより前の通貨記号を使用します。 たとえば,イタリア語のロケール it_IT.ISO8859-15 は,ユーロをサポートします。 イタリア語のロケール it_IT.ISO8859-1 は,リラをサポートします。

LC_MONETARY シンボル定義についての詳細は, locale(4) のリファレンス・ページを参照してください。

6.2.5    LC_NUMERIC ロケール・カテゴリの定義

ロケール・ソース・ファイルの LC_NUMERIC セクションには,数値データを書式付けるための規則とシンボルを定義します。 localeconv()nl_langinfo() 関数を使用することにより,この書式情報にアクセスできます。 例 6-8 は,LC_NUMERIC セクションです。

例 6-8:  LC_NUMERIC カテゴリの定義

LC_NUMERIC    [1]
decimal_point     "<comma>"    [2]
thousands_sep     ""    [3]
grouping          3;0    [4]
 
END LC_NUMERIC    [5]

  1. カテゴリ・ヘッダ [例に戻る]

  2. 小数点文字の定義 [例に戻る]

  3. 小数点の左側の桁を区切るために使用する文字の定義。 このロケールでは,省略時の文字は定義されていません。 したがって,アプリケーションでは必要に応じてこの文字を指定する必要があります。 [例に戻る]

  4. 小数点の左側の桁の各グループの大きさ。 thousands_sep で定義される文字があるときには,grouping で定義されるグループの間に挿入されます。

    セミコロン (;) で区切って桁数を複数指定することで,グループの大きさを変化させることができます。 たとえば,3;2 と指定すると,小数点の左側の最初のグループは 3 桁になり,それに続くグループはすべて 2 桁になります。 Tru64 UNIX システムでは,3;03 は同じであり,小数点の左側のすべての桁は,3 桁ごとにグループ化されます。 [例に戻る]

  5. カテゴリ・トレイラ [例に戻る]

例 6-8 は,LC_NUMERIC セクションで定義可能なすべてのシンボルを示します。 シンボル定義を使用する代わりに,セクション・ヘッダとトレイラ間に copy 文を指定して,他のロケールからこのセクションをインクルードできます。

LC_NUMERIC シンボル定義の詳細については, locale(4) のリファレンス・ページを参照してください。

6.2.6    LC_TIME ロケール・カテゴリの定義

ロケール・ソース・ファイルの LC_TIME セクションには,date コマンドで使用されるフィールド記述子の解釈を定義します。 このカテゴリ・セクションは,strftime()wcsftime()strptime(),および nl_langinfo() 関数の動作に影響します。 例 6-9 に,サンプルのフランス語ロケールについて定義されているシンボルの一部を示します。

例 6-9:  LC_TIME カテゴリの定義

LC_TIME    [1]
 
abday   "<d><i><m>";\
        "<l><u><n>";\
        "<m><a><r>";\
        "<m><e><r>";\
        "<j><e><u>";\
        "<v><e><n>";\
        "<s><a><m>"    [2]
 
day     "<d><i><m><a><n><c><h><e>";\
        "<l><u><n><d><i>";\
        "<m><a><r><d><i>";\
        "<m><e><r><c><r><e><d><i>";\
        "<j><e><u><d><i>";\
        "<v><e><n><d><r><e><d><i>";\
        "<s><a><m><e><d><i>"    [3]
 
abmon   "<j><a><n>";\
        "<f><e-acute><v>";\
        "<m><a><r>";\
        "<a><v><r>";\
        "<m><a><i>";\
        "<j><u><n>";\
        "<j><u><l>";\
        "<a><o><u-circumflex>";\
        "<s><e><p>";\
        "<o><c><t>";\
        "<n><o><v>";\
        "<d><e-acute><c>"    [4]
 
mon     "<j><a><n><v><i><e><r>";\
        "<f><e-acute><v><r><i><e><r>";\
        "<m><a><r><s>";\
        "<a><v><r><i><l>";\
        "<m><a><i>";\
        "<j><u><i><n>";\
        "<j><u><i><l><l><e><t>";\
        "<a><o><u-circumflex><t>";\
        "<s><e><p><t><e><m><b><r><e>";\
        "<o><c><t><o><b><r><e>";\
        "<n><o><v><e><m><b><r><e>";\
        "<d><e-acute><c><e><m><b><r><e>"    [5]
 
# date/time format. The following designates this
# format: "%a %e %b %H:%M:%S %Z %Y"
 
d_t_fmt "<percent-sign><a><space><percent-sign><e>\
<space><percent-sign><b><space><percent-sign><H>\
<colon><percent-sign><M><colon><percent-sign><S>\
<space><percent-sign><Z><space><percent-sign><Y>"    [6]

.
.
.
END LC_TIME [7]

  1. セクション・ヘッダ [例に戻る]

  2. 曜日の省略名

    書式中にこの文字列を含めるには,%a 変換指定子を使用します。 [例に戻る]

  3. 曜日の完全名

    書式中にこの文字列を含めるには,%A 変換指定子を使用します。 [例に戻る]

  4. 月の省略名

    書式中にこの文字列を含めるには,%b 変換指定子を使用します。 [例に戻る]

  5. 月の完全名

    書式中にこの文字列を含めるには,%B 変換指定子を使用します。 [例に戻る]

  6. 日付と時刻情報を組み合わせた書式

    この書式では,strftime() 関数で定義されているように,フィールド記述子を結合します。 フィールド記述子の一覧については, strftime(3) のリファレンス・ページを参照してください。

    規定されている書式には,曜日の省略形 (%a),月内の日付 (%e),24 時間制での時間 (%H),分 (%M),秒 (%S),タイム・ゾーン (%Z),年の完全表現 (%Y) のフィールド記述子があります。 米国東部時間で日付が 1999 年 4 月 23 日の場合,この例に指定された書式では,date コマンドで ven 23 avr 13:43:05 EDT 1999 と表示されます。 [例に戻る]

  7. セクション・トレイラ [例に戻る]

例 6-9 は,LC_TIME カテゴリのすべての標準シンボル定義を含んでいるわけではありません。 LC_TIME では,次の標準の定義を指定することもできます。

他のカテゴリ・セクションと同様に,copy 文を使用して,他のロケールの LC_TIME 定義全体をインクルードできます。 Tru64 UNIX では,ここで説明したもの以外のシンボルとフィールド記述子もサポートしています。 LC_TIME 定義についての詳細は, locale(4) のリファレンス・ページを参照してください。

6.3    マルチバイト・コードとワイド文字コード間の変換を行うライブラリの構築

C ライブラリ・ルーチンは,データ・ファイル・コードとワイド文字コード (内部処理コード) 間の変換を行う特別なインタフェース群を使用します。 省略時には,C ライブラリ・ルーチンは,シングルバイト文字だけを扱うインタフェースを使用します。 ただし,多くのルーチンには,マルチバイト文字を扱える代替インタフェースを使用するためのエントリ・ポイントが用意されています。 ロケールのコードセットに合わせて修正可能なインタフェースはメソッドと呼ばれます。

マルチバイト・コードセットを持つロケールでは,メソッドを使用しなければなりません。 また,シングルバイト・コードセットのロケールでも,メソッドを用意しなければならない場合があります。 たとえば,ロケールに対応するインタフェースが文字のデータ形式の変換を行い,その操作を正しく実行するために,コードセット固有のロジックが必要になるロケールでは,メソッドを用意する必要があります。 ただし,対応するインタフェースがワイド文字に変換済みのデータを扱っており,シングルバイト文字とマルチバイト文字の両方に有効なロジックを使用しているときは,メソッドは無くてもかまいません。

ロケールにメソッドを用意する場合,必要なメソッドのセットを含んでいなければなりません (6.3.1 項を参照)。 オプションのメソッドについては,6.3.2 項を参照してください。

メソッドは,システム上ではシェアード・ライブラリとして利用できなければなりません。 このライブラリと,各メソッドを実装するライブラリ内の関数は,methods ファイルを介して localedef コマンドから利用できるようになります。 localedef コマンドで methods ファイルを charmap および locale ソース・ファイルとともに処理すると,結果として得られるロケールには,ロケールに含まれるすべてのメソッドへのポインタと,ロケールに含まれていない省略時のオプション・メソッドへのポインタが取り込まれます。 新たに作成したロケールを LANG 変数に設定して,コマンドやアプリケーションを実行すると,メソッドは,システム・ソフトウェアで利用可能な状態になっていれば,常にコマンドやアプリケーションで使用されます。

6.3.1    必須メソッド

ロケールでメソッドを使用するときは,次のものが用意されていなければなりません。

これらのメソッドは,C ライブラリ関数でマルチバイト形式とワイド文字形式間のデータ変換を行えるようにします。

6.3.1.1    fgetws 関数用の _ _mbstopcs メソッドの作成

fgetws() 関数は _ _mbstopcs メソッドを使用して,標準入出力 (stdio) バッファ内のバイトをワイド文字列に変換します。 このメソッドを実装する関数は,呼び出しによって変換されたワイド文字の数を返さなければなりません。

このメソッドは mbstowcs() (6.3.1.6 項を参照) に類似していますが,fgetws() の要件を満たすために,いくつかのパラメータが追加されています。 一般に,このメソッドの C ソース・ファイルの名前は,_ _mbstopcs_codeset.c です。 codeset は,メソッドに対応するコードセットを示します。 例 6-10 は,ja_JP.sdeckanji ロケールで使用される _ _mbstopcs メソッドを定義するファイル,_ _mbstopcs_sdeckanji.c です。

例 6-10:  ja_JP.sdeckanji ロケールのための _ _mbstopcs_sdeckanji メソッド

#include <stdlib.h>  [1]
#include <wchar.h>   [1]
#include <sys/localedef.h>   [1]
 
int _ _mbstopcs_sdeckanji(
        wchar_t *pwcs,   [2]
        size_t pwcs_len,   [3]
        const char *s,   [4]
        size_t s_len,   [5]
        int stopchr,   [6]
        char **endptr,   [7]
        int *err,   [8]
        _LC_charmap_t *handle )   [9]
{
    int cnt = 0;   [10]
    int pwcs_cnt = 0;   [10]
    int s_cnt = 0;   [10]
 
    *err = 0;   [11]
 
    while (1) {   [12]
        if (pwcs_cnt >= pwcs_len || s_cnt >= s_len) {
            *endptr = (char *)&(s[s_cnt]);
            break;
        }   [13]
        if ((cnt = _ _mbtopc_sdeckanji(&(pwcs[pwcs_cnt]),
            &(s[s_cnt]), (s_len - s_cnt), err)) == 0) {
            *endptr = (char *)&(s[s_cnt]);
            break;
        }   [14]
        pwcs_cnt++;   [15]
        if ( s[s_cnt] == (char) stopchr) {
            *endptr = (char *)&(s[s_cnt+1]);
            break;
        }   [16]
        s_cnt += cnt;   [17]
    }   [18]
    return (pwcs_cnt);   [19]
}

  1. このメソッドに必要な定数と構造体を含むヘッダ・ファイルをインクルードします。 [例に戻る]

  2. ワイド文字列を格納しているバッファを pwcs でポイントします。 [例に戻る]

  3. pwcs バッファのサイズを格納するための変数 pwcs_len を定義します。 [例に戻る]

  4. 変換対象のマルチバイト文字列を格納しているバッファを s でポイントします。 [例に戻る]

  5. s バッファ内のデータのバイト数を格納するための変数 s_len を定義します。

    fgetws() 関数が読み込む標準入出力バッファには,ヌルで終わる文字列が含まれていないため,このパラメータが必要になります。 [例に戻る]

  6. 変換を強制終了するためのバイト値を格納する変数 stopchr を定義します。

    一般に,この値は \n で,呼び出しごとに 1 行の入力を処理する fgetws( ) 関数からの呼び出しでこのメソッドに渡されます。 [例に戻る]

  7. 変換された最後のバイトの次のバイトをポイントする変数 endptr を定義します。

    このポインタは,fgetws() の次の呼び出しに備え,標準入出力バッファ内の開始文字を指定するために必要です。 [例に戻る]

  8. このメソッドが mbtopc メソッドを呼び出したときの実行ステータスを格納している変数を,err でポイントします。 [例に戻る]

  9. このロケールの文字マップを解析するメソッドへのポインタを格納している構造体を,hdl でポイントします。

    localedef コマンドは _LC_charmap_t 構造体を作成し,値を格納します。 [例に戻る]

  10. マルチバイト形式の文字に必要なバイト数を示す変数 (mbtopc メソッドが提供する) と,fgetws() 関数が使用するバッファ内のバイトまたは文字位置を示す変数を初期化します。 [例に戻る]

  11. err にゼロ (0) を設定し,成功を示します。 [例に戻る]

  12. マルチバイト文字列を変換する while ループを開始します。 [例に戻る]

  13. ワイド文字データを含むバッファ内にスペースがなくなるか,マルチバイト・データを含むバッファ内にデータがなくなったときに,endptr を設定し,ループから抜けます。 [例に戻る]

  14. mbtopc メソッドを呼び出して,文字をマルチバイト形式からワイド文字形式に変換します。

    mbtopc メソッドが文字の変換に失敗し,エラーを返した場合,ループから抜け,変換できなかった文字の最初のバイトを endptr に設定します。

    err 変数には,次のいずれかの,mbtopc メソッド呼び出しのリターン・ステータスが格納されます。

    [例に戻る]

  15. ワイド文字データを含むバッファ内の文字位置をインクリメントします。 [例に戻る]

  16. マルチバイト・データ内に stopchr 文字が現れた場合,endptrstopchr 内の次の文字に設定します。 [例に戻る]

  17. マルチバイト・データを含むバッファ内のバイト位置をインクリメントします。 [例に戻る]

  18. while ループを終了します。 [例に戻る]

  19. ワイド文字データを含むバッファ内の文字数を返します。 [例に戻る]

6.3.1.2    getwc( ) 関数用の _ _mbtopc メソッドの作成

getwc() または fgetwc() 関数は,_ _mbtopc メソッドを呼び出して,マルチバイト文字をワイド文字に変換します。 このメソッドは,変換対象のマルチバイト文字に含まれるバイト数を返します。 このメソッドは mbtowc (6.3.1.7 項を参照) 用のメソッドと類似していますが,getwc() が必要とするパラメータが追加されています。 一般に,このメソッドの C ソース・ファイルの名前は,_ _mbtopc_codeset.c です。 codeset は,このメソッドに対応するコードセットを示します。 例 6-11 は,ja_JP.sdeckanji ロケールで使用される _ _mbtopc メソッドを定義しているファイル,_ _mbtopc_sdeckanji.c です。

例 6-11:  ja_JP.sdeckanji ロケールのための _ _mbtopc_sdeckanji メソッド

#include <stdlib.h>  [1]
#include <wchar.h>   
#include <sys/localedef.h>   
 
/*
The algorithm for this conversion is:
s[0] < 0x9f:  PC = s[0]
s[0] = 0x8e:  PC = s[1] + 0x5f;
s[0] = 0x8f   PC = (((s[1] - 0xa1) << 7) | (s[2] - 0xa1)) + 0x303c
s[0] > 0xa1:0xa1 < s[1] < 0xfe
              PC = (((s[0] - 0xa1) << 7) | (s[1] - 0xa1)) + 0x15e
            0x21 < s[1] < 0x7e
              PC = (((s[0] - 0xa1) << 7) | (s[1] - 0x21)) + 0x5f1a
+-----------------+-----------+-----------+-----------+
|  process code   |   s[0]    |   s[1]    |   s[2]    |
+-----------------+-----------+-----------+-----------+
| 0x0000 - 0x009f | 0x00-0x9f |    --     |    --     |
| 0x00a0 - 0x00ff |   --      |    --     |    --     |
| 0x0100 - 0x015d | 0x8e      | 0xa1-0xfe |    --     | JIS X0201 RH
| 0x015e - 0x303b | 0xa1-0xfe | 0xa1-0xfe |    --     | JIS X0208
| 0x303c - 0x5f19 | 0x8f      | 0xa1-0xfe | 0xa1-0xfe | JIS X0212
| 0x5f1a - 0x8df7 | 0xa1-0xfe | 0x21-0xfe |    --     | UDC
+-----------------+-----------+-----------+-----------+
*/   [2]
int  _ _mbtopc_sdeckanji(
        wchar_t *pwc,   [3]
        char *ts,   [4]
        size_t maxlen,   [5]
        int *err,   [6]
        _LC_charmap_t *handle )   [7]
{
    wchar_t dummy;   [8]
    unsigned char *s = (unsigned char *)ts;   [9]
    if (s == NULL)
        return(0);   [10]
    if (pwc == (wchar_t *)NULL)
        pwc = &dummy;   [11]
    *err = 0;   [12]
    if (s[0] <= 0x8d) {
        if (maxlen < 1) {
            *err = 1;
            return(0);
        }
        else {
            *pwc = (wchar_t) s[0];
            return(1);
        }
    }   [13]
    else if (s[0] == 0x8e) {
        if (maxlen >= 2) {
            if (s[1] >=0xa1 && s[1] <=0xfe) {
                *pwc = (wchar_t) (s[1] + 0x5f);
                return(2);
            }
        }
        else {
            *err = 2;
            return(0);
        }
    }   [14]
    else if (s[0] == 0x8f) {
        if (maxlen >= 3) {
            if ((s[1] >=0xa1 && s[1] <=0xfe) &&
                (s[2] >=0xa1 && s[2] <= 0xfe)) {
                *pwc = (wchar_t) (((s[1] - 0xa1) << 7) |
                       (wchar_t) (s[2] - 0xa1)) + 0x303c;
                return(3);
            }
        }
        else {
            *err = 3;
            return(0);
        }
    }   [15]
    else if (s[0] <= 0x9f) {
        if (maxlen < 1) {
            *err = 1;
            return(0);
        }
        else {
            *pwc = (wchar_t) s[0];
            return(1);
        }
    }   [16]
    else if (s[0] >= 0xa1 && s[0] <= 0xfe) {
        if (maxlen >= 2) {
            if  (s[1] >=0xa1 && s[1] <= 0xfe) {
                *pwc = (wchar_t) (((s[0] - 0xa1) << 7) |
                       (wchar_t) (s[1] - 0xa1)) + 0x15e;
                return(2);
            } else if  (s[1] >=0x21 && s[1] <= 0x7e) {
                *pwc = (wchar_t) (((s[0] - 0xa1) << 7) |
                       (wchar_t) (s[1] - 0x21)) + 0x5f1a;
                return(2);
            }
        }
        else {
            *err = 2;
            return(0);
        }
    }   [17]
    *err = -1;
    return(0);   [18]
}

  1. このメソッドに必要な定数と構造体を含むヘッダ・ファイルをインクルードします。 [例に戻る]

  2. コードセットでサポートされる各種の文字セットについて,バイト数と有効バイトの組み合わせを判定するためのアルゴリズムを記述しています。

    このコードセットは複数の文字セットをサポートしており,各文字セットに含まれる文字の長さは同じです。 最初のバイトの値から文字セットがわかり,同時に文字の長さも判定できます。 マルチバイト文字を含む文字セットでは,さらに 1 つまたは複数のバイトを調べ,値の並びが文字を表現しているか,無効なものかどうかを判定する必要があります。 [例に戻る]

  3. ワイド文字を格納しているバッファを pwc でポイントします。 [例に戻る]

  4. 呼び出し元の関数からメソッドに渡されるバイトを格納しているバッファを,ts でポイントします。 [例に戻る]

  5. マルチバイト・データ内の最大バイト数を含む変数 maxlen を宣言します。

    この値は呼び出し元の関数から渡されます。 [例に戻る]

  6. 実行ステータスを含むバッファを err でポイントします。 [例に戻る]

  7. このロケールの文字マップを解析するメソッドへのポインタを格納している構造体を,handle でポイントします。 [例に戻る]

  8. 変数 dummy を宣言します。 この変数を pwc に設定することにより,pwc が有効なアドレスをポイントしていることが保証されます。 [例に戻る]

  9. ts (符号付き文字の配列) を s (符号なし文字の配列) にキャストします。

    この操作を行うことにより,配列に整数値が格納されているときに,それらの値をインデックスで参照する際に起きる問題を回避できます。 コンパイラは,char のような小さな符号付きデータ型を,int のような大きな符号付きデータ型と比較するときに,値の符号拡張を行います。 この場合,次のような条件は,偽になると期待していても真と評価されます。

    if (s[0] <= 0x8d [例に戻る]

  10. s バッファが NULL を含んでいるか,NULL をポイントしているときは,ゼロ (0) を返します。 [例に戻る]

  11. ts バッファが NULL を含んでいるか,NULL をポイントしているときは,dummy の内容をワイド文字バッファに格納します。

    この操作により,*pwc は常に有効なアドレスをポイントします。 有効なアドレスをポイントしておらず,ワイド文字が pwc に格納されていない場合,アプリケーションがこのポインタを参照すると,セグメンテーション違反が発生します。 [例に戻る]

  12. err にゼロ (0) を設定し,成功を示します。 [例に戻る]

  13. 文字が,コードセットで 0x8d 以下の値として定義されているシングルバイト文字の 1 つであるかどうかを判定します。

    s が文字を含んでいない場合,ゼロ (0) を返し,バイトの変換が行われなかったことを示します。 また,err に 1 を設定し,有効な文字を作成するには 1 バイトが必要であることを示します。

    バイト値がテスト範囲に含まれている場合,対応する処理コード値を pwc に移動して,変換したバイトの数を示すために 1 を返します。 [例に戻る]

  14. 文字が,コードセットで値 0x8e (第 1 バイト) と,0xa1 から 0xfe の範囲の値 (第 2 バイト) として定義されている 2 バイト文字の 1 つであるかどうかを判定します。

    文字が条件を満たす場合,対応する処理コード値を pwc バッファに移動して,変換したバイトの数を示すために 2 を返します。 そうでなければ,ゼロ(0)を返し,変換が行われなかったことを示します。 また,err に 2 を設定し,有効な文字を作成するには少なくとも 2 バイトが必要であることを示します。 [例に戻る]

  15. 文字が,コードセットで値 0x8f (第 1 バイト),0xa1 から 0xfe の範囲の値 (第 2 バイト),および 0xa1 から 0xfe の範囲の値 (第 3 バイト) として定義されている 3 バイト文字の 1 つであるかどうかを判定します。

    文字が条件を満たす場合,対応する処理コード値を pwc バッファに移動し,変換したバイトの数を示すために 3 を返します。 そうでなければ,ゼロ (0) を返し,変換が行われなかったことを示します。 また,err に 3 を設定し,有効な文字を作成するには少なくとも 3 バイトが必要であることを示します。 [例に戻る]

  16. 文字が,コードセットで 0x90 から 0x9f の範囲の値として定義されているシングルバイト文字の 1 つであるかどうかを判定します。

    標準入出力バッファにバイト・データがない場合,ゼロ (0) を返し,変換が行われなかったことを示します。 また,err に 1 を設定し,有効な文字を作成するには少なくとも 1 バイトが必要であることを示します。

    バイト値が定義された範囲に含まれていれば,対応する処理コード値を pwc に移動し,変換したバイトの数を示すために 1 を返します。 [例に戻る]

  17. 文字が,コードセットで 0xa1 から 0xfe の範囲の値 (第 1 バイト) と,0x21 から 0x7e の範囲の値 (第 2 バイト) として定義されている 2 バイト文字の 1 つであるかどうかを判定します。

    文字が条件を満たす場合,対応する処理コード値を pwc バッファに移動し,変換したバイトの数を示すために 2 を返します。 そうでなければ,ゼロ (0) を返し,変換が行われなかったことを示します。 また,err に 2 を設定し,有効な文字を作成するには少なくとも 2 バイトが必要であることを示します。 [例に戻る]

  18. err に -1 を設定し,無効なマルチバイト・シーケンスが存在していたことを示します。 また,ゼロ (0) を返し,変換が行われなかったことを示します。

    これらの文は,s 中のマルチバイト・データが,上記の if 条件をいずれも満たしていない場合に実行されます。 [例に戻る]

6.3.1.3    fputws( ) 関数用の _ _pcstombs メソッドの作成

fputws() 関数は _ _pcstombs メソッドを呼び出して,文字列を処理 (ワイド文字) コードからマルチバイト・コードに変換します。 このメソッドが -1 を返し,ロケールでサポートされていないことを示した場合,fputws() は,変換する文字列中のワイド文字ごとに putwc() を呼び出します。 一般に,このメソッドの C ソース・ファイルの名前は,_ _pcstombs_codeset.c です。 codeset は,このメソッドに対応するコードセットを示します。 例 6-12 は,ja_JP.sdeckanji ロケールで使用される _ _pcstombs メソッドを定義するファイル,_ _pcstombs_sdeckanji.c です。

例 6-12:  ja_JP.sdeckanji ロケールのための _ _pcstombs_sdeckanji メソッド

int _ _pcstombs_sdeckanji()
{
        return -1;   [1]
}

  1. -1 を返し,このメソッドがロケールでサポートされていないことを示します。

    この戻り値により,fputws() 関数は putwc() を複数回呼び出して,文字列中のワイド文字を変換します。 [例に戻る]

単に -1 を返すだけではない完全なメソッドを実装したい場合には,関数が変換されたワイド文字の数を返すようにしなければなりません。 また,次の例に示すヘッダ・ファイルとパラメータをインクルードする必要があります。

#include <stdlib.h>
#include <wchar.h>
#include <sys/localedef.h>
 
int _ _pcstombs_newcodeset(
        wchar_t *pcsbuf,   [1]
        size_t pcsbuf_len,   [2]
        char *mbsbuf,  [3]
        size_t mbsbuf_len,  [4]
        char **endptr,  [5]
        int *err,   [6]
        _LC_charmap_t *handle )  [7]

  1. ワイド文字列を含むバッファへのポインタを指定します。 [例に戻る]

  2. ワイド文字バッファの大きさを含む変数を指定します。

    この値は,fputws() からの呼び出しでメソッドに渡されます。 [例に戻る]

  3. マルチバイト文字列を含むバッファへのポインタを指定します。 [例に戻る]

  4. マルチバイト文字バッファの大きさを含む変数を指定します。

    この値は,fputws() からの呼び出しでメソッドに渡されます。 [例に戻る]

  5. すべてのワイド文字データを変換するために fputws() を複数回呼び出さなければならない場合,マルチバイト文字バッファ内の次の文字の開始バイト位置へのポインタを,endptr でポイントします。 [例に戻る]

  6. 実行ステータスを返すためのポインタを指定します。

    このメソッドが文字変換を行うために wctomb メソッドを呼び出す場合,このステータスは wctomb が設定します。 それ以外の場合には,このメソッドはワイド文字からマルチバイト文字への変換を実行するロジックを備えている必要があり,また,このメソッドがステータスを直接設定しなければなりません。

    いずれの場合でも,fputws() 関数は次の値を想定します。

    [例に戻る]

  7. このロケールで使用されるメソッドへのポインタを格納している _LC_charmap_t 構造体へのポインタを指定します。 [例に戻る]

_ _pcstombs メソッドは,_ _mbstopcs メソッドが実行する操作 (6.3.1.1 項を参照) の逆の操作を行います。 データ変換の向きが異なるため,_ _pcstombs メソッドには次のような特徴があります。

6.3.1.4    _ _pctomb メソッドの作成

C ライブラリ関数は,現時点では _ _pctomb インタフェースを使用しません。 たとえば putwc() 関数は,wctomb メソッドを呼び出して,文字をワイド文字形式からマルチバイト文字形式に変換します。 ただし,localedef コマンドは,ロケールでメソッドが提供されている場合には,この関数のためのメソッドを必要とします。 一般に,このメソッドの C ソース・ファイルの名前は,_ _pctomb_codeset.c です。 codeset は,このメソッドに対応するコードセットを示します。 例 6-13 は,ja_JP.sdeckanji ロケールで使用される _ _pctomb メソッドを定義するファイル,_ _pctomb_sdeckanji.c です。

例 6-13:  ja_JP.sdeckanji ロケールのための _ _pctomb_sdeckanji メソッド

int _ _pctomb_sdeckanji()
{
        return -1;   [1]
}

  1. -1 を返し,ロケールでこのメソッドがサポートされていないことを示します。 [例に戻る]

6.3.1.5    mblen( ) 関数用のメソッドの作成

mblen() 関数は mblen メソッドを使用して,マルチバイト文字のバイト数を返します。 一般に,このメソッドの C ソース・ファイルの名前は,_ _mblen_codeset.c です。 codeset は,このメソッドに対応するコードセットを示します。 例 6-14 は,ja_JP.sdeckanji ロケールで使用される mblen メソッドを定義するファイル,_ _mblen_sdeckanji.c です。

例 6-14:  ja_JP.sdeckanji ロケールのための _ _mblen_sdeckanji メソッド

#include <stdlib.h>   [1]
#include <wchar.h>   
#include <sys/errno.h>   
#include <sys/localedef.h>   
 
/*
The algorithm for this conversion is:
 
s[0] < 0x9f:  1 byte
s[0] = 0x8e:  2 bytes
s[0] = 0x8f   3 bytes
s[0] > 0xa1   2 bytes
 
+-----------------+-----------+-----------+-----------+
|  process code   |   s[0]    |   s[1]    |   s[2]    |
+-----------------+-----------+-----------+-----------+
| 0x0000 - 0x009f | 0x00-0x9f |    --     |    --     |
| 0x00a0 - 0x00ff |   --      |    --     |    --     |
| 0x0100 - 0x015d | 0x8e      | 0xa1-0xfe |    --     | JIS X0201 RH
| 0x015e - 0x303b | 0xa1-0xfe | 0xa1-0xfe |    --     | JIS X0208
| 0x303c - 0x5f19 | 0x8f      | 0xa1-0xfe | 0xa1-0xfe | JIS X0212
| 0x5f1a - 0x8df7 | 0xa1-0xfe | 0x21-0xfe |    --     | UDC
+-----------------+-----------+-----------+-----------+
*/   [2]
 
int _ _mblen_sdeckanji(
        char *fs,   [3]
        size_t maxlen,   [4]
        _LC_charmap_t *handle )   [5]
{
    const unsigned char *s = (void *) fs;   [6]
 
    if (s == NULL || *s == '\0')
        return(0);   [7]
 
    if (maxlen < 1) {
        _Seterrno(EILSEQ);
        return((size_t)-1);
    }   [8]
 
    if (s[0] <= 0x8d)
        return(1);   [9]
 
    else if (s[0] == 0x8e) {
        if (maxlen >= 2 && s[1] >=0xa1 && s[1] <=0xfe)
            return(2);
    }   [10]
 
    else if (s[0] == 0x8f) {
        if(maxlen >=3 && (s[1] >=0xa1 && s[1] <=0xfe) &&
            (s[2] >=0xa1 && s[2] <= 0xfe))
            return(3);
    }   [11]
 
    else if (s[0] <= 0x9f)
        return(1);   [12]
 
    else if (s[0] >= 0xa1) {
            if (maxlen >=2 && (s[0] <= 0xfe) )
                    if ( (s[1] >=0xa1 && s[1] <= 0xfe) ||
                       (s[1] >=0x21 && s[1] <= 0x7e) )
                        return(2);
    }   [13]
 
    _Seterrno(EILSEQ);
    return((size_t)-1);   [14]
}

  1. このメソッドに必要な定数と構造体を含むヘッダ・ファイルをインクルードします。 [例に戻る]

  2. 文字のバイト数と,その文字が有効なバイト・シーケンスであるかどうかを決定するためのアルゴリズムを記述します。

    このコードセットは複数の文字セットをサポートしており,各文字に含まれる文字の長さは同じです。 最初のバイトの値から文字セットがわかり,同時に文字の長さも判定できます。 マルチバイト文字を含む文字セットでは,さらに 1 つまたは複数のバイトを調べ,値の並びが文字を表現しているか,無効なものかどうかを判定する必要があります。 [例に戻る]

  3. 検査するバイト文字列を含むバッファを fs でポイントします。 [例に戻る]

  4. マルチバイト文字の最大長を含む変数 maxlen を定義します。

    この値は,mblen() 関数からこのメソッドに渡されます。 [例に戻る]

  5. このロケールの文字マップを解析するメソッドへのポインタを格納している構造体を,handle でポイントします。 [例に戻る]

  6. fs (符号付き文字の配列) を s (符号なし文字の配列) にキャストします。

    この操作を行うことにより,配列に整数値が格納されているときに,インデックスで参照する際に起きる問題を回避できます。 コンパイラは,char のような小さな符号付きデータ型を,int のような大きな符号付きデータ型と比較するときに,値の符号拡張を行います。 この場合,次のような条件は,偽になると期待していても真と評価されます。

    if (s[0] <= 0x8d [例に戻る]

  7. sNULL を含んでいるか,NULL をポイントしているときは,ゼロ (0) を返し,文字の長さがゼロ (0) であることを示します。 [例に戻る]

  8. maxlen (最大バイト数) がゼロか,負の値の場合には,-1 を返し,errno に [EILSEQ] (無効な文字シーケンス) を設定します。

    マルチスレッド・アプリケーションで errno が正しく機能するように設定するには,代入文ではなく _Seterrno を使用します。 [例に戻る]

  9. 最初のバイトが 0x8d 以下のシングルバイト文字を示しているかどうかを判定します。

    そうであれば,1 を返して,文字の長さが 1 バイトであることを示します。 [例に戻る]

  10. 最初のバイトが値 0x8e を含み,2 番目のバイトが 0xa1 から 0xfe の範囲の値を含む 2 バイト文字を示しているかどうかを判定します。

    そうであれば,2 を返して,文字の長さが 2 バイトであることを示します。 [例に戻る]

  11. 最初のバイトが値 0x8f を含み,2 番目と 3 番目のバイトが 0xa1 から 0xfe の範囲の値を含む 3 バイト文字を示しているかどうかを判定します。

    そうであれば,3 を返して,文字の長さが 3 バイトであることを示します。 [例に戻る]

  12. 最初のバイトが 0x9f 以下のシングルバイト文字を示しているかどうかを判定します。

    そうであれば,1 を返して,文字の長さが 1 バイトであることを示します。 [例に戻る]

  13. 最初のバイトが 0xa1 から 0xfe の範囲の値を含み,2 番目のバイトが 0x21 から 0x7e の範囲の値を含む 2 バイト文字を示しているかどうかを判定します。

    そうであれば,2 を返して,文字の長さが 2 バイトであることを示します。 [例に戻る]

  14. -1 を返し,errno に [EILSEQ] を設定して,無効なマルチバイト・シーケンスであることを示します。

    これらの文は,標準入出力バッファ内のマルチバイト・データが,上記の if 条件をいずれも満たさない場合に実行されます。 [例に戻る]

6.3.1.6    mbstowcs( ) 関数用のメソッドの作成

mbstowcs() 関数は mbstowcs メソッドを使用して,マルチバイト文字列をプロセス・ワイド文字コードに変換し,結果として得られたワイド文字の数を返します。 一般に,このメソッドの C ソース・ファイルの名前は,_ _mbstowcs_codeset.c です。 codeset は,このメソッドに対応するコードセットを示します。 例 6-15 は,ja_JP.sdeckanji ロケールで使用される mbstowcs メソッドを定義するファイル,_ _mbstowcs_sdeckanji.c です。

例 6-15:  ja_JP.sdeckanji ロケールのための _ _mbstowcs_sdeckanji メソッド

#include <stdlib.h>   [1]
#include <wchar.h>   
#include <sys/localedef.h>  
 
size_t _ _mbstowcs_sdeckanji(
        wchar_t *pwcs,   [2]
        const char *s,   [3]
        size_t n,   [4]
        _LC_charmap_t *handle )   [5]
{
    int len = n;   [6]
    int rc;   [7]
    int cnt;   [8]
    wchar_t *pwcs0 = pwcs;   [9]
    int mb_cur_max;   [10]
 
    if (s == NULL)
        return (0);   [11]
 
    mb_cur_max = MB_CUR_MAX;   [12]
 
    if (pwcs == (wchar_t *)NULL) {
        cnt = 0;
        while (*s != '\0') {
             if ((rc = _ _mblen_sdeckanji(s, mb_cur_max, handle)) == -1)
                return(-1);
             cnt++  ;
             s += rc;
        }
        return(cnt);
    }   [13]
 
    while (len-- > 0) {
        if ( *s == '\0') {
            *pwcs = (wchar_t) '\0';
            return (pwcs - pwcs0);
        }
        if ((cnt = _ _mbtowc_sdeckanji(pwcs, s, mb_cur_max, handle)) < 0)
            return(-1);
        s += cnt;
        ++pwcs;
    }   [14]
 
    return (n);   [15]
}

  1. このメソッドに必要な定数と構造体を含むヘッダ・ファイルをインクルードします。 [例に戻る]

  2. ワイド文字列を格納しているバッファを pwcs でポイントします。 [例に戻る]

  3. マルチバイト文字列を格納しているバッファを s でポイントします。 [例に戻る]

  4. pwcs 中のワイド文字数を含む変数 n を定義します。 [例に戻る]

  5. このロケールの文字マップを解析するメソッドへのポインタを格納している構造体を,handle でポイントします。 [例に戻る]

  6. pwcs バッファ内のワイド文字の数 (呼び出し元関数が指定した n の値) を len に代入します。 [例に戻る]

  7. このメソッドから呼び出される mblen 関数が返す値を含む変数 rc を定義します。 [例に戻る]

  8. s バッファ内の文字に使用されるバイト数をカウントする変数 cnt を定義します。 [例に戻る]

  9. 呼び出し元の関数が pwcs0 変数に渡すワイド文字列の開始点を保存します。 [例に戻る]

  10. 変数 mb_cur_max を定義します。 この変数は後で MB_CUR_MAX に設定され,mblen メソッドの呼び出しで使用されます。 [例に戻る]

  11. sNULL の場合,ゼロ (0) を返します。

    メソッドは,ロケールにおける文字のエンコーディングに状態がなければゼロ (0) を返し,状態があればゼロ以外の値を返します。 [例に戻る]

  12. MB_CUR_MAX に設定されている値を mb_cur_max に代入し,後で mblen メソッドの呼び出しに使用します。 [例に戻る]

  13. NULL ポインタが呼び出し元の関数から渡されたかどうかを調べ,渡されていれば mblen メソッドを呼び出してワイド文字列のサイズを計算します。

    mbstowcs() の呼び出しでヌル・ワイド文字を pwcs パラメータとして渡すことにより,メモリ割り当てに使用する pwcs バッファのサイズを取得できます。 また,この戻り値を使用することにより,再度 mbstowcs() を呼び出してマルチバイト文字列を実際に変換する前に,アプリケーションのワイド文字バッファのメモリ・スペースを効率的に割り当てることができます。 [例に戻る]

  14. ヌル文字 (文字列の終わり) が現れるまで _ _mbtowc メソッドを呼び出すことにより,マルチバイト文字バッファ内のバイトを変換します。

    NULL が検出されたら処理を停止し,pwcs バッファ内のワイド文字の数を返します。 文字の変換に成功するたびに,マルチバイト文字バッファ内のバイト位置を適切な数だけインクリメントします。

    この while ループは,条件 len-- > 0 を使用して,pwcs バッファが一杯になったときに処理を停止します。 ループ中の最初の if 条件は,s バッファ内のマルチバイト文字列がヌルで終了しているときに,pwcs バッファ内の対応するヌル終端子が,mbtowcs() 関数によりアプリケーションに返されるワイド文字数に含まれないようにします。 [例に戻る]

  15. n の値を返して,pwcs バッファ内のワイド文字の数を示します。

    この文は,s バッファ内でヌルが検出される前に,pwcs バッファのスペースが足りなくなった場合に実行されます。 [例に戻る]

6.3.1.7    mbtowc( ) 関数用のメソッドの作成

mbtowc() 関数は mbtowc メソッドを使用して,マルチバイト文字をワイド文字に変換し,変換したマルチバイト文字のバイト数を返します。 一般に,このメソッドの C ソース・ファイルの名前は,_ _mbtowc_codeset.c です。 codeset は,このメソッドが対応するコードセットを示します。 例 6-16 は,ja_JP.sdeckanji ロケールで使用される mbtowc メソッドを定義するファイル,_ _mbtowc_sdeckanji.c です。

例 6-16:  ja_JP.sdeckanji ロケールのための _ _mbtowc_sdeckanji メソッド

#include <stdlib.h>   [1]
#include <wchar.h>   
#include <sys/errno.h>   
#include <sys/localedef.h>   
 
/*
The algorithm for this conversion is:
 
s[0] < 0x9f:  PC = s[0]
s[0] = 0x8e:  PC = s[1] + 0x5f;
s[0] = 0x8f   PC = (((s[1] - 0xa1) << 7) | (s[2] - 0xa1)) + 0x303c
s[0] > 0xa1:0xa1 < s[1] < 0xfe
              PC = (((s[0] - 0xa1) << 7) | (s[1] - 0xa1)) + 0x15e
0x21 < s[1] < 0x7e
              PC = (((s[0] - 0xa1) << 7) | (s[1] - 0x21)) + 0x5f1a
 
+-----------------+-----------+-----------+-----------+
|  process code   |   s[0]    |   s[1]    |   s[2]    |
+-----------------+-----------+-----------+-----------+
| 0x0000 - 0x009f | 0x00-0x9f |    --     |    --     |
| 0x00a0 - 0x00ff |   --      |    --     |    --     |
| 0x0100 - 0x015d | 0x8e      | 0xa1-0xfe |    --     | JIS X0201 RH
| 0x015e - 0x303b | 0xa1-0xfe | 0xa1-0xfe |    --     | JIS X0208
| 0x303c - 0x5f19 | 0x8f      | 0xa1-0xfe | 0xa1-0xfe | JIS X0212
| 0x5f1a - 0x8df7 | 0xa1-0xfe | 0x21-0xfe |    --     | UDC
+-----------------+-----------+-----------+-----------+
*/   [2]
int _ _mbtowc_sdeckanji(
        wchar_t *pwc,   [3]
        const char *ts,   [4]
        size_t maxlen,   [5]
        _LC_charmap_t *handle )   [6]
{
    unsigned char *s = (unsigned char *)ts;   [7]
    wchar_t dummy;   [8]
 
    if (s == NULL)
        return(0);   [9]
 
    if (maxlen < 1) {
        _Seterrno(EILSEQ);
        return((size_t)-1);
    }   [10]
 
    if (pwc == (wchar_t *)NULL)
        pwc = &dummy;   [11]
 
    if (s[0] <= 0x8d) {
        *pwc = (wchar_t) s[0];
        if (s[0] != '\0')
            return(1);
        else
            return(0);
    }   [12]
 
    else if (s[0] == 0x8e) {
        if ( (maxlen >= 2) && ((s[1] >=0xa1) && (s[1] <=0xfe))) {
            *pwc = (wchar_t) (s[1] + 0x5f); /* 0x100 - 0xa1 */
            return(2);
        }
    }   [13]
 
    else if (s[0] == 0x8f) {
        if((maxlen >= 3) && (((s[1] >=0xa1) && (s[1] <=0xfe))
           && ((s[2] >=0xa1) && (s[2] <= 0xfe)))) {
                *pwc = (wchar_t) (((s[1] - 0xa1) << 7) |
                   (wchar_t) (s[2] - 0xa1)) + 0x303c;
           return(3);
        }
    }   [14]
 
    else if (s[0] <= 0x9f) {
        *pwc = (wchar_t) s[0];
        if (s[0] != '\0')
            return(1);
        else
            return(0);
    }   [15]
 
    else if (((s[0] >= 0xa1) && (s[0] <= 0xfe)) && (maxlen >= 2)){
            if (((s[1] >=0xa1) && (s[1] <= 0xfe))){
                    *pwc = (wchar_t) (((s[0] - 0xa1) << 7) |
                              (wchar_t)(s[1] - 0xa1)) + 0x15e;
                    return(2);
            } else if (((s[1] >=0x21) && (s[1] <= 0x7e))){
                    *pwc = (wchar_t) (((s[0] - 0xa1) << 7) |
                              (wchar_t)(s[1] - 0x21)) + 0x5f1a;
                    return(2);
            }
    }   [16]
    _Seterrno(EILSEQ);
    return(-1);   [17]
}

  1. このメソッドに必要な定数と構造体を含むヘッダ・ファイルをインクルードします。 [例に戻る]

  2. 文字のバイト数と,その文字が有効なバイト・シーケンスであるかどうかを判定するためのアルゴリズムを記述します。

    このコードセットは複数の文字セットをサポートしており,各文字セットに含まれる文字の長さは同じです。 最初のバイトの値から文字セットがわかり,同時に文字の長さも判定できます。 マルチバイト文字を含む文字セットでは,さらに 1 つまたは複数のバイトを調べ,値の並びが文字を表現しているか,無効なものかどうかを判定する必要があります。 [例に戻る]

  3. ワイド文字を含むバッファを pwc でポイントします。 [例に戻る]

  4. マルチバイト文字形式の値を含むバッファを ts でポイントします。 [例に戻る]

  5. マルチバイト文字の最大長を含む変数 maxlen を定義します。

    この値は呼び出し元の関数から渡されます。 値は,アプリケーション・プログラマが最初に行った呼び出しで,MB_CUR_MAX に設定されています。 [例に戻る]

  6. このロケールの文字マップを解析するメソッドへのポインタを格納している構造体を,handle でポイントします。 [例に戻る]

  7. ts (符号付き文字の配列) を s (符号なし文字の配列) にキャストします。

    この操作を行うことにより,配列に整数値が格納されているときに,インデックスで参照する際に起きる問題を回避できます。 コンパイラは,char のような小さな符号付きデータ型を,int のような大きな符号付きデータ型と比較するときに,値の符号拡張を行います。 この場合,次のような条件は,偽になると期待していても真と評価されます。

    if (s[0] <= 0x8d [例に戻る]

  8. 変数 dummy を宣言します。 この変数を pwc に設定することにより,pwc が有効なアドレスをポイントすることが保証されます。 [例に戻る]

  9. sNULL を含んでいるか,NULL をポイントしているときは,ゼロ (0) を返して,ロケールにおける文字のエンコーディングに状態がないことを示します。

    NULL ポインタが渡された場合,このメソッドは,ロケールにおける文字のエンコーディングに状態があるかどうかを示す値を返さなければなりません。 状態がある場合は,ゼロ以外の値を返します。 [例に戻る]

  10. マルチバイト・データ・バッファの長さが 1 バイト未満であれば,size_t にキャストされた -1 を返し,errno に [EILSEQ] (無効なバイト・シーケンス) を設定します。 [例に戻る]

  11. ts バッファが NULL を含んでいるか,NULL をポイントしているときは,dummy の内容をワイド文字バッファに格納します。

    この操作により,pwc は常に有効なアドレスをポイントします。 この操作を行わないと,ワイド文字が pwc に格納されていないときにアプリケーションがこのポインタを参照した場合,セグメンテーション違反が発生します。 [例に戻る]

  12. 最初のバイトが,0x8d 以下のシングルバイト文字を示しているかどうかを判定します。

    そうであれば,対応する処理コード値を pwc バッファに格納し,文字の長さが 1 バイトであることを示す 1 を返します。 [例に戻る]

  13. 最初のバイトが値 0x8e を含み,2 番目のバイトが 0xa1 から 0xfe の範囲の値を含む 2 バイト文字を示しているかどうかを判定します。

    そうであれば,対応する処理コード値を pwc バッファに格納し,文字の長さが 2 バイトであることを示す 2 を返します。 [例に戻る]

  14. 最初のバイトが値 0x8f を含み,2 番目と 3 番目のバイトが 0xa1 から 0xfe の範囲の値を含む 3 バイト文字を示しているかどうかを判定します。

    そうであれば,対応する処理コード値を pwc バッファに格納し,文字の長さが 3 バイトであることを示す 3 を返します。 [例に戻る]

  15. 最初のバイトの値が 0x9f 以下のシングルバイト文字を示しているかどうかを判定します。

    そうであれば,対応する処理コード値を pwc バッファに格納し,文字の長さが 1 バイトであることを示す 1 を返します。 [例に戻る]

  16. 最初のバイトが 0xa1 から 0xfe の範囲の値を含み,2 番目のバイトが 0x21 から 0x7e の範囲の値を含む 2 バイト文字を示しているかどうかを判定します。

    そうであれば,対応する処理コード値を pwc バッファに格納し,文字の長さが 2 バイトであることを示す 2 を返します。 [例に戻る]

  17. -1 を返し,errno に [EILSEQ] を設定して,無効なマルチバイト・シーケンスであることを示します。

    これらの文は,s バッファ内のマルチバイト・データが上記の if 条件をいずれも満たさない場合に実行されます。 [例に戻る]

6.3.1.8    wcstombs( ) 関数用のメソッドの作成

wcstombs() 関数は wcstombs メソッドを呼び出して,ワイド文字列をマルチバイト文字列に変換し,結果として得られたマルチバイト文字列のバイト数を返します。 一般に,このメソッドの C ソース・ファイルの名前は,_ _wcstombs_codeset.c です。 codeset は,このメソッドに対応するコードセットを示します。 例 6-17 は,ja_JP.sdeckanji ロケールで使用される wcstombs メソッドを定義するファイル,_ _wcstombs_sdeckanji.c です。

例 6-17:  ja_JP.sdeckanji ロケールのための _ _wcstombs_sdeckanji メソッド

#include <stdlib.h>   [1]
#include <wchar.h>   
#include <limits.h>   
#include <sys/localedef.h>   
 
size_t _ _wcstombs_sdeckanji(
        char *s,   [2]
        const wchar_t *pwcs,   [3]
        size_t n,   [4]
        _LC_charmap_t *handle )   [5]
{
    int cnt=0;   [6]
    int len=0;   [7]
    int i=0;   [8]
    char tmps[MB_LEN_MAX+1];   [9]
 
    if ( s == (char *)NULL) {
        cnt = 0;
        while (*pwcs != (wchar_t)'\0') {
            if ((len = _ _wctomb_sdeckanji(tmps, *pwcs)) == -1)
                    return(-1);
            cnt += len;
            pwcs++;
        }
        return(cnt);
    }   [10]
 
    if (*pwcs == (wchar_t)'\0') {
        *s = '\0';
        return(0);
    }   [11]
 
    while (1) {   [12]
 
        if ((len = _ _wctomb_sdeckanji(tmps, *pwcs)) == -1)
            return(-1);   [13]
 
        else if (cnt+len > n) {
            *s = '\0';
            break;
        }   [14]
 
        if (tmps[0] == '\0') {
            *s = '\0';
            break;
        }   [15]
 
        for (i=0; i<len; i++) {
            *s = tmps[i];
            s++;
        }   [16]
 
        cnt += len;   [17]
 
        if (cnt == n)
            break;   [18]
 
        pwcs++;   [19]
    }   [20]
 
    if (cnt == 0)
        cnt = len;   [21]
    return (cnt);   [22]
}

  1. このメソッドに必要な定数と構造体を含むヘッダ・ファイルをインクルードします。 [例に戻る]

  2. このメソッドが呼び出し元の関数に渡すマルチバイト文字列を格納しているバッファを,s でポイントします。 [例に戻る]

  3. 変換するワイド文字列を格納しているバッファを pwcs でポイントします。 [例に戻る]

  4. マルチバイト文字列バッファ内の最大バイト数を格納する変数 n を定義します。

    この値は,呼び出し元の関数が指定します。 [例に戻る]

  5. このロケールの文字マップを解析するメソッドへのポインタを格納している構造体を,handle でポイントします。 [例に戻る]

  6. 変換された文字のバイト数 (len) でインクリメントされる変数 cnt を初期化します。 [例に戻る]

  7. 変換された文字の長さを含む変数 len を初期化します。 [例に戻る]

  8. 変換した文字を一時的な記憶領域から s に移動するときに,各マルチバイト文字中のバイトに対するインデックスとして使用する変数 i を初期化します。 [例に戻る]

  9. wctomb メソッドの呼び出しで返されるマルチバイト文字を格納している一時的なバッファ tmps を定義します。 [例に戻る]

  10. 呼び出し元の関数が s バッファに NULL を渡したかどうかを調べます。

    NULL が渡されている場合,wctomb メソッドを呼び出して,マルチバイト文字バッファ内の変換された文字に必要なバイト数 (ヌル終端子は除く) を計算します。

    wcstombs() の呼び出しでヌル・バイトを s パラメータとして渡すことにより,メモリ割り当てに使用する s バッファのサイズを取得できます。 また,この戻り値を使用することにより,再度 wcstombs() を呼び出してワイド文字列を実際に変換する前に,アプリケーションのワイド文字バッファのメモリ・スペースを効率的に割り当てることができます。 [例に戻る]

  11. ゼロ (0) を返し,マルチバイト文字が得られなかったことを示します。 また,pwcsNULL をポイントしていれば,sNULL を設定します。 [例に戻る]

  12. ワイド文字列中の文字を処理する while ループを開始します。 [例に戻る]

  13. wctomb メソッドを呼び出して,ワイド文字バッファ内の文字を変換します。 wctomb が -1 を返したときは,-1 を返して,文字が無効であることを示します。 [例に戻る]

  14. wctomb が変換した文字のためのスペースが s になければ,s の末尾に NULL を置き,while ループを抜けます。 [例に戻る]

  15. s 中で NULL が検出されときは,s にヌル終端子を移動して,while ループを抜けます。 [例に戻る]

  16. 現在のワイド文字が NULL でない場合,tmps 内の各バイトを s に追加します。 [例に戻る]

  17. マルチバイト形式でこの文字が占めるバイト数 (len) だけ,cnt をインクリメントします。 [例に戻る]

  18. 処理されたバイト数が n (s の最大バイト数) に等しいときは,ヌル終端子を追加せずに while ループを抜けます。 [例に戻る]

  19. pwcs をインクリメントし,変換する次のワイド文字をポイントするようにします。 [例に戻る]

  20. 個々のワイド文字を変換する while ループを終了します。 [例に戻る]

  21. s に 1 文字分のスペースがない場合は,ゼロ (0) を返すようにします。 [例に戻る]

  22. 結果として得られたマルチバイト文字列中のバイト数を返します。 [例に戻る]

6.3.1.9    wctomb( ) 関数用のメソッドの作成

wctomb() 関数は wctomb メソッドを呼び出して,ワイド文字をマルチバイト文字に変換し,結果として得られたマルチバイト文字のバイト数を返します。 一般に,このメソッドの C ソース・ファイルの名前は,_ _wctomb_codeset.c です。 codeset は,このメソッドに対応するコードセットを示します。 例 6-18 は,ja_JP.sdeckanji ロケールのための wctomb メソッドを定義するファイル,_ _wctomb_sdeckanji.c です。

例 6-18:  ja_JP.sdeckanji ロケールのための _ _wctomb_sdeckanji メソッド

#include <stdlib.h>   [1]
#include <wchar.h>   
#include <sys/errno.h>   
#include <sys/localedef.h>   
 
/*
  The algorithm for this conversion is:
 
PC <= 0x009f:                 s[0] = PC
PC >= 0x0100 and PC <=0x015d: s[0] = 0x8e
                              s[1] = PC - 0x005f
PC >= 0x015e and PC <=0x303b: s[0] = ((PC - 0x015e) >> 7) + 0x00a1
                              s[1] = ((PC - 0x015e) & 0x007f) + 0x00a1
PC >= 0x303c and PC <=0x5f19: s[0] = 0x8f
                              s[1] = ((PC - 0x303c) >> 7) + 0x00a1
                              s[2] = ((PC - 0x303c) & 0x007f) + 0x00a1
PC >= 0x5f1a and PC <=0x8df7  s[0] = ((PC - 0x5f1a) >> 7) + 0x00a1
                              s[1] = ((PC - 0x5f1a) & 0x007f) + 0x0021
 
+-----------------+-----------+-----------+-----------+
|  process code   |   s[0]    |   s[1]    |   s[2]    |
+-----------------+-----------+-----------+-----------+
| 0x0000 - 0x009f | 0x00-0x9f |    --     |    --     |
| 0x00a0 - 0x00ff |   --      |    --     |    --     |
| 0x0100 - 0x015d | 0x8e      | 0xa1-0xfe |    --     | JIS X0201 RH
| 0x015e - 0x303b | 0xa1-0xfe | 0xa1-0xfe |    --     | JIS X0208
| 0x303c - 0x5f19 | 0x8f      | 0xa1-0xfe | 0xa1-0xfe | JIS X0212
| 0x5f1a - 0x8df7 | 0xa1-0xfe | 0x21-0xfe |    --     | UDC
+-----------------+-----------+-----------+-----------+
*/   [2]
 
int _ _wctomb_sdeckanji(
        char *s,    [3]
        wchar_t wc,    [4]
        _LC_charmap_t *handle )    [5]
{
    if (s == (char *)NULL)
        return(0);    [6]
 
    if (wc <= 0x9f) {
        s[0] = (char) wc;
        return(1);
    }    [7]
 
    else if ((wc >= 0x0100) && (wc <= 0x015d)) {
        s[0] = 0x8e;
        s[1] = wc - 0x5f;
        return(2);
    }    [8]
 
    else if ((wc >=0x015e) && (wc <= 0x303b)) {
        s[0] = (char) (((wc - 0x015e) >> 7) + 0x00a1);
        s[1] = (char) (((wc - 0x015e) & 0x007f) + 0x00a1);
        return(2);
    }    [9]
 
    else if ((wc >=0x303c) && (wc <= 0x5f19)) {
        s[0] = 0x8f;
        s[1] = (char) (((wc - 0x303c) >> 7) + 0x00a1);
        s[2] = (char) (((wc - 0x303c) & 0x007f) + 0x00a1);
        return(3);
    }    [10]
 
    else if ((wc >=0x5f1a) && (wc <= 0x8df7)) {
        s[0] = (char) (((wc - 0x5f1a) >> 7) + 0x00a1);
        s[1] = (char) (((wc - 0x5f1a) & 0x007f) + 0x0021);
        return(2);
    }    [11]
 
    _Seterrno(EILSEQ);
    return(-1);    [12]
}

  1. このメソッドに必要な定数と構造体を含むヘッダ・ファイルをインクルードします。 [例に戻る]

  2. このメソッドが使用する変換アルゴリズムを記述します。

    コードセットでサポートされる各文字セットは,ワイド文字 (処理コード) 値の一意の範囲に対応しています。 個々の文字セット中では,マルチバイト文字の長さは一定 (1,2 または 3 バイト) です。 そのため,個々のワイド文字が属している範囲は,マルチバイト形式の文字に必要なバイト数を示します。 ワイド文字値そのものは,その文字のマルチバイト形式における特定の値を決定します。 [例に戻る]

  3. マルチバイト文字を含むバッファを s でポイントします。 [例に戻る]

  4. ワイド文字を含む変数 wc を定義します。 [例に戻る]

  5. このロケールの文字マップを解析するメソッドへのポインタを格納している構造体を,handle でポイントします。 [例に戻る]

  6. sNULL をポイントするときは,ゼロ (0) を返して,文字の変換が行われなかったことを示します。 [例に戻る]

  7. ワイド文字値が 0x9f 以下の場合,その値を配列 s の最初のバイトに移動して,変換された文字の長さが 1 バイトであることを示す 1 を返します。 [例に戻る]

  8. ワイド文字値が 0x0100 から 0x015d の範囲にあれば,値 0x8e を配列 s の最初のバイトに移動し,計算した値を 2 番目のバイトに移動します。 2 を返して,変換された文字の長さが 2 バイトであることを示します。 [例に戻る]

  9. ワイド文字値が 0x015e から 0x303b の範囲にあれば,計算した値を配列 s の最初のバイトと 2 番目のバイトに移動します。 2 を返して,変換された文字の長さが 2 バイトであることを示します。 [例に戻る]

  10. ワイド文字値が 0x303c から 0x5f19 の範囲にあれば,値 0x8f を配列 s の最初のバイトに移動し,計算した値を 2 番目と 3 番目のバイトに移動します。 3 を返して,変換された文字の長さが 3 バイトであることを示します。 [例に戻る]

  11. ワイド文字の値が 0x5f1a から 0x8df7 の範囲にあれば,計算した値を配列 s の最初のバイトと 2 番目のバイトに移動します。 2 を返して,変換された文字の長さが 2 バイトであることを示します。 [例に戻る]

  12. errno に [EILSEQ] を設定し,-1 を返して,ワイド文字が無効であることを示します。

    これらの文は,ワイド文字の値が上記の条件をいずれも満たさない場合に実行されます。 [例に戻る]

6.3.1.10    wcswidth( ) 関数用のメソッドの作成

wcswidth() 関数は wcswidth メソッドを使用して,ワイド文字列を表示するのに必要なカラム数を判定します。 一般に,このメソッドの C ソース・ファイルの名前は,_ _wcswidth_codeset.c です。 codeset は,このメソッドに対応するコードセットを示します。 例 6-19 は,ja_JP.sdeckanji ロケールに使用される wcswidth メソッドを定義するファイル,_ _wcswidth_sdeckanji.c です。

例 6-19:  ja_JP.sdeckanji ロケールのための _ _wcswidth_sdeckanji メソッド

#include <stdlib.h>   [1]
#include <wchar.h>   
#include <sys/localedef.h>   
 
/*
The algorithm for this conversion is:
 
PC <= 0x009f:                 s[0] = PC
PC >= 0x0100 and PC <=0x015d: s[0] = 0x8e
                              s[1] = PC - 0x005f
PC >= 0x015e and PC <=0x303b: s[0] = ((PC - 0x015e) >> 7) + 0x00a1
                              s[1] = ((PC - 0x015e) & 0x007f) + 0x00a1
PC >= 0x303c and PC <=0x5f19: s[0] = 0x8f
                              s[1] = ((PC - 0x303c) >> 7) + 0x00a1
                              s[2] = ((PC - 0x303c) & 0x007f) + 0x00a1
PC >= 0x5f1a and PC <=0x8df7  s[0] = ((PC - 0x5f1a) >> 7) + 0x00a1
                              s[1] = ((PC - 0x5f1a) & 0x007f) + 0x0021
 
+-----------------+-----------+-----------+-----------+
|  process code   |   s[0]    |   s[1]    |   s[2]    |
+-----------------+-----------+-----------+-----------+
| 0x0000 - 0x009f | 0x00-0x9f |    --     |    --     |
| 0x00a0 - 0x00ff |   --      |    --     |    --     |
| 0x0100 - 0x015d | 0x8e      | 0xa1-0xfe |    --     | JIS X0201 RH
| 0x015e - 0x303b | 0xa1-0xfe | 0xa1-0xfe |    --     | JIS X0208
| 0x303c - 0x5f19 | 0x8f      | 0xa1-0xfe | 0xa1-0xfe | JIS X0212
| 0x5f1a - 0x8df7 | 0xa1-0xfe | 0x21-0xfe |    --     | UDC
+-----------------+-----------+-----------+-----------+
*/   [2]
 
int _ _wcswidth_sdeckanji(
        const wchar_t *wcs,   [3]
        size_t n,   [4]
        _LC_charmap_t *hdl )   [5]
{
    int len;   [6]
    int i;   [7]
 
    if (wcs == (wchar_t *)NULL || *wcs == (wchar_t)NULL)
        return(0);   [8]
 
    len = 0;   [9]
    for (i=0; wcs[i] != (wchar_t)NULL && i<n; i++) {   [10]
 
        if (wcs[i] <= 0x9f)
             len += 1;   [11]
 
        else if ((wcs[i] >= 0x0100) && (wcs[i] <= 0x015d))
             len += 1;   [12]
 
        else if ((wcs[i] >=0x015e) && (wcs[i] <= 0x303b))
             len += 2;   [13]
 
        else if ((wcs[i] >=0x303c) && (wcs[i] <= 0x5f19))
            len += 2;   [14]
 
        else if ((wcs[i] >=0x5f1a) && (wcs[i] <= 0x8df7))
            len += 2;   [15]
 
        else
            return(-1);   [16]
    }   [17]
 
    return(len);   [18]
}

  1. このメソッドに必要な定数と構造体を含むヘッダ・ファイルをインクルードします。 [例に戻る]

  2. 必要な表示幅を判定するためのアルゴリズムを記述します。

    各文字の表示幅は,文字が属する文字セットに応じて 1 カラムまたは 2 カラムのいずれかです。 表示幅は,マルチバイト形式の文字のサイズとは異なります。 たとえば,3 バイト文字には 2 つの表示カラムが必要であり,2 バイト文字には 1 つまたは 2 つの表示カラムが必要です。 [例に戻る]

  3. 表示幅情報を必要とするワイド文字列を含むバッファを,wcs でポイントします。 [例に戻る]

  4. wcs バッファの最大サイズを含む変数 n を定義します。 [例に戻る]

  5. このロケールの文字マップを解析するメソッドへのポインタを格納している構造体を,hdl でポイントします。 [例に戻る]

  6. バイトまたはカラム数で表示幅を保持する変数 len を定義します。 [例に戻る]

  7. ループ・カウンタとして使用する変数 i を定義します。 [例に戻る]

  8. wcsNULL を含んでいるか,NULL をポイントしている場合は,ゼロ (0) を返します。 [例に戻る]

  9. len をゼロ (0) に初期化します。 [例に戻る]

  10. wcs バッファ内の各ワイド文字を処理し,ワイド文字ポインタをインクリメントする for ループを開始します。 [例に戻る]

  11. 現在のワイド文字の値が 0x9f 以下であれば,len を 1 だけインクリメントします。 [例に戻る]

  12. 現在のワイド文字の値が 0x0100 から 0x015d の範囲にあれば,len を 1 だけインクリメントします。 [例に戻る]

  13. 現在のワイド文字の値が 0x015e から 0x303b の範囲にあれば,len を 2 だけインクリメントします。 [例に戻る]

  14. 現在のワイド文字の値が 0x303c から 0x5f19 の範囲にあれば,len を 2 だけインクリメントします。 [例に戻る]

  15. 現在のワイド文字の値が 0x5f1a から 0x8df7 の範囲にあれば,len を 2 だけインクリメントします。 [例に戻る]

  16. -1 を返して,文字列に無効なワイド文字が含まれていることを示します。

    この文は,文字列中の値が上記の条件をいずれも満たさない場合に実行されます。 呼び出し元の関数 wcswidth() は,ワイド文字が印字不可能な場合にも -1 を返します。 ただし,この条件は呼び出し元関数のレベルで評価されるため,このメソッドが評価する必要はありません。 [例に戻る]

  17. wcs バッファ内のワイド文字を処理する for ループを終了します。 [例に戻る]

  18. ワイド文字列を表示するのに必要なカラム数を示す len を返します。 [例に戻る]

6.3.1.11    wcwidth( ) 関数用のメソッドの作成

wcwidth() 関数は wcwidth メソッドを使用して,ワイド文字を表示するのに必要なカラム数を判定します。 一般に,このメソッドの C ソース・ファイルの名前は,_ _wcwidth_codeset.c です。 codeset は,このメソッドに対応するコードセットを示します。 例 6-20 は,ja_JP.sdeckanji ロケールで使用される wcwidth メソッドを定義するファイル,_ _wcwidth_sdeckanji.c です。

例 6-20:  ja_JP.sdeckanji ロケールのための _ _wcwidth_sdeckanji メソッド

#include <stdlib.h>   [1]
#include <wchar.h>   
#include <sys/localedef.h>   
 
/*
The algorithm for this conversion is:
 
PC <= 0x009f:                 s[0] = PC
PC >= 0x0100 and PC <=0x015d: s[0] = 0x8e
                              s[1] = PC - 0x005f
PC >= 0x015e and PC <=0x303b: s[0] = ((PC - 0x015e) >> 7) + 0x00a1
                              s[1] = ((PC - 0x015e) & 0x007f) + 0x00a1
PC >= 0x303c and PC <=0x5f19: s[0] = 0x8f
                              s[1] = ((PC - 0x303c) >> 7) + 0x00a1
                              s[2] = ((PC - 0x303c) & 0x007f) + 0x00a1
PC >= 0x5f1a and PC <=0x8df7  s[0] = ((PC - 0x5f1a) >> 7) + 0x00a1
                              s[1] = ((PC - 0x5f1a) & 0x007f) + 0x0021
 
+-----------------+-----------+-----------+-----------+
|  process code   |   s[0]    |   s[1]    |   s[2]    |
+-----------------+-----------+-----------+-----------+
| 0x0000 - 0x009f | 0x00-0x9f |    --     |    --     |
| 0x00a0 - 0x00ff |   --      |    --     |    --     |
| 0x0100 - 0x015d | 0x8e      | 0xa1-0xfe |    --     | JIS X0201 RH
| 0x015e - 0x303b | 0xa1-0xfe | 0xa1-0xfe |    --     | JIS X0208
| 0x303c - 0x5f19 | 0x8f      | 0xa1-0xfe | 0xa1-0xfe | JIS X0212
| 0x5f1a - 0x8df7 | 0xa1-0xfe | 0x21-0xfe |    --     | UDC
+-----------------+-----------+-----------+-----------+
*/   [2]
 
int _ _wcwidth_sdeckanji(
        wint_t wc,   [3]
        _LC_charmap_t *hdl )   [4]
{
 
    if (wc == 0)
        return(0);   [5]
 
    if (wc <= 0x9f)
        return(1);   [6]
 
    else if ((wc >= 0x0100) && (wc <= 0x015d))
        return(1);   [7]
 
    else if ((wc >=0x015e) && (wc <= 0x303b))
        return(2);   [8]
 
    else if ((wc >=0x303c) && (wc <= 0x5f19))
        return(2);   [9]
 
    else if ((wc >=0x5f1a) && (wc <= 0x8df7))
        return(2);   [10]
 
        return(-1);   [11]
}

  1. このメソッドに必要な定数と構造体を含むヘッダ・ファイルをインクルードします。 [例に戻る]

  2. 必要な表示幅を判定するためのアルゴリズムを記述します。

    各文字の表示幅は,文字が属する文字セットに応じて 1 カラムと 2 カラムのいずれかです。 表示幅は,マルチバイト形式の文字のサイズとは異なります。 たとえば,3 バイト文字には 2 つの表示カラムが必要であり,2 バイト文字には 1 つまたは 2 つの表示カラムが必要です。 [例に戻る]

  3. 表示幅情報を必要とするワイド文字を含む wc 変数を定義します。 [例に戻る]

  4. このロケールの文字マップを解析するメソッドへのポインタを格納している構造体を,hdl でポイントします。 [例に戻る]

  5. ワイド文字バッファが空の場合,ゼロ (0) を返します。 [例に戻る]

  6. ワイド文字値が 0x009f 以下の場合,1 を返します。 [例に戻る]

  7. ワイド文字値が 0x0100 から 0x015d の範囲にあれば,1 を返します。 [例に戻る]

  8. ワイド文字値が 0x015e から 0x303b の範囲にあれば,2 を返します。 [例に戻る]

  9. ワイド文字値が 0x303c から 0x5f19 の範囲にあれば,2 を返します。 [例に戻る]

  10. ワイド文字値が 0x5f1a から 0x8df7 の範囲にあれば,2 を返します。 [例に戻る]

  11. ワイド文字の値が無効な場合,-1 を返します。

    呼び出し元の関数 wcwidth() は,ワイド文字が印字不可能な場合にも -1 を返します。 ただし,この条件は呼び出し元関数のレベルで評価されるため,このメソッドが評価する必要はありません。 [例に戻る]

6.3.2    オプションのメソッド

ロケールには,必須メソッド (6.3.1 項 を参照) 以外のメソッドも含めることができます。 メソッド指定がないために省略時のメソッドが適用された場合,そのメソッドはオプションだと見なされます。 つまり,ロケールでメソッドを使用するが,特定のロケール・カテゴリに関連する関数や,その他のロケール関連の関数用のメソッドを用意していない場合,localedef コマンドは,シングルバイト文字とマルチバイト文字の両方の処理コードを扱う省略時のメソッドを適用します。

オプションのメソッドを作成するためには,C ライブラリ・ルーチンの内部インタフェースについての詳細情報が必要になります。 この情報はベンダ独自の情報であり,変更される場合があります。 したがって,この項のオプション・メソッドの説明は,必須メソッドの説明と比べて不完全です。

まれなケースとして,オプションのメソッドをロケールに含めなければならないことがあります。 詳細は,最寄りの技術サポートにお問い合わせください。

以下に,オプションのメソッドを示します。

6.3.3    ロケールで使用するシェアード・ライブラリの作成

例 6-21 に,コンパイラとリンカのコマンド行を示します。 これらのコマンド行は,ja_JP.sdeckanji ロケールで使用されるシェアード・ライブラリをメソッドのソース・ファイルから作成する際に必要です。

例 6-21:  ja_JP.sdeckanji ロケールで使用されるメソッドのライブラリの作成

cc -std0 -c \
   _ _mblen_sdeckanji.c _ _mbstopcs_sdeckanji.c \
   _ _mbstowcs_sdeckanji.c _ _mbtopc_sdeckanji.c \
   _ _mbtowc_sdeckanji.c _ _pcstombs_sdeckanji.c \
   _ _pctomb_sdeckanji.c _ _wcstombs_sdeckanji.c \
   _ _wcswidth_sdeckanji.c _ _wctomb_sdeckanji.c \
   _ _wcwidth_sdeckanji.c
 
ld -shared -set_version osf.1 -soname libsdeckanji.so -shared \
   -no_archive -o libsdeckanji.so \
   _ _mblen_sdeckanji.o _ _mbstopcs_sdeckanji.o \
   _ _mbstowcs_sdeckanji.o _ _mbtopc_sdeckanji.o \
   _ _mbtowc_sdeckanji.o _ _pcstombs_sdeckanji.o _ _pctomb_sdeckanji.o \
   _ _wcstombs_sdeckanji.o _ _wcswidth_sdeckanji.o _ _wctomb_sdeckanji.o \
   _ _wcwidth_sdeckanji.o \
   -lc

シェアード・ライブラリについての詳細は, cc(1) および ld(1) のリファレンス・ページを参照してください。

6.3.4    ロケールに対応した methods ファイルの作成

methods ファイルには,ロケールで使用されるメソッド・シェアード・ライブラリで定義されている各関数のエントリが含まれています。 関数が実行する操作は,メソッド・キーワードで識別されます。 メソッド・キーワードの後には,引用符で囲まれた関数の名前と,その関数を含むシェアード・ライブラリのパスが続きます。

例 6-22 に,ja_JP.sdeckanji ロケールで使用されるメソッドのための methods ファイルのセクションを示します。 C ライブラリ・インタフェースの指定を変更したいときは,必須のメソッドのリストを定義する必要があるため,この例で示すように,methods ファイルには個々の必須メソッドのエントリが含まれていなければなりません。 ja_JP.sdeckanji ロケールではすべてのオプション・メソッドに対して,省略時の実装が使用されています。 そのため,この例にはオプション・メソッドのエントリは含まれていません。

例 6-22:  ja_JP.sdeckanji ロケールのための methods ファイル

# sdeckanji.m   [1]
# <method_keyword> "<entry>" "<package>" "<library_path>"   [1]
 
METHODS    [2]
 
_ _mbstopcs "_ _mbstopcs_sdeckanji" "libsdeckanji.so" \
"/usr/shlib/libsdeckanji.so"  [3]
_ _mbtopc   "_ _mbtopc_sdeckanji"   "libsdeckanji.so" \
"/usr/shlib/libsdeckanji.so"  [3]
_ _pcstombs "_ _pcstombs_sdeckanji" "libsdeckanji.so" \
"/usr/shlib/libsdeckanji.so"  [3]
_ _pctomb   "_ _pctomb_sdeckanji"   "libsdeckanji.so" \
"/usr/shlib/libsdeckanji.so"  [3]
mblen      "_ _mblen_sdeckanji"    "libsdeckanji.so" \
"/usr/shlib/libsdeckanji.so"  [3]
mbstowcs   "_ _mbstowcs_sdeckanji" "libsdeckanji.so" \
"/usr/shlib/libsdeckanji.so"  [3]
mbtowc     "_ _mbtowc_sdeckanji"   "libsdeckanji.so" \
"/usr/shlib/libsdeckanji.so"  [3]
wcstombs   "_ _wcstombs_sdeckanji" "libsdeckanji.so" \
"/usr/shlib/libsdeckanji.so"  [3]
wcswidth   "_ _wcswidth_sdeckanji" "libsdeckanji.so" \
"/usr/shlib/libsdeckanji.so"  [3]
wctomb     "_ _wctomb_sdeckanji"   "libsdeckanji.so" \
"/usr/shlib/libsdeckanji.so"  [3]
wcwidth    "_ _wcwidth_sdeckanji"  "libsdeckanji.so" \
"/usr/shlib/libsdeckanji.so"  [3]
 
END METHODS    [4]

  1. コメント行

    これらの行は,methods ファイルの名前と,メソッド・エントリのフォーマットを示します。 フォーマット中の <package> フィールドは無視されますが,ライブラリ・パスを指定するためには,何らかの文字列をこのフィールドに設定しておかなければなりません。 [例に戻る]

  2. メソッド・エントリの開始を示すヘッダ [例に戻る]

  3. 必須メソッドのエントリ [例に戻る]

  4. メソッド・エントリの終わりを示すトレイラ [例に戻る]

methods ファイルのエントリの詳細については, localedef(1) のリファレンス・ページを参照してください。

6.4    ロケールの作成とテスト

localedef コマンドを使用して,ソース・ファイルからロケールを作成します。 例 6-23 は,この章のほとんどの例で使用されているフランス語ロケールを作成するためのコマンド行です。 この例では,すべてのソース・ファイルがユーザの省略時のディレクトリに置かれており,作成されたロケールもそのディレクトリに置かれるものとします。

例 6-23:  fr_FR.ISO8859-1@example ロケールの作成

% localedef -f ISO8859-1.cmap \    [1]
-i fr_FR.ISO8859-1.src \   [2]
fr_FR.ISO8859-1@example   [3]

  1. -f オプションは,文字マップ・ソース・ファイルを指定します。 [例に戻る]

  2. -i オプションは,ロケール定義ソース・ファイルを指定します。 [例に戻る]

  3. コマンドに指定する最後の引数は,ロケールの名前です。 [例に戻る]

ロケールをテストする場合,特に,そのロケールがシステム上にインストールされている標準ロケールに類似している場合は,そのロケール名に拡張子を付けます。 アットマーク (@) 拡張子を付加した名前を使用することにより,言語,地域,およびコードセットに対して標準の文字列を指定でき,またテスト・ロケールを一意に識別できます。 この設定は,後でテスト・ロケールを,他のロケールが配置されているディレクトリ /usr/lib/nls/loc に移動する際に重要になります。

例 6-23 には,localedef コマンドの 1 つの形式と,2,3 のオプションだけを示します。 localedef(1) のリファレンス・ページにこのコマンドの詳細な説明があります。

以下に,重要な規則とオプションの要約を示します。

省略時の設定では,ロケールは /usr/lib/nls/loc ディレクトリになければなりません。 テスト・ロケールを /usr/lib/nls/loc ディレクトリに移動する前にテストしたい場合は,LOCPATH 変数を設定し,ロケールが置かれているディレクトリを指定します。 その後で LANG 環境変数を新しいロケールに設定すれば,コマンドやアプリケーションを使用してロケールを対話形式でテストできます。

例 6-24 は,date コマンドを使用して,日付と時刻の形式をテストします。

例 6-24:  LOCPATH 変数の設定とロケールのテスト

% setenv LOCPATH ~harry/locales
% setenv LANG fr_FR.ISO8859-1@example
% date
ven 23 avr 13:43:05 EDT 1999

注意

LOCPATH 変数は,X/Open の UNIX 標準で規定されている仕様の拡張であり,この仕様に準拠するすべてのシステムで認識されるわけではありません。

プログラムによっては,標準ロケールの名前とまったく同じ名前を持つシステム・ディレクトリにインストールされたサポート・ファイルが使用されています。 その場合,アプリケーション・ソフトウェアやシステム・ソフトウェア,あるいはその両方は,LANG 環境変数の値を使用して,サポート・ファイルが置かれているロケール固有のディレクトリを決定します。 LANG または LC_ALL 環境変数にロケール・ファイル名を直接指定した場合,アットマーク (@) サフィックスが付加されているロケール・ファイル名は,アプリケーションによっては無効な検索パスとなることがあります。

LANG 環境変数に標準のロケール名を指定し,ロケールのカテゴリ変数に異なるロケール名を指定することにより,この問題を回避する方法を次の例に示します。 指定しなければならないカテゴリ変数は,その適用範囲が作成したロケールと元のロケール間で異なっているものだけです。

% setenv LANG fr_FR.ISO8859-1
% setenv LC_CTYPE fr_FR.ISO8859-1@example
% setenv LC_COLLATE fr_FR.ISO8859-1@example

.
.
.
% setenv LC_TIME fr_FR.ISO8859-1@example