18 확장된 문자들

다수의 언어들이 char의 형태로 문자들을 표현할 수 없다. 일본어와 중국어가 이와 가장 유사한 예이다. GNU C 라이브러리는 확장된 문자 집합들을 취급하기 위해서 두 개의 메커니즘을 지원한다: 다중 바이트 문자들과 와이드 캐릭터(wide characters) 이 장은 이들 메커니즘과 그들을 변환하는 함수들을 어떻게 사용할 것인지를 설명한다. 이 장에 있는 함수들의 동작은 문자 분류 LC_CTYPE 범주로 나타낸 현재의 지역에 의해 영향을 받는다; 19. 3절 [Locale Categories] 참조. 지역을 선택하는 것은 다중 바이트 코드가 사용되는지, 와이드 캐릭터 코드가 사용되는지를 선택하는 것이다.


18. 1 확장된 문자들에 대한 소개

당신은 두 가지 방법중에 하나로 확장 문자들을 나타낼 수 있다.

다중 바이트 문자들은 char 오브젝트의 배열인 원래의 문자열에 포함 될 수 있다. 이것의 이득은 많은 프로그램들과 운영제체가 아무런 변환 없이, 원래의 ASCII 문자들 사이에 흩어져 있는 다중 바이트 문자들을 다룰 수 있다는 것이다.

와이트 캐릭터는 더 많은 비트들을 점유한다는 것을 제외하고는 원래의 문자들과 같다. 와이트 캐릭터 데이터 타입, wchar_t는 ASCII 코드들 은 물론 확장된 문자 코드들을 다루기 위해서 충분히 큰 범위를 갖는다. 와이드 캐릭터의 이득은 각 문자들이 원래의 ASCII 문자들처럼 단일한 데이터 오브젝트라는 것이다. 하지만 몇 개의 불편이 있다.

어떤 현존하는 프로그램이 와이트 캐릭터를 사용하도록 하려면 갱신되고 재컴파일 되어야만 한다.

와이드 캐릭터의 파일들은 보통의 문자들을 제외하고는 프로그램에 의해 읽혀질 수 없다.

일반적으로, 당신은 파일에 텍스트를 읽거나 쓰기처럼, 외부 프로그램 인터페이스의 부분으로 다중 바이트 문자 표현을 사용한다. 그렇지만, 일정한 표현은 편집 명령들을 가장 쉽게 구현하도록 하기 때문에, wchar_t 오브젝트의 배열로 확장된 문자들을 포함하는 문자열을 내부적인 처리를 수행하는 것이 보통은 더 쉽다. 만일 당신이 파일에서는 다중 바이트 문자들을 사용하고 내부 동작에는 와이트 캐릭터를 사용한다면, 당신은 데이터를 읽거나 쓸 때, 그들 사이에 변환을 할 필요가 있다. 만일 당신의 시스템이 확장된 문자들을 지원한다면, 다중 바이트 문자들과 와이드 캐릭터 문자들을 둘다 지원한다. 라이브러리에 포함된 함수를 통해 당신은 그 두 표현 사이의 변환을 수행할 수 있다. 이들 함수들은 이 장에 설명되어 있다.


18. 2 지역과 확장된 문자

컴퓨터 시스템은 한 개의 다중 바이트 문자 코드보다 많이, 그리고 한 개의 와이트 캐릭터 코드보다는 많이 지원할 수 있다. 사용자는 문자 분류에 있는 현재의 지역코드를 선택함으로써 제어한다( 19장 [Locals] 참조. ) 각 지역은 특정한 다중 바이트 문자 코드와 특정한 와이드 캐럭터 코드를 정한다. 지역의 선택은 라이브러리에 있는 변환 함수들의 동작에 영향을 끼친다. 어떤 지역들에서는 와이드캐릭터나 혹은 다중 바이트 문자들중 하나만 지원한다. 이들의 지역에서, 라이브러리의 변환 함수들은 비록 하찮은 일들이지만 여전히 작업한다.

