diff options
author | Choe Hwanjin <choe.hwanjin@gmail.com> | 2009-10-29 23:11:42 +0900 |
---|---|---|
committer | Choe Hwanjin <choe.hwanjin@gmail.com> | 2009-10-29 23:11:42 +0900 |
commit | e10b4225b5954dcb5af74b4338fd79023745abdb (patch) | |
tree | 0d3743ad5c02d889cad52bafd63555869f0b3c71 | |
parent | 23e35eda8d44c9adce9d8da705a2667df62d73bf (diff) | |
download | libhangul-e10b4225b5954dcb5af74b4338fd79023745abdb.tar.gz |
libhangul의 API 문서 작성
git-svn-id: http://kldp.net/svn/hangul/libhangul/trunk@205 8f00fcd2-89fc-0310-932e-b01be5b65e01
-rw-r--r-- | hangul/hangulctype.c | 137 | ||||
-rw-r--r-- | hangul/hangulinputcontext.c | 312 | ||||
-rw-r--r-- | hangul/hanja.c | 273 |
3 files changed, 677 insertions, 45 deletions
diff --git a/hangul/hangulctype.c b/hangul/hangulctype.c index 193e46a..99c17a5 100644 --- a/hangul/hangulctype.c +++ b/hangul/hangulctype.c @@ -1,8 +1,3 @@ -/** - * @file hangulctype.c - * @brief hangulctype source file - */ - /* libhangul * Copyright (C) 2004 - 2006 Choe Hwanjin * @@ -29,6 +24,31 @@ #include "hangul.h" +/** + * @defgroup hangulctype 한글 글자 조작 + * + * @section hangulctype 한글 글자 조작 + * libhangul은 한글 각 글자를 구분하고 조작하는데 사용할 수 있는 몇가지 함수를 + * 제공한다. libhangul의 글자 구분 함수의 인터페이스에서 글자의 기본 단위는 + * UCS4 코드값이다. + */ + +/** + * @file hangulctype.c + */ + +/** + * @ingroup hangulctype + * @typedef ucschar + * @brief UCS4 코드 단위의 글자 코드 값 + * + * UCS4 코드 값을 저장한다. libhangul에서 사용하는 문자열의 기본단위이다. + * preedit 문자열과 commit 문자열 모두 ucschar 포인터 형으로 전달된다. + * 이 스트링은 C 스트링과 유사하게 0으로 끝난다. + * 유니코드 값이 한글의 어떤 범주에 속하는지 확인하는 함수도 모두 ucschar 형을 + * 사용한다. + */ + static const ucschar syllable_base = 0xac00; static const ucschar choseong_base = 0x1100; static const ucschar jungseong_base = 0x1161; @@ -37,11 +57,12 @@ static const int njungseong = 21; static const int njongseong = 28; /** + * @ingroup hangulctype * @brief 초성인지 확인하는 함수 * @param c UCS4 코드 값 - * @return @param c 가 초성에 해당하면 true를 리턴함, 아니면 false + * @return @a c 가 초성에 해당하면 true를 리턴함, 아니면 false * - * @param c 로 주어진 UCS4 코드가 초성인지 확인한다. + * @a c 로 주어진 UCS4 코드가 초성인지 확인한다. * Unicode 5.2 지원 */ bool @@ -53,11 +74,12 @@ hangul_is_choseong(ucschar c) } /** + * @ingroup hangulctype * @brief 중성인지 확인하는 함수 * @param c UCS4 코드 값 - * @return @param c 가 중성에 해당하면 true를 리턴함, 아니면 false + * @return @a c 가 중성에 해당하면 true를 리턴함, 아니면 false * - * @param c 로 주어진 UCS4 코드가 중성인지 확인한다. + * @a c 로 주어진 UCS4 코드가 중성인지 확인한다. * Unicode 5.2 지원 */ bool @@ -68,11 +90,12 @@ hangul_is_jungseong(ucschar c) } /** + * @ingroup hangulctype * @brief 종성인지 확인하는 함수 * @param c UCS4 코드 값 - * @return @param c 가 종성에 해당하면 true를 리턴함, 아니면 false + * @return @a c 가 종성에 해당하면 true를 리턴함, 아니면 false * - * @param c 로 주어진 UCS4 코드가 종성인지 확인한다. + * @a c 로 주어진 UCS4 코드가 종성인지 확인한다. * Unicode 5.2 지원 */ bool @@ -92,6 +115,7 @@ hangul_is_combining_mark(ucschar c) } /** + * @ingroup hangulctype * @brief 초성이고 조합 가능한지 확인 */ bool @@ -101,6 +125,7 @@ hangul_is_choseong_conjoinable(ucschar c) } /** + * @ingroup hangulctype * @brief 중성이고 조합 가능한지 확인 */ bool @@ -110,6 +135,7 @@ hangul_is_jungseong_conjoinable(ucschar c) } /** + * @ingroup hangulctype * @brief 종성이고 조합 가능한지 확인 */ bool @@ -119,12 +145,13 @@ hangul_is_jongseong_conjoinable(ucschar c) } /** - * @brief check for a syllable - * @param c ucs4 code value - * @return true if the character c falls into syllable class + * @ingroup hangulctype + * @brief 한글 음절 인지 확 + * @param c UCS4 코드 값 + * @return @a c가 한글 음절 코드이면 true, 그 외에는 false * - * This function check whether c, which must have ucs4 value, falls into - * syllable class; that is from U+AC00 to 0xD7A3. + * 이 함수는 @a c로 주어진 UCS4 코드가 현대 한글 음절에 해당하는지 + * 확인한다. */ bool hangul_is_syllable(ucschar c) @@ -133,11 +160,12 @@ hangul_is_syllable(ucschar c) } /** + * @ingroup hangulctype * @brief 자모 인지 확인 * @param c UCS4 코드 값 - * @return @param c 가 자모 코드이면 true를 리턴, 그외에는 false + * @return @a c 가 자모 코드이면 true를 리턴, 그외에는 false * - * @param c 로 주어진 UCS4 코드가 자모 코드인지 확인한다. + * @a c 로 주어진 UCS4 코드가 자모 코드인지 확인한다. * Unicode 5.2 지원 */ bool @@ -148,7 +176,7 @@ hangul_is_jamo(ucschar c) hangul_is_jongseong(c); } -/* deprecated */ +/** @deprecated 이 함수 대신 hangul_is_jamo()함수를 사용한다. */ bool hangul_is_jaso(ucschar c) { @@ -156,12 +184,12 @@ hangul_is_jaso(ucschar c) } /** - * @brief check for a compatibility jamo - * @param c ucs4 code value - * @return true if the character c falls into compatibility class + * @ingroup hangulctype + * @brief 호환 자모인지 확인 + * @param c UCS4 코드 값 + * @return @a c가 호환자모이면 true, 그 외에는 false * - * This function check whether c, which must have ucs4 value, falls into - * compatibility jamo class. + * 이 함수는 @a c로 주어진 UCS4 코드가 호환 자모인지 확인한다. */ bool hangul_is_cjamo(ucschar c) @@ -170,12 +198,14 @@ hangul_is_cjamo(ucschar c) } /** - * @brief convert a jamo to the compatibility jamo - * @param c ucs4 code value - * @return converted value, or c + * @ingroup hangulctype + * @brief 자모 코드를 대응하는 호환 자모로 변환 + * @param c 변환할 UCS4 코드 값 + * @return @a c 에 대응되는 호환 자모 값, or c * - * This function converts the jamo c, which must have ucs4 value, to - * comaptibility jamo or c if the conversion is failed + * 이 함수는 @a c 로 주어진 자모 코드와 같은 형태를 가진 호환 자모 값을 + * 리턴한다. 자모와 같은 형태를 가진 호환 자모가 없는 경우에는 @a c 의 + * 값을 그대로 리턴한다. */ ucschar hangul_jamo_to_cjamo(ucschar c) @@ -562,7 +592,7 @@ hangul_jamo_to_cjamo(ucschar c) return ret; } -/* deprecated */ +/** @deprecated 이 함수 대신 hangul_jamo_to_cjamo()함수를 사용한다. */ ucschar hangul_jaso_to_jamo(ucschar c) { @@ -673,14 +703,18 @@ hangul_jongseong_dicompose(ucschar c, ucschar* jong, ucschar* cho) } /** - * @brief compose a hangul syllable - * @param choseong UCS4 code value - * @param jungseong UCS4 code value - * @param jongseong UCS4 code value - * @return syllable code compose from choseong, jungseong and jongseong + * @ingroup hangulctype + * @brief 자모 코드를 조합하여 한글 음절로 변환 + * @param choseong 초성이 될 UCS4 코드 값 + * @param jungseong 중성이 될 UCS4 코드 값 + * @param jongseong 종성이 될 UCS4 코드 값 + * @return @a choseong @a jungseong @a jongseong을 조합한 현대 한글 음절 코드, + * 또는 0 * - * This function compose hangul jamo choseong, jungseong and jongseong and - * return the syllable code. + * 이 함수는 @a choseong @a jungseong @a jongseong으로 주어진 코드 값을 각각 + * 초성, 중성, 종성으로 하는 현대 한글 음절 코드를 구한다. + * @a choseong @a jungseong @a jongseong 이 조합 가능한 코드가 아니라면 + * 0을 리턴한다. 종성이 없는 글자를 만들기 위해서는 jongseong에 0을 주면 된다. */ ucschar hangul_jamo_to_syllable(ucschar choseong, ucschar jungseong, ucschar jongseong) @@ -707,13 +741,26 @@ hangul_jamo_to_syllable(ucschar choseong, ucschar jungseong, ucschar jongseong) return c; } -/* deprecated */ +/** @deprecated 이 함수 대신 hangul_jamo_to_syllable()을 사용한다. */ ucschar hangul_jaso_to_syllable(ucschar choseong, ucschar jungseong, ucschar jongseong) { return hangul_jamo_to_syllable(choseong, jungseong, jongseong); } +/** + * @ingroup hangulctype + * @brief 음절을 자모로 분해 + * @param syllable 분해할 음절 + * @retval choseong 음절에서 초성 부분의 코드 + * @retval jungseong 음절에서 중성 부분의 코드 + * @retval jongseong 음절에서 종성 부분의 코드, 종성이 없으면 0을 반환한다 + * @return 없음 + * + * 이 함수는 @a syllable 로 주어진 음절 코드를 분해하여 자모 코드를 반환한다. + * 반환하는 값은 @a choseong, @a jungseong, @a jongseong 의 포인터에 대입하여 + * 리턴한다. 종성이 없는 음절인 경우에는 @a jongseong 에 0을 반환한다. + */ void hangul_syllable_to_jamo(ucschar syllable, ucschar* choseong, @@ -747,7 +794,7 @@ hangul_syllable_to_jamo(ucschar syllable, } } -/* deprecated */ +/** @deprecated 이 함수 대신 hangul_syllable_to_jamo함수를 사용한다. */ void hangul_syllable_to_jaso(ucschar syllable, ucschar* choseong, @@ -944,7 +991,8 @@ build_syllable(const ucschar* str, size_t len) } /** - * @brief 한 음절에 해당하는 코드의 갯수를 구한다 + * @ingroup hangulctype + * @brief 한 음절에 해당하는 코드의 갯수를 구하는 함수 * @param str 음절의 길이를 구할 스트링 * @param max_len @a str 에서 읽을 길이의 제한값 * @return 한 음절에 해당하는 코드의 갯수 @@ -990,7 +1038,8 @@ hangul_syllable_len(const ucschar* str, int max_len) } /** - * @brief @a iter를 기준으로 이전 음절의 첫자모 글자에 대한 포인터를 구한다. + * @ingroup hangulctype + * @brief @a iter를 기준으로 이전 음절의 첫자모 글자에 대한 포인터를 구하는 함수 * @param iter 현재 위치 * @param begin 스트링의 시작위치, 포인터가 이동할 한계값 * @return 이전 음절의 첫번째 자모에 대한 포인터 @@ -1019,7 +1068,8 @@ hangul_syllable_iterator_prev(const ucschar* iter, const ucschar* begin) } /** - * @brief @a iter를 기준으로 다음 음절의 첫자모 글자에 대한 포인터를 구한다. + * @ingroup hangulctype + * @brief @a iter를 기준으로 다음 음절의 첫자모 글자에 대한 포인터를 구하는 함수 * @param iter 현재 위치 * @param end 스트링의 끝위치, 포인터가 이동할 한계값 * @return 다음 음절의 첫번째 자모에 대한 포인터 @@ -1048,7 +1098,8 @@ hangul_syllable_iterator_next(const ucschar* iter, const ucschar* end) } /** - * @brief 자모 스트링을 음절 스트링을 변환한다 + * @ingroup hangulctype + * @brief 자모 스트링을 음절 스트링으로 변환 * @param dest 음절형으로 변환된 결과가 저장될 버퍼 * @param destlen 결과를 저장할 버퍼의 길이(ucschar 코드 단위) * @param src 변환할 자모 스트링 diff --git a/hangul/hangulinputcontext.c b/hangul/hangulinputcontext.c index ac5da5b..1f0cdfc 100644 --- a/hangul/hangulinputcontext.c +++ b/hangul/hangulinputcontext.c @@ -12,7 +12,6 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ @@ -29,6 +28,143 @@ #include "hangul.h" #include "hangulinternals.h" +/** + * @defgroup hangulic 한글 입력 기능 구현 + * + * @section hangulicusage Hangul Input Context의 사용법 + * 이 섹션에서는 한글 입력 기능을 구현하는 핵심 기능에 대해 설명한다. + * + * 먼저 preedit string과 commit string 이 두 용어에 대해서 설멍하겠다. + * 이 두가지 용어는 Unix 계열의 입력기 framework에서 널리 쓰이는 표현이다. + * + * preedit string은 아직 조합중으로 어플리케이션에 완전히 입력되지 않은 + * 스트링을 가리킨다. 일반적으로 한글 입력기에서는 역상으로 보이고 + * 일본 중국어 입력기에서는 underline이 붙어 나타난다. 아직 완성이 되지 + * 않은 스트링이므로 어플리케이션에 전달이 되지 않고 사라질 수도 있다. + * + * commit string은 조합이 완료되어 어플리케이션에 전달되는 스트링이다. + * 이 스트링은 실제 어플리케이션의 텍스트로 인식이 되므로 이 이후에는 + * 더이상 입력기가 관리할 수 있는 데이터가 아니다. + * + * 한글 입력과정은 다음과 같은 과정을 거치게 된다. + * 입력된 영문 키를 그에 해댱하는 한글 자모로 변환한후 한글 자모를 모아 + * 하나의 음절을 만든다. 여기까지 이루어지는 과정을 preedit string 형태로 + * 사용자에게 계속 보이게 하는 것이 필요하다. + * 그리고는 한글 음절이 완성되고나면 그 글자를 어플리케이션에 commit + * string 형태로 보내여 입력을 완료하는 것이다. 다음 키를 받게 되면 + * 이 과정을 반복해서 수행한다. + * + * libhangul에서 한글 조합 기능은 @ref HangulInputContext를 이용해서 구현하게 + * 되는데 기본 적인 방법은 @ref HangulInputContext에 사용자로부터의 입력을 + * 순서대로 전달하면서 그 상태가 바뀜에 따라서 preedit 나 commit 스트링을 + * 상황에 맞게 변화시키는 것이다. + * + * 입력 코드들은 GUI 코드와 밀접하게 붙어 있어서 키 이벤트를 받아서 + * 처리하도록 구현하는 것이 보통이다. 그런데 유닉스에는 많은 입력 프레임웍들이 + * 난립하고 있는 상황이어서 매 입력 프레임웍마다 한글 조합 루틴을 작성해서 + * 넣는 것은 비효율적이다. 간단한 API를 구현하여 여러 프레임웍에서 바로 + * 사용할 수 있도록 구현하는 편이 사용성이 높아지게 된다. + * + * 그래서 libhangul에서는 키 이벤트를 따로 재정의하지 않고 ASCII 코드를 + * 직접 사용하는 방향으로 재정의된 데이터가 많지 않도록 하였다. + * 실제 사용 방법은 말로 설명하는 것보다 샘플 코드를 사용하는 편이 + * 이해가 빠를 것이다. 그래서 대략적인 진행 과정을 샘플 코드로 + * 작성하였다. + * + * 아래 예제는 실제로는 존재하지 않는 GUI 라이브러리 코드를 사용하였다. + * 실제 GUI 코드를 사용하면 코드가 너무 길어져서 설명이 어렵고 코드가 + * 길어지면 핵심을 놓치기 쉽기 때문에 가공의 함수를 사용하였다. + * 또한 텍스트의 encoding conversion 관련된 부분도 생략하였다. + * 여기서 사용한 가공의 GUI 코드는 TWin으로 시작하게 하였다. + * + * @code + + HangulInputContext* hic = hangul_ic_new("2"); + ... + + // 아래는 키 입력만 처리하는 이벤트 루프이다. + // 실제 GUI코드는 이렇게 단순하진 않지만 + // 편의상 키 입력만 처리하는 코드로 작성하였다. + + TWinKeyEvent event = TWinGetKeyEvent(); // 키이벤트를 받는 이런 함수가 + // 있다고 치자 + while (ascii != 0) { + bool res; + if (event.isBackspace()) { + // backspace를 ascii로 변환하기가 좀 꺼림직해서 + // libhangul에서는 backspace 처리를 위한 + // 함수를 따로 만들었다. + res = hangul_ic_backspace(hic); + } else { + // 키 입력을 해당하는 ascii 코드로 변환한다. + // libhangul에서는 이 ascii 코드가 키 이벤트 + // 코드와 마찬가지다. + int ascii = event.getAscii(); + + // 키 입력을 받았으면 이것을 hic에 먼저 보낸다. + // 그래야 hic가 이 키를 사용할 것인지 아닌지를 판단할 수 있다. + // 함수가 true를 리턴하면 이 키를 사용했다는 의미이므로 + // GUI 코드가 이 키 입력을 프로세싱하지 않도록 해야 한다. + // 그렇지 않으면 한 키입력이 두번 프로세싱된다. + res = hangul_ic_process(hic, ascii); + } + + // hic는 한번 키입력을 받고 나면 내부 상태 변화가 일어나고 + // 완성된 글자를 어플리케이션에 보내야 하는 상황이 있을 수 있다. + // 이것을 HangulInputContext에서는 commit 스트링이 있는지로 + // 판단한다. commit 스트링을 받아봐서 스트링이 있다면 + // 그 스트링으로 입력이 완료된 걸로 본다. + const ucschar commit; + commit = hangul_ic_get_commit_string(hic); + if (commit[0] != 0) { // 스트링의 길이를 재서 commit 스트링이 있는지 + // 판단한다. + TWinInputUnicodeChars(commit); + } + + // 키입력 후에는 preedit string도 역시 변화하게 되는데 + // 입력기 프레임웍에서는 이 스트링을 화면에 보여주어야 + // 조합중인 글자가 화면에 표시가 되는 것이다. + const ucschar preedit; + preedit = hangul_ic_get_preedit_string(hic); + // 이 경우에는 스트링의 길이에 관계없이 항상 업데이트를 + // 해야 한다. 왜냐하면 이전에 조합중이던 글자가 있다가 + // 조합이 완료되면서 조합중인 상태의 글자가 없어질 수도 있기 때문에 + // 스트링의 길이에 관계없이 현재 상태의 스트링을 preedit + // 스트링으로 보여주면 되는 것이다. + TWinUpdatePreeditString(preedit); + + // 위 두작업이 끝난후에는 키 이벤트를 계속 프로세싱해야 하는지 + // 아닌지를 처리해야 한다. + // hic가 키 이벤트를 사용하지 않았다면 기본 GUI 코드에 계속해서 + // 키 이벤트 프로세싱을 진행하도록 해야 한다. + if (!res) + TWinForwardKeyEventToUI(ascii); + + ascii = GetKeyEvent(); + } + + hangul_ic_delete(hic); + + * @endcode + */ + +/** + * @file hangulinputcontext.c + */ + +/** + * @ingroup hangulic + * @typedef HangulInputContext + * @brief 한글 입력 상태를 관리하기 위한 오브젝트 + * + * libhangul에서 제공하는 한글 조합 루틴에서 상태 정보를 저장하는 opaque + * 데이타 오브젝트이다. 이 오브젝트에 키입력 정보를 순차적으로 보내주면서 + * preedit 스트링이나, commit 스트링을 받아서 처리하면 한글 입력 기능을 + * 손쉽게 구현할 수 있다. + * 내부의 데이터 멤버는 공개되어 있지 않다. 각각의 멤버는 accessor 함수로만 + * 참조하여야 한다. + */ + #ifndef TRUE #define TRUE 1 #endif @@ -1006,6 +1142,32 @@ flush: return false; } +/** + * @ingroup hangulic + * @brief 키 입력을 처리하여 실제로 한글 조합을 하는 함수 + * @param hic @ref HangulInputContext 오브젝트 + * @param ascii 키 이벤트 + * @return @ref HangulInputContext가 이 키를 사용했으면 true, + * 사용하지 않았으면 false + * + * ascii 값으로 주어진 키 이벤트를 받아서 내부의 한글 조합 상태를 + * 변화시키고, preedit, commit 스트링을 저장한다. + * + * libhangul의 키 이벤트 프로세스는 ASCII 코드 값을 기준으로 처리한다. + * 이 키 값은 US Qwerty 자판 배열에서의 키 값에 해당한다. + * 따라서 유럽어 자판을 사용하는 경우에는 해당 키의 ASCII 코드를 직접 + * 전달하면 안되고, 그 키가 US Qwerty 자판이었을 경우에 발생할 수 있는 + * ASCII 코드 값을 주어야 한다. + * 또한 ASCII 코드 이므로 Shift 상태는 대문자로 전달이 된다. + * Capslock이 눌린 경우에는 대소문자를 뒤바꾸어 보내주지 않으면 + * 마치 Shift가 눌린 것 처럼 동작할 수 있으므로 주의한다. + * preedit, commit 스트링은 hangul_ic_get_preedit_string(), + * hangul_ic_get_commit_string() 함수를 이용하여 구할 수 있다. + * + * 이 함수의 사용법에 대한 설명은 @ref hangulicusage 부분을 참조한다. + * + * @remarks 이 함수는 @ref HangulInputContext의 상태를 변화 시킨다. + */ bool hangul_ic_process(HangulInputContext *hic, int ascii) { @@ -1029,6 +1191,18 @@ hangul_ic_process(HangulInputContext *hic, int ascii) return hangul_ic_process_romaja(hic, ascii, c); } +/** + * @ingroup hangulic + * @brief 현재 상태의 preedit string을 구하는 함수 + * @param hic preedit string을 구하고자하는 입력 상태 object + * @return UCS4 preedit 스트링, 이 스트링은 @a hic 내부의 데이터이므로 + * 수정하거나 free해서는 안된다. + * + * 이 함수는 @a hic 내부의 현재 상태의 preedit string을 리턴한다. + * 따라서 hic가 다른 키 이벤트를 처리하고 나면 그 내용이 바뀔 수 있다. + * + * @remarks 이 함수는 @ref HangulInputContext의 상태를 변화 시키지 않는다. + */ const ucschar* hangul_ic_get_preedit_string(HangulInputContext *hic) { @@ -1038,6 +1212,18 @@ hangul_ic_get_preedit_string(HangulInputContext *hic) return hic->preedit_string; } +/** + * @ingroup hangulic + * @brief 현재 상태의 commit string을 구하는 함수 + * @param hic commit string을 구하고자하는 입력 상태 object + * @return UCS4 commit 스트링, 이 스트링은 @a hic 내부의 데이터이므로 + * 수정하거나 free해서는 안된다. + * + * 이 함수는 @a hic 내부의 현재 상태의 commit string을 리턴한다. + * 따라서 hic가 다른 키 이벤트를 처리하고 나면 그 내용이 바뀔 수 있다. + * + * @remarks 이 함수는 @ref HangulInputContext의 상태를 변화 시키지 않는다. + */ const ucschar* hangul_ic_get_commit_string(HangulInputContext *hic) { @@ -1047,6 +1233,20 @@ hangul_ic_get_commit_string(HangulInputContext *hic) return hic->commit_string; } +/** + * @ingroup hangulic + * @brief @ref HangulInputContext를 초기상태로 되돌리는 함수 + * @param hic @ref HangulInputContext를 가리키는 포인터 + * + * 이 함수는 @a hic가 가리키는 @ref HangulInputContext의 상태를 + * 처음 상태로 되돌린다. preedit 스트링, commit 스트링, flush 스트링이 + * 없어지고, 입력되었던 키에 대한 기록이 없어진다. + * 영어 상태로 바뀌는 것이 아니다. + * + * 비교: hangul_ic_flush() + * + * @remarks 이 함수는 @ref HangulInputContext의 상태를 변화 시킨다. + */ void hangul_ic_reset(HangulInputContext *hic) { @@ -1071,6 +1271,23 @@ hangul_ic_flush_internal(HangulInputContext *hic) hangul_buffer_clear(&hic->buffer); } +/** + * @ingroup hangulic + * @brief @ref HangulInputContext의 입력 상태를 완료하는 함수 + * @param hic @ref HangulInputContext를 가리키는 포인터 + * @return 조합 완료된 스트링, 스트링의 길이가 0이면 조합 완료된 스트링이 + * 없는 것 + * + * 이 함수는 @a hic가 가리키는 @ref HangulInputContext의 입력 상태를 완료한다. + * 조합중이던 스트링을 완성하여 리턴한다. 그리고 입력 상태가 초기 상태로 + * 되돌아 간다. 조합중이던 글자를 강제로 commit하고 싶을때 사용하는 함수다. + * 보통의 경우 입력 framework에서 focus가 나갈때 이 함수를 불러서 마지막 + * 상태를 완료해야 조합중이던 글자를 잃어버리지 않게 된다. + * + * 비교: hangul_ic_reset() + * + * @remarks 이 함수는 @ref HangulInputContext의 상태를 변화 시킨다. + */ const ucschar* hangul_ic_flush(HangulInputContext *hic) { @@ -1095,6 +1312,19 @@ hangul_ic_flush(HangulInputContext *hic) return hic->flushed_string; } +/** + * @ingroup hangulic + * @brief @ref HangulInputContext가 backspace 키를 처리하도록 하는 함수 + * @param hic @ref HangulInputContext를 가리키는 포인터 + * @return @a hic가 키를 사용했으면 true, 사용하지 않았으면 false + * + * 이 함수는 @a hic가 가리키는 @ref HangulInputContext의 조합중이던 글자를 + * 뒤에서부터 하나 지우는 기능을 한다. backspace 키를 눌렀을 때 발생하는 + * 동작을 한다. 따라서 이 함수를 부르고 나면 preedit string이 바뀌므로 + * 반드시 업데이트를 해야 한다. + * + * @remarks 이 함수는 @ref HangulInputContext의 상태를 변화 시킨다. + */ bool hangul_ic_backspace(HangulInputContext *hic) { @@ -1218,24 +1448,60 @@ hangul_ic_dvorak_to_qwerty(int qwerty) return qwerty; } +/** + * @ingroup hangulic + * @brief @ref HangulInputContext가 조합중인 글자를 가지고 있는지 확인하는 함수 + * @param hic @ref HangulInputContext를 가리키는 포인터 + * + * @ref HangulInputContext가 조합중인 글자가 있으면 true를 리턴한다. + * + * @remarks 이 함수는 @ref HangulInputContext의 상태를 변화 시키지 않는다. + */ bool hangul_ic_is_empty(HangulInputContext *hic) { return hangul_buffer_is_empty(&hic->buffer); } +/** + * @ingroup hangulic + * @brief @ref HangulInputContext가 조합중인 초성을 가지고 있는지 확인하는 함수 + * @param hic @ref HangulInputContext를 가리키는 포인터 + * + * @ref HangulInputContext가 조합중인 글자가 초성이 있으면 true를 리턴한다. + * + * @remarks 이 함수는 @ref HangulInputContext의 상태를 변화 시키지 않는다. + */ bool hangul_ic_has_choseong(HangulInputContext *hic) { return hangul_buffer_has_choseong(&hic->buffer); } +/** + * @ingroup hangulic + * @brief @ref HangulInputContext가 조합중인 중성을 가지고 있는지 확인하는 함수 + * @param hic @ref HangulInputContext를 가리키는 포인터 + * + * @ref HangulInputContext가 조합중인 글자가 중성이 있으면 true를 리턴한다. + * + * @remarks 이 함수는 @ref HangulInputContext의 상태를 변화 시키지 않는다. + */ bool hangul_ic_has_jungseong(HangulInputContext *hic) { return hangul_buffer_has_jungseong(&hic->buffer); } +/** + * @ingroup hangulic + * @brief @ref HangulInputContext가 조합중인 종성을 가지고 있는지 확인하는 함수 + * @param hic @ref HangulInputContext를 가리키는 포인터 + * + * @ref HangulInputContext가 조합중인 글자가 종성이 있으면 true를 리턴한다. + * + * @remarks 이 함수는 @ref HangulInputContext의 상태를 변화 시키지 않는다. + */ bool hangul_ic_has_jongseong(HangulInputContext *hic) { @@ -1304,6 +1570,27 @@ hangul_ic_set_keyboard(HangulInputContext *hic, const HangulKeyboard* keyboard) hic->keyboard = keyboard; } +/** + * @ingroup hangulic + * @brief @ref HangulInputContext의 자판 배열을 바꾸는 함수 + * @param hic @ref HangulInputContext 오브젝트 + * @param id 선택하고자 하는 자판, 아래와 같은 값을 선택할 수 있다. + * @li "2" 두벌식 자판 + * @li "32" 세벌식 자판으로 두벌식의 배열을 가진 자판. + * 두벌식 사용자가 쉽게 세벌식 테스트를 할 수 있다. + * shift를 누르면 자음이 종성으로 동작한다. + * @li "3f" 세벌식 최종 + * @li "39" 세벌식 390 + * @li "3s" 세벌식 순아래 + * @li "3y" 세벌식 옛글 + * @li "ro" 로마자 방식 자판 + * @return 없음 + * + * 이 함수는 @ref HangulInputContext의 자판을 @a id로 지정된 것으로 변경한다. + * + * @remarks 이 함수는 @ref HangulInputContext의 내부 조합 상태에는 영향을 + * 미치지 않는다. 따라서 입력 중간에 자판을 변경하더라도 조합 상태는 유지된다. + */ void hangul_ic_select_keyboard(HangulInputContext *hic, const char* id) { @@ -1361,6 +1648,18 @@ hangul_ic_set_combination(HangulInputContext *hic, hic->combination = combination; } +/** + * @ingroup hangulic + * @brief @ref HangulInputContext 오브젝트를 생성한다. + * @param keyboard 사용하고자 하는 키보드, 사용 가능한 값에 대해서는 + * hangul_ic_select_keyboard() 함수 설명을 참조한다. + * @return 새로 생성된 @ref HangulInputContext에 대한 포인터 + * + * 이 함수는 한글 조합 기능을 제공하는 @ref HangulInputContext 오브젝트를 + * 생성한다. 생성할때 지정한 자판은 나중에 hangul_ic_select_keyboard() 함수로 + * 다른 자판으로 변경이 가능하다. + * 더이상 사용하지 않을 때에는 hangul_ic_delete() 함수로 삭제해야 한다. + */ HangulInputContext* hangul_ic_new(const char* keyboard) { @@ -1390,6 +1689,17 @@ hangul_ic_new(const char* keyboard) return hic; } +/** + * @ingroup hangulic + * @brief @ref HangulInputContext를 삭제하는 함수 + * @param hic @ref HangulInputContext 오브젝트 + * + * @a hic가 가리키는 @ref HangulInputContext 오브젝트의 메모리를 해제한다. + * hangul_ic_new() 함수로 생성된 모든 @ref HangulInputContext 오브젝트는 + * 이 함수로 메모리해제를 해야 한다. + * 메모리 해제 과정에서 상태 변화는 일어나지 않으므로 마지막 입력된 + * 조합중이던 내용은 사라지게 된다. + */ void hangul_ic_delete(HangulInputContext *hic) { diff --git a/hangul/hanja.c b/hangul/hanja.c index 61222b8..9363209 100644 --- a/hangul/hanja.c +++ b/hangul/hanja.c @@ -44,6 +44,108 @@ #define FALSE 0 #endif +/** + * @defgroup hanjadictionary 한자 사전 검색 기능 + * + * @section hanjadictionaryusage 한자 사전 루틴의 사용 방법 + * libhangul에서는 한자 사전 파일과 그 사전 파일을 검색할 수 있는 몇가지 + * 함수의 셋을 제공한다. 여기에서 사용되는 모든 스트링은 UTF-8 인코딩을 + * 사용한다. libhangul에서 사용하는 한자 사전 파일의 포맷은 + * @ref HanjaTable 섹션을 참조한다. + * + * 그 개략적인 사용 방법은 다음과 같다. + * + * @code + // 지정된 위치의 한자 사전 파일을 로딩한다. + // 아래 코드에서는 libhangul의 한자 사전 파일을 로딩하기 위해서 + // NULL을 argument로 준다. + HanjaTable* table = hanja_table_load(NULL); + + // "삼국사기"에 해당하는 한자를 찾는다. + HanjaList* list = hanja_table_match_exact(table, "삼국사기"); + if (list != NULL) { + int i; + int n = hanja_list_get_size(list); + for (i = 0; i < n; ++i) { + const char* hanja = hanja_list_get_nth_value(list); + printf("한자: %s\n", hanja); + } + hanja_list_delete(list); + } + + hanja_table_delete(table); + + * @endcode + */ + +/** + * @file hanja.c + */ + +/** + * @ingroup hanjadictionary + * @typedef Hanja + * @brief 한자 사전 검색 결과의 최소 단위 + * + * Hanja 오브젝트는 한자 사전 파일의 각 엔트리에 해당한다. + * 각 엔트리는 키(key), 밸류(value) 페어로 볼 수 있는데, libhangul에서는 + * 약간 확장을 하여 설명(comment)도 포함하고 있다. + * 한자 사전 포맷은 @ref HanjaTable 부분을 참조한다. + * + * 한자 사전을 검색하면 결과는 Hanja 오브젝트의 리스트 형태로 전달된다. + * @ref HanjaList에서 각 엔트리의 내용을 하나씩 확인할 수 있다. + * Hanja의 멤버는 직접 참조할 수 없고, hanja_get_key(), hanja_get_value(), + * hanja_get_comment() 함수로 찾아볼 수 있다. + * char 스트링으로 전달되는 내용은 모두 UTF-8 인코딩으로 되어 있다. + */ + +/** + * @ingroup hanjadictionary + * @typedef HanjaList + * @brief 한자 사전의 검색 결과를 전달하는데 사용하는 오브젝트 + * + * 한자 사전의 검색 함수를 사용하면 이 타입으로 결과를 리턴한다. + * 이 오브젝트에서 hanja_list_get_nth()함수를 이용하여 검색 결과를 + * 이터레이션할 수 있다. 내부 구현 내용은 외부로 노출되어 있지 않다. + * @ref HanjaList가 가지고 있는 아이템들은 accessor 함수들을 이용해서 참조한다. + * + * 참조: hanja_list_get_nth(), hanja_list_get_nth_key(), + * hanja_list_get_nth_value(), hanja_list_get_nth_comment() + */ + +/** + * @ingroup hanjadictionary + * @typedef HanjaTable + * @brief 한자 사전을 관리하는데 사용하는 오브젝트 + * + * libhangul에서 한자 사전을 관리하는데 사용하는 오브젝트로 + * 내부 구현 내용은 외부로 노출되어 있지 않다. + * + * libhangul에서 사용하는 한자 사전 파일의 포맷은 다음과 같은 형식이다. + * + * @code + * # comment + * key1:value1:comment1 + * key2:value2:comment2 + * key3:value3:comment3 + * ... + * @endcode + * + * 각 필드는 @b @c : 으로 구분하고, 첫번째 필드는 각 한자를 찾을 키값이고 + * 두번째 필드는 그 키값에 해당하는 한자 스트링, 세번째 필드는 이 키와 + * 값에 대한 설명이다. #으로 시작하는 라인은 주석으로 무시된다. + * + * 실제 예를 들면 다음과 같은 식이다. + * + * @code + * 삼국사기:三國史記:삼국사기 + * 한자:漢字:한자 + * @endcode + * + * 그 내용은 키값에 대해서 sorting 되어야 있어야 한다. + * 파일의 인코딩은 UTF-8이어야 한다. + */ + typedef struct _HanjaIndex HanjaIndex; typedef struct _HanjaPair HanjaPair; @@ -172,6 +274,15 @@ hanja_delete(Hanja* hanja) free(hanja); } +/** + * @ingroup hanjadictionary + * @brief @ref Hanja의 키를 찾아본다. + * @return @a hanja 오브젝트의 키, UTF-8 + * + * 일반적으로 @ref Hanja 아이템의 키는 한글이다. + * 리턴되는 스트링은 @a hanja 오브젝트 내부적으로 관리하는 데이터로 + * 수정하거나 free 되어서는 안된다. + */ const char* hanja_get_key(const Hanja* hanja) { @@ -182,6 +293,15 @@ hanja_get_key(const Hanja* hanja) return NULL; } +/** + * @ingroup hanjadictionary + * @brief @ref Hanja의 값을 찾아본다. + * @return @a hanja 오브젝트의 값, UTF-8 + * + * 일반적으로 @ref Hanja 아이템의 값은 key에 대응되는 한자다. + * 리턴되는 스트링은 @a hanja 오브젝트 내부적으로 관리하는 데이터로 + * 수정하거나 free되어서는 안된다. + */ const char* hanja_get_value(const Hanja* hanja) { @@ -192,6 +312,16 @@ hanja_get_value(const Hanja* hanja) return NULL; } +/** + * @ingroup hanjadictionary + * @brief @ref Hanja의 설명을 찾아본다. + * @return @a hanja 오브젝트의 comment 필드, UTF-8 + * + * 일반적으로 @ref Hanja 아이템의 설명은 한글과 그 한자에 대한 설명이다. + * 파일에 따라서 내용이 없을 수 있다. + * 리턴되는 스트링은 @a hanja 오브젝트 내부적으로 관리하는 데이터로 + * 수정하거나 free되어서는 안된다. + */ const char* hanja_get_comment(const Hanja* hanja) { @@ -316,6 +446,23 @@ hanja_table_match(const HanjaTable* table, } } +/** + * @ingroup hanjadictionary + * @brief 한자 사전 파일을 로딩하는 함수 + * @param filename 로딩할 사전 파일의 위치, 또는 NULL + * @return 한자 사전 object 또는 NULL + * + * 이 함수는 한자 사전 파일을 로딩하는 함수로 @a filename으로 지정된 + * 파일을 로딩한다. 한자 사전 파일은 libhangul에서 사용하는 포맷이어야 한다. + * 한자 사전 파일의 포맷에 대한 정보는 HanjaTable을 참조한다. + * + * @a filename은 locale에 따른 인코딩으로 되어 있어야 한다. UTF-8이 아닐 수 + * 있으므로 주의한다. + * + * @a filename 에 NULL을 주면 libhangul에서 디폴트로 배포하는 사전을 로딩한다. + * 파일이 없거나, 포맷이 맞지 않으면 로딩에 실패하고 NULL을 리턴한다. + * 한자 사전이 더이상 필요없으면 hanja_table_delete() 함수로 삭제해야 한다. + */ HanjaTable* hanja_table_load(const char* filename) { @@ -398,6 +545,11 @@ hanja_table_load(const char* filename) return table; } +/** + * @ingroup hanjadictionary + * @brief 한자 사전 object를 free하는 함수 + * @param table free할 한자 사전 object + */ void hanja_table_delete(HanjaTable *table) { @@ -408,6 +560,18 @@ hanja_table_delete(HanjaTable *table) } } +/** + * @ingroup hanjadictionary + * @brief 한자 사전에서 매치되는 키를 가진 엔트리를 찾는 함수 + * @param table 한자 사전 object + * @param key 찾을 키, UTF-8 인코딩 + * @return 찾은 결과를 HanjaList object로 리턴한다. 찾은 것이 없거나 에러가 + * 있으면 NULL을 리턴한다. + * + * @a key 값과 같은 키를 가진 엔트리를 검색한다. + * 리턴된 결과는 다 사용하고 나면 반드시 hanja_list_delete() 함수로 free해야 + * 한다. + */ HanjaList* hanja_table_match_exact(const HanjaTable* table, const char *key) { @@ -421,6 +585,21 @@ hanja_table_match_exact(const HanjaTable* table, const char *key) return ret; } +/** + * @ingroup hanjadictionary + * @brief 한자 사전에서 앞부분이 매치되는 키를 가진 엔트리를 찾는 함수 + * @param table 한자 사전 object + * @param key 찾을 키, UTF-8 인코딩 + * @return 찾은 결과를 HanjaList object로 리턴한다. 찾은 것이 없거나 에러가 + * 있으면 NULL을 리턴한다. + * + * @a key 값과 같거나 앞부분이 같은 키를 가진 엔트리를 검색한다. + * 그리고 key를 뒤에서부터 한자씩 줄여가면서 검색을 계속한다. + * 예로 들면 "삼국사기"를 검색하면 "삼국사기", "삼국사", "삼국", "삼"을 + * 각각 모두 검색한다. + * 리턴된 결과는 다 사용하고 나면 반드시 hanja_list_delete() 함수로 free해야 + * 한다. + */ HanjaList* hanja_table_match_prefix(const HanjaTable* table, const char *key) { @@ -446,6 +625,21 @@ hanja_table_match_prefix(const HanjaTable* table, const char *key) return ret; } +/** + * @ingroup hanjadictionary + * @brief 한자 사전에서 뒷부분이 매치되는 키를 가진 엔트리를 찾는 함수 + * @param table 한자 사전 object + * @param key 찾을 키, UTF-8 인코딩 + * @return 찾은 결과를 HanjaList object로 리턴한다. 찾은 것이 없거나 에러가 + * 있으면 NULL을 리턴한다. + * + * @a key 값과 같거나 뒷부분이 같은 키를 가진 엔트리를 검색한다. + * 그리고 key를 앞에서부터 한자씩 줄여가면서 검색을 계속한다. + * 예로 들면 "삼국사기"를 검색하면 "삼국사기", "국사기", "사기", "기"를 + * 각각 모두 검색한다. + * 리턴된 결과는 다 사용하고 나면 반드시 hanja_list_delete() 함수로 free해야 + * 한다. + */ HanjaList* hanja_table_match_suffix(const HanjaTable* table, const char *key) { @@ -464,6 +658,10 @@ hanja_table_match_suffix(const HanjaTable* table, const char *key) return ret; } +/** + * @ingroup hanjadictionary + * @brief @ref HanjaList가 가지고 있는 아이템의 갯수를 구하는 함수 + */ int hanja_list_get_size(const HanjaList *list) { @@ -472,6 +670,22 @@ hanja_list_get_size(const HanjaList *list) return 0; } +/** + * @ingroup hanjadictionary + * @brief @ref HanjaList가 생성될때 검색함수에서 사용한 키를 구하는 함수 + * @return @ref HanjaList의 key 스트링 + * + * 한자 사전 검색 함수로 HanjaList를 생성하면 HanjaList는 그 검색할때 사용한 + * 키를 기억하고 있다. 이 값을 확인할때 사용한다. + * 주의할 점은, 각 Hanja 아이템들은 각각의 키를 가지고 있지만, 이것이 + * 반드시 @ref HanjaList와 일치하지는 않는다는 것이다. + * 검색할 당시에 사용한 함수가 prefix나 suffix계열이면 더 짧은 키로도 + * 검색하기 때문에 @ref HanjaList의 키와 검색 결과의 키와 다른 것들도 + * 가지고 있게 된다. + * + * 리턴된 스트링 포인터는 @ref HanjaList에서 관리하는 스트링으로 + * 수정하거나 free해서는 안된다. + */ const char* hanja_list_get_key(const HanjaList *list) { @@ -480,6 +694,35 @@ hanja_list_get_key(const HanjaList *list) return NULL; } +/** + * @ingroup hanjadictionary + * @brief @ref HanjaList 의 n번째 @ref Hanja 아이템의 포인터를 구하는 함수 + * @param list @ref HanjaList를 가리키는 포인터 + * @param n 참조할 아이템의 인덱스 + * @return @ref Hanja를 가리키는 포인터 + * + * 이 함수는 @a list가 가리키는 @ref HanjaList의 n번째 @ref Hanja 오브젝트를 + * 가리키는 포인터를 리턴한다. + * @ref HanjaList 의 각 아이템은 정수형 인덱스로 각각 참조할 수 있다. + * @ref HanjaList 가 가진 엔트리 갯수를 넘어서는 인덱스를 주면 NULL을 리턴한다. + * 리턴된 @ref Hanja 오브젝트는 @ref HanjaList가 관리하는 오브젝트로 free하거나 + * 수정해서는 안된다. + * + * 다음의 예제는 list로 주어진 @ref HanjaList 의 모든 값을 프린트 하는 + * 코드다. + * + * @code + * int i; + * int n = hanja_list_get_size(list); + * for (i = 0; i < n; i++) { + * Hanja* hanja = hanja_list_get_nth(i); + * const char* value = hanja_get_value(hanja); + * printf("Hanja: %s\n", value); + * // 또는 hanja에서 다른 정보를 참조하거나 + * // 다른 작업을 할 수도 있다. + * } + * @endcode + */ const Hanja* hanja_list_get_nth(const HanjaList *list, unsigned int n) { @@ -490,6 +733,13 @@ hanja_list_get_nth(const HanjaList *list, unsigned int n) return NULL; } +/** + * @ingroup hanjadictionary + * @brief @ref HanjaList 의 n번째 아이템의 키를 구하는 함수 + * @return n번째 아이템의 키, UTF-8 + * + * HanjaList_get_nth()의 convenient 함수 + */ const char* hanja_list_get_nth_key(const HanjaList *list, unsigned int n) { @@ -497,6 +747,13 @@ hanja_list_get_nth_key(const HanjaList *list, unsigned int n) return hanja_get_key(hanja); } +/** + * @ingroup hanjadictionary + * @brief @ref HanjaList의 n번째 아이템의 값를 구하는 함수 + * @return n번째 아이템의 값(value), UTF-8 + * + * HanjaList_get_nth()의 convenient 함수 + */ const char* hanja_list_get_nth_value(const HanjaList *list, unsigned int n) { @@ -504,6 +761,13 @@ hanja_list_get_nth_value(const HanjaList *list, unsigned int n) return hanja_get_value(hanja); } +/** + * @ingroup hanjadictionary + * @brief @ref HanjaList의 n번째 아이템의 설명을 구하는 함수 + * @return n번째 아이템의 설명(comment), UTF-8 + * + * HanjaList_get_nth()의 convenient 함수 + */ const char* hanja_list_get_nth_comment(const HanjaList *list, unsigned int n) { @@ -511,6 +775,14 @@ hanja_list_get_nth_comment(const HanjaList *list, unsigned int n) return hanja_get_comment(hanja); } +/** + * @ingroup hanjadictionary + * @brief 한자 사전 검색 함수가 리턴한 결과를 free하는 함수 + * @param list free할 @ref HanjaList + * + * libhangul의 모든 한자 사전 검색 루틴이 리턴한 결과는 반드시 + * 이 함수로 free해야 한다. + */ void hanja_list_delete(HanjaList *list) { @@ -587,4 +859,3 @@ hanja_unified_form(ucschar* str, size_t n) return nconverted; } - |