만일 당신이 문자분류를 위해서 새로운 지역을 선택한다면, 그들 함수들에 의하여 유지되고 있던 내부 shift 상황은 혼란하게 될 수도 있다, 그러므로 당신이 문자열을 처리하는 도중에 지역을 변경하는 것은 좋은 생각이 아니다.


18. 3 다중 바이트 문자들

보통의 ASCII 코드에서 연속된 문자들은 바이트가 연속하고 있음을 의미하고 각 문자는 한 바이트이다. 이것은 매우 간단하지만, 오직 256개의 독립문자들만을 허용한다.

다중 바이트 문자 코드에서도, 연속된 문자들은 바이트가 연속하고 있음을 의미하지만, 각 문자는 한 개 또는 더 많은 연속적인 바이트들을 점유하고 있을 것이다.

다중 바이트 코드를 설계하는 많은 다른 방법들이 있다; 다른 시스템들은 다른 코드들을 사용한다. 특정한 코드를 설계하기 위해서는 특정한 문자를 대표하는 한 문자를 몇바이트(기본 바이트 시퀀스)로 나타낼 것인지를 정해야 한다. 컴퓨터에서 한 코드는 실제로 기본 시퀀스들의 제한된 개수를 가져야만 하고, 그들 중 어떤 것도 이것보다 길어서는 안된다.

이들 시퀀스들이 모두 같은 길이를 가질 필요는 없다. 실제로, 그들 중 대부분은 단지 한바이트 길이를 가진다. 0에서 0177의 범위에 있는 기본 ASCII 문자들이 중요하기 때문에, 그래서 그들을 모두 다중 바이트 코드로 나타낸다. 0에서 0177의 범위에 있는 한 바이트는 그 자체로 한 문자를 표현하고 있다. 한 바이트보다 긴 문자들은 0200에서 0377 범위에 있는 한바이트로 항상 시작되어야만 한다. 바이트 값 0은 문자열을 끝내기 위해서 사용될 수 있고, 종종 ASCII 문자들의 문자열에 사용된다.

단일한 문자들을 표현하는 기본 바이트 시퀀스를 정하는 것은 자동적으 로긴 바이트 시퀀스에 의미를 주게된다. 예를 들어, 두 개의 바이트 시퀀스 0205 049가 그리스 문자 알파를 의미한다면, 0205 049 065는 알파 뒤에 'A'(ASCII 코드 065)가 따라옴을 나타내고, 0205 049 0205 049는 일렬로 두 개의 알파가 있음을 나타낸다.

만일 어느 바이트 시퀀스가 여러 가지의 의미로 해석될 수 있다면 그 다중 바이트 코드는 좋은 것이 아니다. 시스템에서 코드는 실제로 모두 단일한 의미로 사용된다. 대부분의 코드에서 어떤 바이트들의 시퀀스는 문자로써 아무런 의미를 가지지 않는다. 그들을 유용하지 않다라고 한다.

가장 간단하고 가능한 다중 바이트 코드에 대한 한가지 :
단일한 바이트들로 구성된 기본 시퀀스
특정한 코드는 전혀 다중 바이트 코드를 사용하지 않는다. 그것은 유용하지 않은 시퀀스가 없다. 그러나 오직 256개의 문자들만을 취급할 수 있다. 이곳에 9376개의 다른 문자들을 다룰 수 있는 다른 가능한 코드가 있다.
기본 시퀀스의 구성은. 0에서 0237은 단일한 바이트값.
0240에서 0377 범위에 있는 값들을 가진 바이트 두 개로 두 개-바이트 시퀀스
이 코드 또는 이와 유사한 것들은 일본어 문자들을 표현하기 위해서 어떤 시스템에서 사용된다. 유용하지 않은 시퀀스는 0240부터 0377의 범위에 있는 연속된 바이트들의 개수가 홀수라면 유용하지 않은 것이다.
여기에 더 많은 확장된 문자들을 다룰 수 있는 다중 바이트 코드가 있다. 이것은 실제로 거의 3000만 까지 된다.
기본 시퀀스 구성은. 0에서 0177의 범위로는 단일한 바이트.
네 개의 바이트로 구성된 시퀀스에서 첫 번째 바이트는 0200에서 0237의 범위를 갖고, 나머지는 0240에서 0377의 범위를 갖는다.
이 코드에서, 어느 시퀀스가 0240에서 0377의 범위의 한바이트로 시작하지 않으면 유용하지 않다. 그리고 마지막 바이트를 제거함으로써 어떤 이득을 갖거나, 한 개의 유용한 문자를 대표하는 바이트들을 가지고 결코 다른 유용한 문자을 만들어낼 수 없는 문자코드가 있다. (이런 특성은 당신이 특정한 문자들이 있는 문자열을 탐색하고자 할 때 편리하다. )
기본 시퀀스 구성은. 0에서 0177의 범위로는 단일한 바이트.
두 개-바이트 시퀀스에서 첫 번째 바이트는 0200에서 0207의 범위를 갖고, 두 번째는 0240에서 0377의 범위를 갖는다.
세 개-바이트 시퀀스에서 첫 번째 바이트는 0210에서 0217의 범위를 갖고, 나머지 바이트들은 0240에서 0377의 범위를 갖는다.
네 개-바이트 시퀀스에서 첫 번째 바이트는 0220에서 0227의 범위를 갖고, 나머지 바이트들은 0240에서 0377의 범위를 갖는다.
이 코드로 구성된 유용한 시퀀스들은 길다; 유용한 시퀀스의 예로 0240 과 0220 0300 065가 있다. 가능한 다중 바이트 코드들의 개수는 셀수가 없다. 그러나 주어진 컴퓨터 시스템은 고작 몇 개의 다른 코드들을 지원할 것이다. ( 그들 코드들중 하나는 수천 개의 다른 문자들을 허용할 것이다. ) 다른 컴퓨터 시스템은 한 개의 완전한 다른 코드를 지원할 것이다. 이 장에서 설명된 라이브러리도구들은 당신의 프로그램에서 그들을 알 필요가 없이 특정 컴퓨터 시스템의 다중 바이트 코드에 대한 세심한 지식들로 꾸려져있기 때문에 유용하다.

당신이 현재 선택된 다중 바이트 코드에서 한문자를 표현하는 바이트들의 최대 가능 개수를 찾기 위해서는 표준 매크로 MB_CUR_MAX를 사용하고, 당신의 컴퓨터에서 지원되는 어느 다중 바이트 코드를 위한 최대 개수를 위해서는 MB_LEN_MAX를 사용하라.

매크로 : int MB__LEN__MAX

이것은 어느 지원된 지역을위한 한 다중 바이트 문자의최대 길이이다. `limits. h'에 정의되어 있다.

매크로 : int MB__CUR__MAX

이 매크로는 현재의 지역에서 한 다중 바이트 문자를 표현하는 최대 바이트의 개수를 양의 정수표현으로(가능하게비-상수)확장한다. 그 값은 결코 MB_LEN_MAX보다 길 수가 없다.
MB_CUR_MAX는 `stdlib. h'에 정의되어 있다.

보통, 특정 문자 코드 안에 있는 각각의 기본 시퀀스는 한 문자를 나타낸다. 같은 다중 바이트 문자 코드들은 한 shift 상황을 갖는다; 어떤 코드들에서는, 쉬프트 시퀀스라고 불리는 다른 쉬프트 상황으로 변경하고, 어떤 또는, 모든 기본 시퀀스들의 의미는 현재의 쉬프트 상황에 따른다. 실제로, 기본 시퀀스의 집합은 심지어 현재의 쉬프트 상황에 의존하여 달라질 것이다. 이 코드의 종류를 다루는 것에 대한 정보는 18. 9절 [Shift State] 를 참조하라.

포함된 다중 바이트 문자열을 그들에 대해서 알지 못하는 함수에게 주려 시도할 때 무슨 일이 일어날것인가? 보통, 함수는 바이트들의 시퀀스로 문자열을 취급하고, 특별한 어떤 바이트값으로 해석한다; 모든 다른 바이트값들은 "보통"이다. 다중 바이트의 길이를 가진 문자가 어느 특별한 바이트 값들을 포함하지 않으면, 그 함수는 몇 개의 보통 문자처럼 그들을 취급할 것이다.

예를 들어, 만일 당신이 파일의 이름으로 다중 바이트 문자들을 사용한다면 무엇이 발생할지를 생각해보자. open과 unlink와 같은 함수들은 특별한 값으로 `/'와 함께, 연속된 바이트들의 시퀀스로 그 이름을 취급하여 함수이름을 가지고 동작한다. 어느 다른 바이트 값들이 시퀀스로 복사되거나 비교되면, 모든 바이트값들은 유사하게 취급된다. 그러면, 당신은 연속된 바이트들로 구성된 파일이름으로 생각하거나, 또는 다중 바이트 문자들이 포함된 문자열로 생각할 것이다; 그 같은 동작은 `/'를 포함하지 않은 다중 바이트 문자에도 같은 방법중 하나로 이해될 것이다.


18. 4 와이드 캐릭터에 대한 안내

와이드 캐릭터는 다중 바이트 문자보다는 많이 간단하다. 그들은 8비트 이상을 가지고 문자들을 표현하기 때문에, 256개보다는 많은 문자들을 표현할 수 있다. 와이드 캐릭터 데이터 타입, wchar_t는 규격화된 ASCII 코드는 물론 확장된 문자 코드들을 저장하기에 충분한 범위를 갖고 있다. 와이드 캐럭터의 사용으로 갖는 이득은 각각의 문자가 보통의 ASCII 문자들처럼, 단일한 데이터 오브젝트라는 것이다. 그렇지만 와이드 캐럭터들은 몇 가지 불편함을 내포하고 있다.

프로그램이 와이드 캐릭터를 사용하려면 수정되고 재컴파일 되어야만 한다.

와이드 캐릭터로 이루어진 파일들은 보통의 문자들을 제외하고는 프로그램에 의해 읽혀질 수 없다.

와이드 캐럭터 값, 0에서 0177 사이는 항상 ASCII 문자 코드와 동일하다. 와이드 캐럭터값 0은 , 0의 값을 가진 단일한 바이트가 보통의 문자들로 이루어진 문자열을 종료하는데 사용되는 것처럼, 와이드 캐릭터들로 이루어진 문자열을 종료하는데 사용된다.

데이터 타입 : wchar__t

이것은 지원된 지역들에서 사용되는 확장된 문자 값들을 모두 표현하기에 충분히 큰 범위를 가진 정수형으로 "와이드 캐럭터"의 데이터형이다. 지역에 대한 정보는 19장 [Locales] 를 참조하라. 이 형은 헤더파일 'stddef. h'에 정의되어 있다.

만일 당신의 시스템이 확장된 문자들을 지원한다면, 각각의 확장된 문자들은 한 개의 와이드 캐릭터 코드와 그에 해당하는 다중 바이트 기본 시퀀스를 둘다 갖는다.


18. 5 확장된 문자열의 변환

mbstowcs함수는 다중 바이트 문자들로 이루어진 문자열을 와이드 캐릭터 배열로 변환한다. wcstombs 함수는 그 역변환을 한다. 이들 함수들은 헤더파일 'stdlib. h'에 선언되어 있다.

대부분의 프로그램에서, 이들 함수들은 와이드 문자열과 다중 바이트 문자열 사이의 변환을 위해서 당신이 필요한 것들이다. 그러나 그들은 제한들을 갖는다. 만일 당신의 데이터가 널문자로 끝나지 않거나, 동시에 모두 코어 안에 있지 않다면, 당신은 아마도 한 번에 한 문자를 변환하는 저-수준 변환함수를 사용해야 할 것이다. 18. 7절 [Converting One Char] 참조.

함수 : size_t mbstowcs (wchar_t *wstring, const char *string, size_t size)

mbstowcs("다중 바이트 문자열을 와이드 캐릭터 문자열로")함수는 널 종료 문자로 끝나는 다중 바이트 문자들로 이루어진 문자열을 와이드 캐릭터 코드들의 배열로 변환한다. 그 배열은 wstring에서 시작하는 배열에 와이드 문자들을 저장하는데, 그 배열의 크기가 size보다는 클 수 없다. size의 크기에는 널 종료문자가 포함되지 않았다, 그래서 만일 size가 이 함수의 실행 결과인 문자열에서 와이드 캐럭터의 실제 개수보다 작았다면, 널 종료문자는 저장되지 않게된다.
문자열을 가지고 문자들을 변환하는 것은 초기 쉬프트 상황으로 시작한다. 만일 유용하지 않은 다중 바이트 문자 시퀀스가 발견되면, 이 함수는 -1의 값을 반환하고, 그렇지 않다면, 배열 wstring에 저장 된 와이드 캐럭터의 개수를 반환한다. 이 개수는 널 종료문자가 포함되지 않은 것으로 만일 개수가 size보다 작으면 널 종료문자가 저장된다.
다음은 결과를 저장하기에 충분한 공간을 할당해서, 다중 바이트 문자열을 어떻게 변환하는지를 보여주는 예제이다.
wchar_t *
mbstowcs_alloc (const char *string)
{
size_t size = strlen (string) + 1;
wchar_t *buf = xmalloc (size * sizeof (wchar_t));
size = mbstowcs (buf, string, size);
if (size == (size_t) -1)
return NULL;
buf = xrealloc (buf, (size + 1) * sizeof (wchar_t));
return buf;
}

함수 : size_t wcstombs (char *string, const wchar_t wstring, size_t size)

wcstombs("와이드 캐럭터 문자열을 다중 바이트 문자열로")함수는 널 종료문자로 끝나는 와이드 캐럭터 배열 wstring을 다중 바이트 문자열로 변환하는 함수로, string에서 시작하여 size 바이트보다 크지않게 저장하는데, 그 size의 크기가 변환된 문자열을 저장하기에 충분하다면 널 종료문자도 저장된다. 문자들의 변환은 초기 쉬프트 상황으로 시작한다.
널 종료문자는 size의 크기에 포함되지 않기 때문에, 만일 size의 크기가 wstring에서 필요로 하는 바이트의 개수와 같거나 더 적다면, 널 종료문자는 저장되지 않는다. 만일 유용한 다중 바이트 문자에 해당되지 않은 코드가 발견되면, 이 함수는 -1의 값을 반환한다. 그렇지 않다면, 반환값은 배열 string에 저장된 바이트들의 개수이다. 이 개수는 널 종료문자가 포함되지 않은 것으로, 그 개수가 size 보다 적다면 널 종료문자가 저장된 것이다.


18. 6 다중 바이트 문자 길이

이 절은 다중 바이트 문자들로 이루어진 문자열을 한 번에 한문자씩 어떻게 조사하는지를 설명하고 있다. 이런 일을 하는데 따르는 어려움은 각각의 한 문자가 몇 개의 바이트로 이루어졌는지를 알아야하는 것이다. 당신은 이것을 판단하는데 mblen 함수를 사용할 수 있다.

함수 : int mblen (const char *string, size_t size)

널 종료문자가 없는 문자열을 가지고 mblen함수를 사용하면, string에서 시작하여 다중 바이트 문자를 구성하는 바이트의 개수를 반환하는데, size바이트 만큼만 시험한다. ( 여기서 size는 당신이 가지고 있는 데이터의 바이트의 개수로 공급한다. ) mblen의 반환값은 세 가지 가능성으로 구분된다: string의 첫 번째 size 바이트들이 유용한 문자로 시작한는지, 유용하지 않은 바이트 시퀀스로 시작하거나 단지 한 문자의 일부인지, 비어있는 문자열인지. 유용한 다중 바이트 문자에서는, mblen은 그 문자(적어도 한 개 이상이고, 결코 size보다 커서는 안된다)의 바이트들의 개수를 반환한다. 유용하지 않은 바이트 시퀀스에서는, mblen은 -1을 반환한다. 비어있는 문자열에서는, 0을 반환한다.
만일 다중 바이트 문자 코드가 쉬프트 문자들을 사용한다면, mblen은 그것을 조사해서 쉬프트 상황을 갱신하고 유지한다. 만일 당신이 string으로 널 포인터를 사용하여 mblen을 호출한다면, 표준 초기값으로 쉬프트 상황을 초기화한다. 그것은 만일 실제로 사용된 다중 바이트 문자 코드가 쉬프트 상황을 갖고 있다면 0이 아닌 값을 반환한다. 18. 9절 [Shift State] 를 참조하라. mblen 함수는 `stdlib. h'에 선언되어 있다.


18. 7 일 대 일로 확장된 문자들의 변환

당신은 mbtowc 함수를 사용해서 다중 바이트 문자를 한번에 한자씩 와이드 캐릭터로 변환할 수 있다. wctomb 함수는 그 반대 작용을 한다. 이들 함수들은 `stdlib. h'에 선언되어 있다.

함수 : int mbtowc (wchar_t *result, const char *string, size_t size)

mbtowc( 다중 바이트 문자를 와이드 캐릭터로 ) 함수는 널 종료 문자가 없는 문자열을 가지고 호출했을 때, string의 처음에 있는 첫 번째 다중 바이트 문자를 그에 해당하는 와이드 캐릭터 코드로 변환한다. 그것은 결과를 *result에 저장한다.
mbtowc는 size 바이트 만큼만 시험한다. ( size는 당신이 가지고 있는 데이터의 바이트의 개수로 공급한다. ) 널 종료문자가 없는 string으로 호출된 mbtowc는 세 가지 가능성으로 구분된다: string에 있는 첫 번째 size 바이트들이 유용한 다중 바이트 문자로 시작하는지, 그들이 유용하지 않는 바이트 시퀀스로 시작하거나 단지 한 문자의 일부분인지, 또는 string이 비어있는( 한 개의 널 문자) 문자열을 가리키는지. 유용한 다중 바이트 문자라면, mbtowc 는 그것은 와이드 캐릭터로 변환하여 *result에 저장하고, 그 문자의 바이트 개수를 반환한다 ( 적어도 한 개 이상이고, 결코 size보다 커서는 안된다. ). 유용하지 않은 바이트 시퀀스라면, mbtowc는 -1을 반환한다. 비어있는 문자열이라면, 0을 반환하고, 또한 *result에도 0을 저장한다.
만일 다중 바이트 문자 코드가 쉬프트 상황을 사용한다면, mbtowc는 그것을 검사하여 쉬프트 상황을 유지하고 갱신한다. 만일 당신이 string에 널 포인터를 사용하여 mbtowc를 호출하면, 그것은 표준 초기값으로 쉬프트 상황을 초기화한다. 그것은 또한 만일 사용하고 있는 다중 바이트 코드가 쉬프트 상황을 갖고 있다면 0이 아닌 값을 반환한다. 18. 9절 [Shift State] 참조.

함수 : int wctomb (char *string, wchar_t wchar)

wctomb("와이드 캐릭터를 다중 바이트로") 함수는 와이드 캐럭터 코드 wchar을 그에 해당하는 다중 바이트 시퀀스로 변환하고, 그 결과를 string의 주소에서 시작하는 바이트들에 저장한다. 아무리 많아도 MB_CUR_MAX 문자들이 저장된다.
널 종료문자가 없는 문자열을 가지고 호출된 wctomb 함수는 세 가지 가능성으로 구분한다: 유용한 와이드 캐릭터 코드( 다중 바이트 문자로 변환될 수 있는 것. ), 유용하지 않은 코드, 그리고 0. 유용한 코드가 주어진 wctomb는 그것은 다중 바이트 문자로 변환하고 string을 시작으로 바이트들을 저장한다. 그리고 그것은 그 문자의 바이트들의 개수를 반환한다( 적어도 한 개 이상하고, 결코 size보다 커서는 안된다. ).
만일 wchar이 유용하지 않은 와이드 캐릭터 코드라면, wctomb는 -1을 반환한다. 만일 wchar이 0이라면, 그것은 0을 반환하고, 또한 *string에도 0을 저장한다.
만일 다중 바이트 문자 코드가 쉬프트 문자들을 사용한다면, wctomb는 그것을 조사해서 쉬프트 상황을 갱신하고 유지한다. 만일 당신이 string으로 널 포인터를 사용해서 wctomb를 호출한다면, 표준 초기값으로 쉬프트 상황을 초기화한다. 만일 사용하고 있는 다중 바이트 문자 코드가 실제로 쉬프트 상황을 갖는다면 0이 아닌 값을 반환한다. 18. 9절 [Shift State] 참조.
wchar에 0을 넣고, string이 null이 아닌 것을 가지고 이 함수를 호출하면, 다중 바이트 문자 0을 저장하고 0을 반환하는것은 물론이고 저장된 쉬프트 상황을 다시 초기화하는 부작용을 갖는다.


18. 8 문자 대 문자 변환의 예제

기술자 input 으로부터 다중 바이트 문자 텍스트를 읽어서 그에 해당하는 와이드 캐럭터들을 기술자 output에 쓰는 예제 프로그램이다. 우리가 이 예제에서 일대일로 문자들을 변환하려한 것은 mbstowcs 함수가 널 문자가 있다면 변환을 계속하지 않고, 읽어들인 많은 입력중에 부분적으로 유용하지 않은 문자가 있다면 이것에 완전하게 대처할 수 없기 때문이다.

int
file_mbstowcs (int input, int output)
{
char buffer[BUFSIZ + MB_LEN_MAX];
int filled = 0;
int eof = 0;
while (!eof)
{
int nread;
int nwrite;
char *inp = buffer;
wchar_t outbuf[BUFSIZ];
wchar_t *outp = outbuf;
/* 입력 파일로부터 버퍼를 채운다. */
nread = read (input, buffer + filled, BUFSIZ);
if (nread < 0) {
perror ("read");
return 0;
}
/* 만일 파일의 끝에 도달하면, 더 이상 읽지 않도록 기록하라*/
if (nread == 0)
eof = 1;
/* filled는 버퍼에 있는 바이트의 개수이다. */
filled += nread;
/* 그들 바이트들을 우리가 할 수 있는 한 많이 와이드 캐릭터로 변환하라. */
while (1)
{
int thislen = mbtowc (outp, inp, filled);
/* 유용하지 않은 문자에서 변환을 멈춰라; 이것은 유용한 문자의 단지 첫 번째 부분을 읽었음을 의미한다. */
if (thislen == -1)
break;
/* 널 문자를 다른 문자처럼 취급하라, 그러나 또한 쉬프트 상황을 재설정하라. */
if (thislen == 0) {
thislen = 1;
mbtowc (NULL, NULL, 0);
}
/* 이 문자를 지나서 진행하라. */
inp += thislen;
filled -= thislen;
outp++;
}
/* 우리가 만들었던 와이드 캐럭터들을 기록하라 */
nwrite = write (output, outbuf, (outp - outbuf) * sizeof (wchar_t));
if (nwrite < 0)
{
perror ("write");
return 0;
}
/* 만일 우리가 실제 유용하지 않은 문자를 가졌는지 보자. */
if((eof && filled > 0) || filled >= MB_CUR_MAX) {
error ("invalid multibyte character");
return 0;
}
/* 만일 어느 문자들이 앞에서 온것임에 틀림없다면, 버퍼의 처음에 그들을 저장하라. */
if (filled > 0)
memcpy (inp, buffer, filled);
}
}
return 1;
}


18. 9 쉬프트 시퀀스들을 사용한 다중 바이트 코드들

어떤 다중 바이트 문자 코드에서, 어느 특정한 바이트 시퀀스의 의미가 고정되지 않은 것이 있다. 그 의미는 동일한 문자열의 처음에 있는 어떤 시퀀스에 의존한다. 전형적으로 그것은 단지 몇 개의 시퀀스로서 다른 시퀀스들의 의미를 변화시킬수 있다; 그들을 쉬프트 시퀀스라고 부르고 우리는 그 다음에 나타나는 다른 시퀀스를 위해서 쉬프트 시퀀스를 설정한다고 말한다.

쉬프트 상황과 쉬프트 시퀀스를 설명하기 위해서, 우리는 시퀀스 0200이 0240에서 0377의 범위를 갖는 바이트의 쌍으로 한 문자를 나타내는 일본어 모드를 시작함을 나타내고, 시퀀스 0201이 0240에서 0377의 범위를 갖고 ISO Latin-1의 문자 집합에 따라 해석되는 Latin-1 모드를 시작함을 나타낸다고 가정하자. 이것은 두개의 선택 가능한 쉬프트 상황을 가진 다중 바이트 코드("일본어 모드"와 "Latin-1 모드")를 가지고, 두 개의 쉬프트 시퀀스는 특정한 쉬프트 상황들을 설정한다. 사용하고 있는 다중 바이트 문자 코드가 쉬프트 상황들을 사용할 때, mblen, mbtowc 그리고 wctomb는 문자열을 조사해서 현재의 쉬프트 상황을 갱신하고 유지한다. 이러한 작업을 적당하게 만들기 위해서, 당신은 다음의 규칙들을 따라야만 한다.

문자열에 대한 조사를 시작하기 전에, 다중 바이트 문자 주소를 널 포인터로 해서 그 함수를 호출하라_예를 들어, mblen(NULL, 0). 이것은 표준 초기값으로 쉬프트 상황을 초기화한다.

한 번에 한문자씩, 순서대로 문자열을 조사하라. "뒤로"가지 말고 이미 조사했던 문자들을 다시 조사하지 말고, 다른 문자열을 처리하는 동안 방해하지 말아라.

이들 규칙들을 따라 mblen을 사용하는 예제가 있다.

void
scan_string (char *s)
{
int length = strlen (s);
/* 쉬프트 상황을 초기화하라. */
mblen (NULL, 0);
while (1) {
int thischar = mblen (s, length);
/* 문자열의 끝과 유용하지 않은 문자들을 처리하라 */
if (thischar == 0)
break;
if (thischar == -1) {
    error ("invalid multibyte character");
    break;
}
/* 이 문자를 넘어서 진행하라 */
s += thischar;
length -= thischar;
}
}

함수 mblen, mbtowc 그리고 wctomb들은 사용하고 있는 다중 바이트 코드가 쉬프트 상황을 사용할 때 재진입하지 않는다. 그렇지만, 어느 다른 라이브러리 함수도 이들 함수들을 호출하지 않기 때문에 당신은 그 쉬프트 상황이 당신이 이해할 수 없게 변할것이라고 걱정할 필요가 없다.