upgrade to libhangul 0.10.0
authorJihoon Kim <jihoon48.kim@samsung.com>
Mon, 4 Apr 2011 05:05:01 +0000 (14:05 +0900)
committerJi-hoon Lee <dalton.lee@samsung.com>
Tue, 21 Aug 2012 08:29:52 +0000 (17:29 +0900)
Change-Id: I5161d2d9213c94e99a44f13e4cd82c1d835d9553

34 files changed:
ChangeLog
Makefile.am
NEWS
README [changed mode: 0755->0644]
bindings/Makefile.am [deleted file]
bindings/Makefile.in [deleted file]
bindings/python/Makefile [deleted file]
bindings/python/pyhangul.c [deleted file]
bindings/python/setup.py [deleted file]
bindings/python/test_pyhangul.py [deleted file]
bindings/ruby/extconf.rb [deleted file]
bindings/ruby/hangul.c [deleted file]
bindings/ruby/test-hangul.rb [deleted file]
configure.ac
data/hanja/hanja.txt [changed mode: 0755->0644]
debian/changelog
debian/control
debian/libhangul-dev.install
debian/libhangul0-data.install [new file with mode: 0644]
debian/libhangul0.install
debian/rules
debian/watch [new file with mode: 0644]
doc/Doxyfile.in [new file with mode: 0644]
doc/Makefile [new file with mode: 0644]
doc/mainpage.dox [new file with mode: 0644]
hangul/hangul.h [changed mode: 0755->0644]
hangul/hangulctype.c [changed mode: 0755->0644]
hangul/hangulinputcontext.c [changed mode: 0755->0644]
hangul/hangulkeyboard.h [changed mode: 0755->0644]
hangul/hanja.c [changed mode: 0755->0644]
test/Makefile.am
test/hangul.c [changed mode: 0755->0644]
test/hanja.c [changed mode: 0755->0644]
test/test.c [new file with mode: 0644]

index d94c5d647813e0165b77ade52c5783963aed476a..1407e70064259c8eab479c869661d06303f11ff7 100755 (executable)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,513 @@
+------------------------------------------------------------------------
+r212 | krisna | 2009-10-31 14:32:09 +0900 (Sat, 31 Oct 2009) | 3 lines
+Changed paths:
+   M /libhangul/trunk/configure.ac
+
+release 0.0.10
+ * update library revision
+
+------------------------------------------------------------------------
+r211 | krisna | 2009-10-31 14:29:52 +0900 (Sat, 31 Oct 2009) | 2 lines
+Changed paths:
+   M /libhangul/trunk/NEWS
+   M /libhangul/trunk/README
+
+문서 갱신
+
+------------------------------------------------------------------------
+r210 | krisna | 2009-10-31 14:28:53 +0900 (Sat, 31 Oct 2009) | 2 lines
+Changed paths:
+   M /libhangul/trunk/hangul/hangulctype.c
+   M /libhangul/trunk/hangul/hangulinputcontext.c
+   M /libhangul/trunk/hangul/hanja.c
+
+카피라이트 연도 갱신
+
+------------------------------------------------------------------------
+r209 | krisna | 2009-10-31 14:12:54 +0900 (Sat, 31 Oct 2009) | 2 lines
+Changed paths:
+   M /libhangul/trunk/doc/Doxyfile.in
+
+기본 생성 문서를 영문대신 한국어로 생성하도록 바꿈
+
+------------------------------------------------------------------------
+r208 | krisna | 2009-10-31 14:12:35 +0900 (Sat, 31 Oct 2009) | 3 lines
+Changed paths:
+   M /libhangul/trunk/doc/Makefile
+
+document를 kldp.net에 업로드하는 룰 추가
+기타 사용할 타겟 추가
+
+------------------------------------------------------------------------
+r207 | krisna | 2009-10-31 14:00:56 +0900 (Sat, 31 Oct 2009) | 4 lines
+Changed paths:
+   M /libhangul/trunk/doc/mainpage.dox
+
+문서 업데이트:
+ * mainpage는 web page의 표지로 사용하므로 경어체로 다시 씀
+ * 몇가지 항목 더 추가
+
+------------------------------------------------------------------------
+r206 | krisna | 2009-10-29 23:22:15 +0900 (Thu, 29 Oct 2009) | 5 lines
+Changed paths:
+   D /libhangul/trunk/Doxyfile
+   M /libhangul/trunk/Makefile.am
+   M /libhangul/trunk/configure.ac
+   A /libhangul/trunk/doc
+   A /libhangul/trunk/doc/Doxyfile.in (from /libhangul/trunk/Doxyfile:204)
+   A /libhangul/trunk/doc/Makefile
+   A /libhangul/trunk/doc/mainpage.dox
+
+문서화 
+ * doxygen 관련 파일은 doc 디렉토리로 옮김
+ * doc 디렉토리에 따로 Makefile을 두어 관리함
+ * Doxyfile에 버젼 정보가 configure 스크립드로 자동 갱신할 수 있도록 수정
+
+------------------------------------------------------------------------
+r205 | krisna | 2009-10-29 23:11:42 +0900 (Thu, 29 Oct 2009) | 2 lines
+Changed paths:
+   M /libhangul/trunk/hangul/hangulctype.c
+   M /libhangul/trunk/hangul/hangulinputcontext.c
+   M /libhangul/trunk/hangul/hanja.c
+
+libhangul의 API 문서 작성
+
+------------------------------------------------------------------------
+r204 | krisna | 2009-10-20 22:06:55 +0900 (Tue, 20 Oct 2009) | 4 lines
+Changed paths:
+   M /libhangul/trunk/hangul/hangul.h
+
+hangul_ic_dvorak_to_qwerty()는 더 이상 제공하지 않는다:
+ * dvorak을 qwerty로 매핑하는 것은 한글의 영역이 아니므로
+   각 입력기에서 구현하는 것으로 한다.
+
+------------------------------------------------------------------------
+r203 | krisna | 2009-10-18 23:24:45 +0900 (Sun, 18 Oct 2009) | 3 lines
+Changed paths:
+   M /libhangul/trunk/hangul/hangulctype.c
+
+hangul_jamo_to_cjamo() 함수를 conjoinable jamo만 아니라
+모든 자모 영역(Unicode 5.2에서 추가된 것 포함)에 대해서 작동하도록 확장함
+
+------------------------------------------------------------------------
+r202 | krisna | 2009-10-18 23:21:21 +0900 (Sun, 18 Oct 2009) | 2 lines
+Changed paths:
+   M /libhangul/trunk/hangul/hangul.h
+   M /libhangul/trunk/hangul/hangulinputcontext.c
+   M /libhangul/trunk/test/hangul.c
+
+deprecate된 함수를 사용하지 않음
+
+------------------------------------------------------------------------
+r201 | krisna | 2009-10-17 22:42:45 +0900 (Sat, 17 Oct 2009) | 6 lines
+Changed paths:
+   M /libhangul/trunk/hangul/hangulctype.c
+
+Unicode 5.2 지원
+ * 확장된 자모 영역을 적용하여 ctype 관련 함수를 업데이트함
+   0x1100의 추가된 영역과 Jamo Extended A, Jamo Extended B 추가
+   코드값이 자모, 초중성 코드인지 확인하는 함수들의 구현을 
+   수정하여 Unicode 5.2에서 추가된 영역도 인식하도록 함
+
+------------------------------------------------------------------------
+r200 | krisna | 2009-10-17 21:35:26 +0900 (Sat, 17 Oct 2009) | 3 lines
+Changed paths:
+   M /libhangul/trunk/hangul/hangul.h
+   M /libhangul/trunk/hangul/hangulctype.c
+
+jaso 대신 jamo를 사용한다.
+따라서 jaso를 사용한 함수는 앞으로 지원하지 않는다.
+
+------------------------------------------------------------------------
+r199 | krisna | 2009-10-16 22:41:41 +0900 (Fri, 16 Oct 2009) | 7 lines
+Changed paths:
+   M /libhangul/trunk/hangul/hangul.h
+   M /libhangul/trunk/hangul/hangulinputcontext.c
+   M /libhangul/trunk/hangul/hangulkeyboard.h
+   M /libhangul/trunk/test/test.c
+
+로마자 구현
+ * 로마자 입력 방식 구현
+ * 로마자 입력 방식 테스트 코드 구현
+ * backspace에서 stack이 바닥나면 초중성 코드를 모두 지운다.
+   로마자 입력방식에서 임의로 추가된 중성 코드가 backspace 입력될때
+   같이 지워지기 위한 구현
+
+------------------------------------------------------------------------
+r198 | krisna | 2009-09-03 23:15:53 +0900 (Thu, 03 Sep 2009) | 3 lines
+Changed paths:
+   M /libhangul/trunk/hangul/hangul.h
+
+불필요한 함수 선언 제거
+참고: http://lists.kldp.net/pipermail/hangul-hackers/2009-September/000392.html
+
+------------------------------------------------------------------------
+r197 | exman | 2009-09-03 21:47:26 +0900 (Thu, 03 Sep 2009) | 1 line
+Changed paths:
+   A /libhangul/trunk/bindings/python_swig
+   A /libhangul/trunk/bindings/python_swig/Makefile
+   A /libhangul/trunk/bindings/python_swig/hangul.i
+   A /libhangul/trunk/bindings/python_swig/test_hangul.py
+   A /libhangul/trunk/bindings/python_swig/test_hanja.py
+   A /libhangul/trunk/bindings/python_swig/valgrind-test.sh
+
+add swig interface for python and test codes
+------------------------------------------------------------------------
+r196 | krisna | 2008-12-22 23:38:20 +0900 (Mon, 22 Dec 2008) | 3 lines
+Changed paths:
+   M /libhangul/trunk/hangul/Makefile.am
+
+hanja.bin 파일을 사용하던 룰을 hanja.txt로 변경하면서 발생한 실수 수정
+버그: #195
+
+------------------------------------------------------------------------
+r195 | krisna | 2008-12-22 23:33:22 +0900 (Mon, 22 Dec 2008) | 4 lines
+Changed paths:
+   M /libhangul/trunk/data/hanja/Makefile.am
+
+hanja.txt 설치 디렉토리를 $(datadir)로 바꿈
+hanja.bin 파일 설치 룰을 수정하는 과정에서 발생한 실수
+버그: #305209
+
+------------------------------------------------------------------------
+r193 | krisna | 2008-12-20 23:13:39 +0900 (Sat, 20 Dec 2008) | 2 lines
+Changed paths:
+   M /libhangul/trunk/configure.ac
+
+release 0.0.9
+
+------------------------------------------------------------------------
+r192 | krisna | 2008-12-20 23:07:44 +0900 (Sat, 20 Dec 2008) | 2 lines
+Changed paths:
+   M /libhangul/trunk/NEWS
+
+문서 업데이트
+
+------------------------------------------------------------------------
+r191 | krisna | 2008-12-20 23:03:27 +0900 (Sat, 20 Dec 2008) | 3 lines
+Changed paths:
+   M /libhangul/trunk/data/hanja/Makefile.am
+
+한자 데이터 파일 패키징 룰 수정:
+ * 예전 hanja.bin 파일 관련 부분 제거
+
+------------------------------------------------------------------------
+r190 | krisna | 2008-12-20 20:56:45 +0900 (Sat, 20 Dec 2008) | 5 lines
+Changed paths:
+   M /libhangul/trunk/configure.ac
+   M /libhangul/trunk/test/Makefile.am
+   A /libhangul/trunk/test/test.c
+
+unit test 코드 적용:
+ * check 라이브러리를 이용하여 구현
+ * check 라이브러리가 없어도 libhangul을 빌드하는 데는 문제 없게 설정
+ * 시범삼아 syllable iterator 코드의 테스트 코드 작성
+
+------------------------------------------------------------------------
+r189 | krisna | 2008-12-20 20:53:05 +0900 (Sat, 20 Dec 2008) | 5 lines
+Changed paths:
+   M /libhangul/trunk/hangul/hangul.h
+   M /libhangul/trunk/hangul/hangulctype.c
+
+자모 스트링을 음절 단위로 iterate하는 함수 구현:
+ * hangul_syllable_iterator_prev()
+ * hangul_syllable_iterator_next()
+ * 음절을 구분하는 단위에 방점이나 combining char도 포함
+
+------------------------------------------------------------------------
+r188 | krisna | 2008-11-11 22:47:54 +0900 (Tue, 11 Nov 2008) | 10 lines
+Changed paths:
+   M /libhangul/trunk/Makefile.am
+   M /libhangul/trunk/configure.ac
+   M /libhangul/trunk/data/hanja/Makefile.am
+   M /libhangul/trunk/hangul/Makefile.am
+   M /libhangul/trunk/hangul/hanja.c
+
+한자 데이터를 관리하는 HanjaTable의 작동 방식을 개선:
+ * 기존에 한자 데이터를 binary로 변환하여 로딩하던 코드를 제거
+ * text 파일에 대한 index만 가지고 있으면서 요청시에 매번 파일을
+   읽어서 데이터를 리턴하는 방식으로 구현함
+ * 예전 방식은 메모리를 많이 차지하여 사용하지 않음
+ * 파일에서 매번 읽는 방식도 그리 속도가 나쁘지 않으므로 사용하기로 하였음
+ * hanja.txt 를 바이너리 포맷으로 변환하던 툴 제거
+ * hanja.bin 대신 hanja.txt 파일을 설치
+ * 참조: http://lists.kldp.net/pipermail/hangul-hackers/2008-November/000385.html
+
+------------------------------------------------------------------------
+r187 | krisna | 2008-11-06 23:44:48 +0900 (Thu, 06 Nov 2008) | 6 lines
+Changed paths:
+   M /libhangul/trunk/hangul/hangulinputcontext.c
+
+hangul_ic_backspace() 에서도 preedit_string과 commit_string을 초기화 함:
+ libhangul의 사용자가 hangul_ic_backspace() 함수를 콜한 후에 preedit string과 
+ commit string이 유효한지 확인하여 처리하도록 코딩할 수 있다.
+ 그리고 모든 키 처리 함수를 호출한후 preedit string과 commit string을 
+ 확인할수 있도록 하기 위해서는 위 과정이 필요하다.
+
+------------------------------------------------------------------------
+r186 | wkpark | 2008-05-10 06:46:48 +0900 (Sat, 10 May 2008) | 2 lines
+Changed paths:
+   M /libhangul/trunk/configure.ac
+
+test for svn check
+
+------------------------------------------------------------------------
+r185 | wkpark | 2008-05-06 19:55:22 +0900 (Tue, 06 May 2008) | 2 lines
+Changed paths:
+   M /libhangul/trunk/hangul/hanja.c
+
+small fix
+
+------------------------------------------------------------------------
+r184 | krisna | 2008-05-06 00:05:11 +0900 (Tue, 06 May 2008) | 3 lines
+Changed paths:
+   M /libhangul/trunk/autogen.sh
+
+which 로 libtoolize 인지 glibtoolize인지 확인함
+참고: #304873
+
+------------------------------------------------------------------------
+r183 | krisna | 2008-05-05 01:46:32 +0900 (Mon, 05 May 2008) | 5 lines
+Changed paths:
+   M /libhangul/trunk/data/hanja/Makefile.am
+
+hanja.txt 파일을 더이상 install 하지 않음
+참조: #304842
+ http://kldp.net/tracker/index.php?func=detail&aid=304842&group_id=362&atid=350420
+ http://lists.kldp.net/pipermail/hangul-hackers/2008-April/000335.html
+
+------------------------------------------------------------------------
+r182 | krisna | 2008-05-04 23:28:05 +0900 (Sun, 04 May 2008) | 2 lines
+Changed paths:
+   M /libhangul/trunk/hangul/hangul.h
+   M /libhangul/trunk/hangul/hanja.c
+
+hanja_table_match_exact() 구현
+
+------------------------------------------------------------------------
+r181 | krisna | 2008-05-03 17:09:13 +0900 (Sat, 03 May 2008) | 3 lines
+Changed paths:
+   M /libhangul/trunk/hangul/hangulctype.c
+
+hangul_syllable_len(), hangul_jamos_to_syllables()에서 
+마지막 글자가 0으로 끝나지 않을 경우 제대로 변환되지 않는 문제 수정
+
+------------------------------------------------------------------------
+r180 | krisna | 2008-05-03 14:05:59 +0900 (Sat, 03 May 2008) | 3 lines
+Changed paths:
+   M /libhangul/trunk/autogen.sh
+
+ChangeLog가 없을 경우 처리
+libtoolize가 없는 경우 glibtoolize를 사용하도록 처리
+
+------------------------------------------------------------------------
+r179 | krisna | 2008-04-22 10:08:01 +0900 (Tue, 22 Apr 2008) | 2 lines
+Changed paths:
+   M /libhangul/trunk/hangul/hangul.h
+
+hanja_list_get_nth_key() 선언 추가
+
+------------------------------------------------------------------------
+r177 | krisna | 2008-04-20 16:22:53 +0900 (Sun, 20 Apr 2008) | 2 lines
+Changed paths:
+   M /libhangul/trunk/configure.ac
+
+release 0.0.8
+
+------------------------------------------------------------------------
+r176 | krisna | 2008-04-20 16:05:58 +0900 (Sun, 20 Apr 2008) | 2 lines
+Changed paths:
+   M /libhangul/trunk/Makefile.am
+
+test 디렉토리 다시 추가
+
+------------------------------------------------------------------------
+r175 | krisna | 2008-04-20 16:01:14 +0900 (Sun, 20 Apr 2008) | 2 lines
+Changed paths:
+   M /libhangul/trunk/NEWS
+   M /libhangul/trunk/README
+
+update document 
+
+------------------------------------------------------------------------
+r174 | krisna | 2008-04-20 16:00:22 +0900 (Sun, 20 Apr 2008) | 2 lines
+Changed paths:
+   M /libhangul/trunk/Makefile.am
+
+do not build test directory
+
+------------------------------------------------------------------------
+r173 | krisna | 2008-04-20 15:48:59 +0900 (Sun, 20 Apr 2008) | 8 lines
+Changed paths:
+   M /libhangul/trunk/hangul/hangulinputcontext.c
+
+hangul input context 개선:
+ * hangul_ic_select_keyboard() 함수에서 output mode 초기화 함
+ * HangulInputContext::use_jamo_mode_only 값에 따라서 
+   output mode 설정 기능이 동작하도록 함
+ * 세벌식 옛글 자판을 선택했다가 현대글자판으로 바꾸면 jamo output 모드 설정이
+   남아있던 문제 수정
+ * libhangul 버그: #304765
+
+------------------------------------------------------------------------
+r172 | krisna | 2008-04-20 15:09:08 +0900 (Sun, 20 Apr 2008) | 4 lines
+Changed paths:
+   M /libhangul/trunk/hangul/hangul.h
+   M /libhangul/trunk/hangul/hangulctype.c
+
+자모 -> 음절 변환을 위한 함수 추가:
+ * hangul_syllable_len(): 한 음절의 길이를 측정
+ * hangul_jamos_to_syllables(): 자모형을 음절형으로 변환
+
+------------------------------------------------------------------------
+r171 | krisna | 2008-03-11 20:17:15 +0900 (Tue, 11 Mar 2008) | 2 lines
+Changed paths:
+   M /libhangul/trunk/data/hanja/Makefile.am
+
+hanja.bin 빌드 룰 개선 (clean 처리)
+
+------------------------------------------------------------------------
+r170 | krisna | 2008-03-11 16:17:58 +0900 (Tue, 11 Mar 2008) | 3 lines
+Changed paths:
+   M /libhangul/trunk/hangul/hanja.c
+
+malloc/realloc 하기 전에 크기 확인 코드 개선
+hanja_table_match_prefix()에서 strdup()의 리턴값 확인
+
+------------------------------------------------------------------------
+r169 | krisna | 2008-03-11 11:53:26 +0900 (Tue, 11 Mar 2008) | 2 lines
+Changed paths:
+   M /libhangul/trunk/data/hanja/Makefile.am
+   M /libhangul/trunk/hangul/Makefile.am
+
+한자 사전 바이너리 파일의 위치를 $(libdir)/libhangul/hanja/로 옮김
+
+------------------------------------------------------------------------
+r168 | krisna | 2008-03-11 11:52:11 +0900 (Tue, 11 Mar 2008) | 2 lines
+Changed paths:
+   M /libhangul/trunk/data/hanja/hanja.txt
+
+중복된 내용 삭제: 동:中洞:지명
+
+------------------------------------------------------------------------
+r167 | krisna | 2008-02-24 11:46:04 +0900 (Sun, 24 Feb 2008) | 2 lines
+Changed paths:
+   M /libhangul/trunk/data/hanja
+
+ignore list 업데이트
+
+------------------------------------------------------------------------
+r166 | krisna | 2008-02-24 11:44:55 +0900 (Sun, 24 Feb 2008) | 2 lines
+Changed paths:
+   A /libhangul/trunk/data/hanja/compat-table.txt
+
+merge.py에서 사용하는 compatibility hanja 관련 테이터 파일 추가
+
+------------------------------------------------------------------------
+r165 | krisna | 2008-02-24 11:12:01 +0900 (Sun, 24 Feb 2008) | 2 lines
+Changed paths:
+   M /libhangul/trunk/Makefile.am
+   M /libhangul/trunk/configure.ac
+
+bindings 디렉토리를 tarball 패키지에 포함하지 않음 
+
+------------------------------------------------------------------------
+r164 | krisna | 2008-02-24 11:02:39 +0900 (Sun, 24 Feb 2008) | 2 lines
+Changed paths:
+   M /libhangul/trunk/hangul/hanja.c
+
+HanjaList와 PtrVector의 크기의 한계값을 SIZE_MAX를 사용하여 체크
+
+------------------------------------------------------------------------
+r163 | krisna | 2008-02-24 10:52:22 +0900 (Sun, 24 Feb 2008) | 2 lines
+Changed paths:
+   M /libhangul/trunk/hangul/hanja.c
+
+HanjaList, PtrVector는 UINT_MAX를 넘지 않는 범위에서 사용하도록 한다.
+
+------------------------------------------------------------------------
+r162 | krisna | 2008-02-24 10:43:55 +0900 (Sun, 24 Feb 2008) | 2 lines
+Changed paths:
+   M /libhangul/trunk/hangul/hanja.c
+
+mmap system call이 없는 시스템을 위한 코드 추가
+
+------------------------------------------------------------------------
+r161 | krisna | 2008-02-24 02:45:53 +0900 (Sun, 24 Feb 2008) | 2 lines
+Changed paths:
+   M /libhangul/trunk/hangul/hanja.c
+
+디버깅 메시지 출력 루틴 제거
+
+------------------------------------------------------------------------
+r160 | krisna | 2008-02-24 02:45:13 +0900 (Sun, 24 Feb 2008) | 4 lines
+Changed paths:
+   M /libhangul/trunk/hangul/hanja.c
+
+한자 검색 루틴에서 null 포인터 확인:
+ * hanja_table_match_prefix(), hanja_table_match_suffix()에서 table이 
+   null이면 검색하지 않음
+
+------------------------------------------------------------------------
+r159 | krisna | 2008-02-24 02:30:34 +0900 (Sun, 24 Feb 2008) | 3 lines
+Changed paths:
+   M /libhangul/trunk/test/hanja.c
+
+테스트 코드 수정:
+ * hanja.c에서 검색 결과 출력 포맷 수정
+
+------------------------------------------------------------------------
+r158 | krisna | 2008-02-24 02:29:23 +0900 (Sun, 24 Feb 2008) | 12 lines
+Changed paths:
+   M /libhangul/trunk/Makefile.am
+   M /libhangul/trunk/configure.ac
+   M /libhangul/trunk/data/hanja/Makefile.am
+   M /libhangul/trunk/hangul/Makefile.am
+   M /libhangul/trunk/hangul/hangul.h
+   M /libhangul/trunk/hangul/hanja.c
+   A /libhangul/trunk/tools
+   A /libhangul/trunk/tools/Makefile.am
+   A /libhangul/trunk/tools/hanjac.c
+
+한자 사전 파일을 바이너리 형태로 사용하는 기능 구현:
+ * 내부적으로 mmap을 이용하여 로딩, 메모리 사용량을 줄임
+ * txt 버젼은 vector로 구현, 더이상 slist를 사용하지 않음
+ * hanja.txt파일을 hanja.bin 형태로 변환하여 사용함
+ * 파일 포맷 변환을 위한 API, hanja_table_txt_to_bin() 추가
+ * tools 디렉토리 추가
+ * 파일 포맷 변환을 위해 hanjac라는 도구를 제공
+ * 기본 한자 사전 파일을 hanja.txt에서 hanja.bin으로 변경
+
+새로운 api 추가
+ * hanja_list_get_nth_key()
+
+------------------------------------------------------------------------
+r157 | krisna | 2008-02-24 01:59:17 +0900 (Sun, 24 Feb 2008) | 4 lines
+Changed paths:
+   M /libhangul/trunk/data/hanja/hanja.txt
+
+인코딩에 문제가 생겨 잘못 입력된 한자어를 바로잡음:
+ * 국어사전을 참고하여 올라 있는 단어는 찾아 바로잡음
+ * 사전에 올라있지 않은 단어는 삭제함
+
+------------------------------------------------------------------------
+r156 | krisna | 2008-02-06 01:00:21 +0900 (Wed, 06 Feb 2008) | 6 lines
+Changed paths:
+   M /libhangul/trunk/hangul/hangulinputcontext.c
+
+세벌식 옛글 처리 수정 (#304728)
+ * 옛글 자판에서는 자모(첫가끝)로 출력
+ * hangul_ic_flush() 함수에서도 output mode에 따른 처리
+ * 나비버그 #304727 참고:
+   http://kldp.net/tracker/?func=detail&atid=100275&aid=304727&group_id=275
+
+------------------------------------------------------------------------
+r155 | krisna | 2008-02-02 16:06:06 +0900 (Sat, 02 Feb 2008) | 2 lines
+Changed paths:
+   A /libhangul/trunk/hangul/hangulinternals.h
+
+libhangul내부적으로 사용할 hangulinternals.h 추가
+
 ------------------------------------------------------------------------
 r153 | krisna | 2008-01-31 23:43:19 +0900 (Thu, 31 Jan 2008) | 2 lines
 Changed paths:
index 6478f1af527bf1ace1cae2325e26882eda3abf5d..339e67d8a8d7188401bb609475e54a01ba7602d1 100755 (executable)
@@ -1,8 +1,13 @@
-SUBDIRS = hangul data bindings test
+SUBDIRS = hangul data test
 
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = libhangul.pc
 
+EXTRA_DIST = \
+    doc/Makefile \
+    doc/Doxyfile.in \
+    doc/mainpage.dox
+
 log:
        unset LC_ALL; \
        export LANG=C ; \
diff --git a/NEWS b/NEWS
index 249e8e52489f3ea93bff68d4a129a33a94bb293d..4a389cf420a01c9dd3530aec9a86c0c49f2d3376 100755 (executable)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,28 @@
+0.0.10
+ * implemented new logic romaja method
+ * updated to support the new Unicode standard 5.2
+ * updated API document
+ * fixed small bugs
+
+0.0.9
+ * updated hanja searching routine
+  - remove binary data file format code
+  - look up hanja.txt file everytime to reduce memory usage
+  - http://lists.kldp.net/pipermail/hangul-hackers/2008-November/000385.html
+ * added new API for syllable iteration
+ * fixed configure script bug on MacOSX (#304873)
+ * updated for imhangul
+
+0.0.8
+ * update hanja searching routine
+  - reduce memory usage on hanja searching
+  - use new binary data file format for hanja table
+ * update hanja.txt
+ * add new API to convert jamo string to syllable string(#304765)
+ * fix some yet hangul input routine(#304728)
+ * fix a bug on keyboard selection(#304765)
+ * remove python, ruby module
+
 0.0.7
  * update hanja.txt
    - added more word data
diff --git a/README b/README
old mode 100755 (executable)
new mode 100644 (file)
index 754b19a..4e13c22
--- a/README
+++ b/README
@@ -1,26 +1,23 @@
 libhangul
-한글 입력을 위한 루틴을 구현한 라이브러리입니다.
+A library to support hangul input method logic, hanja dictionary and small
+hangul character classification.
 
-빌드 방법:
-    $ ./configure
   $ make
-    # make install
+How to build
+ $ ./autogen.sh
$ ./configure
+ # make
 
-python 모듈 빌드 방법:
-    $ cd bindings/pyhangul
-    $ make
-    # make install
+Download:
+ * http://kldp.net/frs/?group_id=362
 
+Bug report:
+ * bug tracker: http://kldp.net/tracker/?group_id=362
 
-libhangul
-
-How to build:
-    $ ./autogen.sh
-    $ ./configure
-    $ make
+Mailing list
+ * mailing list: http://lists.kldp.net/mailman/listinfo/hangul-hackers
+ * mailing list archive: http://lists.kldp.net/pipermail/hangul-hackers/
 
-How to install python module 'pyhangul':
-    $ cd bindings/pyhangul
-    $ make
-    login as root
-    # make install
+Web sites
+ * Home page: http://hangul.kldp.net/
+ * Project page: http://kldp.net/projects/hangul/
+ * Wiki page: http://wiki.kldp.org/wiki.php/libhangul
diff --git a/bindings/Makefile.am b/bindings/Makefile.am
deleted file mode 100755 (executable)
index 4faf87b..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-EXTRA_DIST = \
-    python/test_pyhangul.py \
-    python/setup.py \
-    python/pyhangul.c \
-    python/Makefile \
-    ruby/hangul.c \
-    ruby/test-hangul.rb \
-    ruby/extconf.rb
diff --git a/bindings/Makefile.in b/bindings/Makefile.in
deleted file mode 100755 (executable)
index 32dc806..0000000
+++ /dev/null
@@ -1,332 +0,0 @@
-# Makefile.in generated by automake 1.10 from Makefile.am.
-# @configure_input@
-
-# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-# 2003, 2004, 2005, 2006  Free Software Foundation, Inc.
-# This Makefile.in is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
-# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE.
-
-@SET_MAKE@
-VPATH = @srcdir@
-pkgdatadir = $(datadir)/@PACKAGE@
-pkglibdir = $(libdir)/@PACKAGE@
-pkgincludedir = $(includedir)/@PACKAGE@
-am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
-install_sh_DATA = $(install_sh) -c -m 644
-install_sh_PROGRAM = $(install_sh) -c
-install_sh_SCRIPT = $(install_sh) -c
-INSTALL_HEADER = $(INSTALL_DATA)
-transform = $(program_transform_name)
-NORMAL_INSTALL = :
-PRE_INSTALL = :
-POST_INSTALL = :
-NORMAL_UNINSTALL = :
-PRE_UNINSTALL = :
-POST_UNINSTALL = :
-build_triplet = @build@
-host_triplet = @host@
-subdir = bindings
-DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
-ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/configure.ac
-am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
-       $(ACLOCAL_M4)
-mkinstalldirs = $(install_sh) -d
-CONFIG_HEADER = $(top_builddir)/config.h
-CONFIG_CLEAN_FILES =
-SOURCES =
-DIST_SOURCES =
-DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
-ACLOCAL = @ACLOCAL@
-AMTAR = @AMTAR@
-AR = @AR@
-AUTOCONF = @AUTOCONF@
-AUTOHEADER = @AUTOHEADER@
-AUTOMAKE = @AUTOMAKE@
-AWK = @AWK@
-CC = @CC@
-CCDEPMODE = @CCDEPMODE@
-CFLAGS = @CFLAGS@
-CPP = @CPP@
-CPPFLAGS = @CPPFLAGS@
-CXX = @CXX@
-CXXCPP = @CXXCPP@
-CXXDEPMODE = @CXXDEPMODE@
-CXXFLAGS = @CXXFLAGS@
-CYGPATH_W = @CYGPATH_W@
-DEFS = @DEFS@
-DEPDIR = @DEPDIR@
-ECHO = @ECHO@
-ECHO_C = @ECHO_C@
-ECHO_N = @ECHO_N@
-ECHO_T = @ECHO_T@
-EGREP = @EGREP@
-EXEEXT = @EXEEXT@
-F77 = @F77@
-FFLAGS = @FFLAGS@
-GREP = @GREP@
-INSTALL = @INSTALL@
-INSTALL_DATA = @INSTALL_DATA@
-INSTALL_PROGRAM = @INSTALL_PROGRAM@
-INSTALL_SCRIPT = @INSTALL_SCRIPT@
-INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
-LDFLAGS = @LDFLAGS@
-LIBHANGUL_AGE = @LIBHANGUL_AGE@
-LIBHANGUL_CURRENT = @LIBHANGUL_CURRENT@
-LIBHANGUL_REVISION = @LIBHANGUL_REVISION@
-LIBOBJS = @LIBOBJS@
-LIBS = @LIBS@
-LIBTOOL = @LIBTOOL@
-LN_S = @LN_S@
-LTLIBOBJS = @LTLIBOBJS@
-MAKEINFO = @MAKEINFO@
-MKDIR_P = @MKDIR_P@
-OBJEXT = @OBJEXT@
-PACKAGE = @PACKAGE@
-PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
-PACKAGE_NAME = @PACKAGE_NAME@
-PACKAGE_STRING = @PACKAGE_STRING@
-PACKAGE_TARNAME = @PACKAGE_TARNAME@
-PACKAGE_VERSION = @PACKAGE_VERSION@
-PATH_SEPARATOR = @PATH_SEPARATOR@
-RANLIB = @RANLIB@
-SED = @SED@
-SET_MAKE = @SET_MAKE@
-SHELL = @SHELL@
-STRIP = @STRIP@
-VERSION = @VERSION@
-abs_builddir = @abs_builddir@
-abs_srcdir = @abs_srcdir@
-abs_top_builddir = @abs_top_builddir@
-abs_top_srcdir = @abs_top_srcdir@
-ac_ct_CC = @ac_ct_CC@
-ac_ct_CXX = @ac_ct_CXX@
-ac_ct_F77 = @ac_ct_F77@
-am__include = @am__include@
-am__leading_dot = @am__leading_dot@
-am__quote = @am__quote@
-am__tar = @am__tar@
-am__untar = @am__untar@
-bindir = @bindir@
-build = @build@
-build_alias = @build_alias@
-build_cpu = @build_cpu@
-build_os = @build_os@
-build_vendor = @build_vendor@
-builddir = @builddir@
-datadir = @datadir@
-datarootdir = @datarootdir@
-docdir = @docdir@
-dvidir = @dvidir@
-exec_prefix = @exec_prefix@
-host = @host@
-host_alias = @host_alias@
-host_cpu = @host_cpu@
-host_os = @host_os@
-host_vendor = @host_vendor@
-htmldir = @htmldir@
-includedir = @includedir@
-infodir = @infodir@
-install_sh = @install_sh@
-libdir = @libdir@
-libexecdir = @libexecdir@
-localedir = @localedir@
-localstatedir = @localstatedir@
-mandir = @mandir@
-mkdir_p = @mkdir_p@
-oldincludedir = @oldincludedir@
-pdfdir = @pdfdir@
-prefix = @prefix@
-program_transform_name = @program_transform_name@
-psdir = @psdir@
-sbindir = @sbindir@
-sharedstatedir = @sharedstatedir@
-srcdir = @srcdir@
-sysconfdir = @sysconfdir@
-target_alias = @target_alias@
-top_builddir = @top_builddir@
-top_srcdir = @top_srcdir@
-EXTRA_DIST = \
-    python/test_pyhangul.py \
-    python/setup.py \
-    python/pyhangul.c \
-    python/Makefile \
-    ruby/hangul.c \
-    ruby/test-hangul.rb \
-    ruby/extconf.rb
-
-all: all-am
-
-.SUFFIXES:
-$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
-       @for dep in $?; do \
-         case '$(am__configure_deps)' in \
-           *$$dep*) \
-             cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
-               && exit 0; \
-             exit 1;; \
-         esac; \
-       done; \
-       echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu  bindings/Makefile'; \
-       cd $(top_srcdir) && \
-         $(AUTOMAKE) --gnu  bindings/Makefile
-.PRECIOUS: Makefile
-Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
-       @case '$?' in \
-         *config.status*) \
-           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
-         *) \
-           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
-           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
-       esac;
-
-$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
-       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-
-$(top_srcdir)/configure:  $(am__configure_deps)
-       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
-       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-
-mostlyclean-libtool:
-       -rm -f *.lo
-
-clean-libtool:
-       -rm -rf .libs _libs
-tags: TAGS
-TAGS:
-
-ctags: CTAGS
-CTAGS:
-
-
-distdir: $(DISTFILES)
-       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
-       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
-       list='$(DISTFILES)'; \
-         dist_files=`for file in $$list; do echo $$file; done | \
-         sed -e "s|^$$srcdirstrip/||;t" \
-             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
-       case $$dist_files in \
-         */*) $(MKDIR_P) `echo "$$dist_files" | \
-                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
-                          sort -u` ;; \
-       esac; \
-       for file in $$dist_files; do \
-         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
-         if test -d $$d/$$file; then \
-           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
-           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
-             cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
-           fi; \
-           cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
-         else \
-           test -f $(distdir)/$$file \
-           || cp -p $$d/$$file $(distdir)/$$file \
-           || exit 1; \
-         fi; \
-       done
-check-am: all-am
-check: check-am
-all-am: Makefile
-installdirs:
-install: install-am
-install-exec: install-exec-am
-install-data: install-data-am
-uninstall: uninstall-am
-
-install-am: all-am
-       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
-
-installcheck: installcheck-am
-install-strip:
-       $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
-         install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
-         `test -z '$(STRIP)' || \
-           echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
-mostlyclean-generic:
-
-clean-generic:
-
-distclean-generic:
-       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-
-maintainer-clean-generic:
-       @echo "This command is intended for maintainers to use"
-       @echo "it deletes files that may require special tools to rebuild."
-clean: clean-am
-
-clean-am: clean-generic clean-libtool mostlyclean-am
-
-distclean: distclean-am
-       -rm -f Makefile
-distclean-am: clean-am distclean-generic
-
-dvi: dvi-am
-
-dvi-am:
-
-html: html-am
-
-info: info-am
-
-info-am:
-
-install-data-am:
-
-install-dvi: install-dvi-am
-
-install-exec-am:
-
-install-html: install-html-am
-
-install-info: install-info-am
-
-install-man:
-
-install-pdf: install-pdf-am
-
-install-ps: install-ps-am
-
-installcheck-am:
-
-maintainer-clean: maintainer-clean-am
-       -rm -f Makefile
-maintainer-clean-am: distclean-am maintainer-clean-generic
-
-mostlyclean: mostlyclean-am
-
-mostlyclean-am: mostlyclean-generic mostlyclean-libtool
-
-pdf: pdf-am
-
-pdf-am:
-
-ps: ps-am
-
-ps-am:
-
-uninstall-am:
-
-.MAKE: install-am install-strip
-
-.PHONY: all all-am check check-am clean clean-generic clean-libtool \
-       distclean distclean-generic distclean-libtool distdir dvi \
-       dvi-am html html-am info info-am install install-am \
-       install-data install-data-am install-dvi install-dvi-am \
-       install-exec install-exec-am install-html install-html-am \
-       install-info install-info-am install-man install-pdf \
-       install-pdf-am install-ps install-ps-am install-strip \
-       installcheck installcheck-am installdirs maintainer-clean \
-       maintainer-clean-generic mostlyclean mostlyclean-generic \
-       mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am
-
-# Tell versions [3.59,3.63) of GNU make to not export all variables.
-# Otherwise a system limit (for SysV at least) may be exceeded.
-.NOEXPORT:
diff --git a/bindings/python/Makefile b/bindings/python/Makefile
deleted file mode 100755 (executable)
index 1cfeda8..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-
-all:
-       python setup.py build
-
-clean:
-       rm -rf build
-
-install:
-       python setup.py install
diff --git a/bindings/python/pyhangul.c b/bindings/python/pyhangul.c
deleted file mode 100755 (executable)
index 0139376..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-#include <Python.h>
-
-#include <stdio.h>
-#include <unistd.h>
-
-#include <string.h>
-#include <stdlib.h>
-#include <alloca.h>
-
-#include <hangul.h>
-
-static PyObject *_pyhangul_error;
-
-/* User defined Object */
-typedef struct {
-    PyObject_HEAD
-} PY_HANGUL;
-
-typedef struct {
-    PyObject_HEAD
-
-    HangulInputContext *hic;
-} PY_HANGULIC;
-
-extern PyTypeObject PY_HANGULIC_Type;
-
-static int ucscharlen(const ucschar *str)
-{
-    const ucschar *end = str;
-    while (*end != 0)
-       end++;
-    return end - str;
-} 
-
-static PyObject *_create_ic(PY_HANGUL *self, PyObject *args)
-{ 
-    PY_HANGULIC *imObject;
-    const char* keyboard = NULL;
-
-    if(!PyArg_ParseTuple(args,"s",&keyboard)) {
-       PyErr_SetString(_pyhangul_error,
-                       "Usage: create_ic(keyboard)\n"
-                       "\tkeyboard: hangul2, hangul3{2,90,f,s}");
-       return NULL;
-    }
-
-    imObject = PyObject_NEW(PY_HANGULIC, &PY_HANGULIC_Type);
-    if(imObject == NULL) {
-       PyErr_SetString(_pyhangul_error,"Fail to create PY_HANGULIC Object");
-       return NULL;
-    }
-
-    imObject->hic = hangul_ic_new(keyboard);
-
-    return (PyObject *)imObject;
-}
-
-static PyMethodDef _pyhangul_methods[] = {
-    { "create_ic", (PyCFunction) _create_ic, METH_VARARGS, NULL },
-    { NULL,      NULL, 0, NULL } 
-};
-
-void inithangul(void)
-{
-    PyObject *m, *d;
-
-    m = Py_InitModule("hangul", _pyhangul_methods);
-
-    d = PyModule_GetDict(m);
-    _pyhangul_error = PyErr_NewException("_pyhangul.error", NULL, NULL);
-    PyDict_SetItemString(d, "error", _pyhangul_error);
-} 
-
-/* im's member function */
-static PyObject *_pyhangulic_process(PY_HANGULIC *self, PyObject *args)
-{
-    int ret;
-    int ascii; 
-
-    if(!PyArg_ParseTuple(args,"i", &ascii)) {
-       PyErr_SetString(_pyhangul_error,"Usage: process(ascii)");
-       return NULL;
-    }
-
-    ret = hangul_ic_process(self->hic, ascii);
-
-    return Py_BuildValue("i", ret);
-}
-
-static PyObject *_pyhangulic_reset(PY_HANGULIC *self, PyObject *args)
-{
-    hangul_ic_reset(self->hic);
-
-    return Py_None;
-}
-
-static PyObject *_pyhangulic_flush(PY_HANGULIC *self, PyObject *args)
-{
-#ifndef Py_UNICODE_WIDE
-    int i;
-    Py_UNICODE *buf;
-#endif /* !Py_UNICODE_WIDE */
-    int len;
-    const ucschar *str;
-
-    str = hangul_ic_flush(self->hic);
-    len = ucscharlen(str);
-
-#ifdef Py_UNICODE_WIDE
-    return PyUnicode_FromUnicode((Py_UNICODE*)str, len);
-#else  /* Py_UNICODE_WIDE */
-    buf = alloca(sizeof(Py_UNICODE) * len);
-    for (i = 0; i < len; i++)
-       buf[i] = str[i];
-    return PyUnicode_FromUnicode(buf, len);
-#endif /* Py_UNICODE_WIDE */
-}
-
-static PyObject *_pyhangulic_backspace(PY_HANGULIC *self, PyObject *args)
-{
-    int ret;
-
-    ret = hangul_ic_backspace(self->hic);
-
-    return Py_BuildValue("i", ret);
-}
-
-static PyObject *_pyhangulic_preedit_string(PY_HANGULIC *self, PyObject *args)
-{
-#ifndef Py_UNICODE_WIDE
-    int i;
-    Py_UNICODE *buf;
-#endif /* !Py_UNICODE_WIDE */
-    int len;
-    const ucschar *str;
-
-    str = hangul_ic_get_preedit_string(self->hic);
-    len = ucscharlen(str);
-
-#ifdef Py_UNICODE_WIDE
-    return PyUnicode_FromUnicode((Py_UNICODE*)str, len);
-#else  /* Py_UNICODE_WIDE */
-    buf = alloca(sizeof(Py_UNICODE) * len);
-    for (i = 0; i < len; i++)
-       buf[i] = str[i];
-    return PyUnicode_FromUnicode(buf, len);
-#endif /* Py_UNICODE_WIDE */
-}
-
-static PyObject *_pyhangulic_commit_string(PY_HANGULIC *self, PyObject *args)
-{
-#ifndef Py_UNICODE_WIDE
-    int i;
-    Py_UNICODE *buf;
-#endif /* !Py_UNICODE_WIDE */
-    int len;
-    const ucschar *str;
-
-    str = hangul_ic_get_commit_string(self->hic);
-    len = ucscharlen(str);
-
-#ifdef Py_UNICODE_WIDE
-    return PyUnicode_FromUnicode((Py_UNICODE*)str, len);
-#else  /* Py_UNICODE_WIDE */
-    buf = alloca(sizeof(Py_UNICODE) * len);
-    for (i = 0; i < len; i++)
-       buf[i] = str[i];
-    return PyUnicode_FromUnicode(buf, len);
-#endif /* Py_UNICODE_WIDE */
-}
-
-/* PY_HANGULIC methods */
-static PyMethodDef PY_HANGULIC_methods[] = {
-    { "process",       (PyCFunction)_pyhangulic_process,        METH_VARARGS, NULL},
-    { "reset",         (PyCFunction)_pyhangulic_reset,          METH_VARARGS, NULL},
-    { "flush",         (PyCFunction)_pyhangulic_flush,          METH_VARARGS, NULL},
-    { "backspace",     (PyCFunction)_pyhangulic_backspace,      METH_VARARGS, NULL},
-    { "preedit_string",(PyCFunction)_pyhangulic_preedit_string, METH_VARARGS, NULL},
-    { "commit_string", (PyCFunction)_pyhangulic_commit_string,  METH_VARARGS, NULL},
-    { NULL, NULL, 0, NULL }
-};
-
-/* PY_HANGULIC dealloc */
-static void PY_HANGULIC_dealloc(PY_HANGULIC *self)
-{
-    hangul_ic_delete(self->hic);
-    self->hic = NULL;
-    PyMem_Free((char *) self);
-}
-
-/* PY_HANGULIC getattr */
-static PyObject * PY_HANGULIC_getattr(PY_HANGULIC *self, char *name)
-{
-    PyObject *res;
-    res = Py_FindMethod(PY_HANGULIC_methods, (PyObject *)self, name);
-    if(res != NULL)
-       return res;
-    PyErr_Clear();
-    PyErr_SetString(_pyhangul_error,"UnKnown method");
-    return NULL;
-}
-
-/* PY_HANGULIC repr */
-static PyObject * PY_HANGULIC_repr(PY_HANGULIC *self)
-{
-    char buf[300];
-    sprintf(buf,"<Class pyhangul at %lx>",(long)self);
-    return PyString_FromString(buf);
-}
-
-
-/* PY_HANGUL Type */
-PyTypeObject PY_HANGULIC_Type = {
-#ifndef MS_WIN32
-    PyObject_HEAD_INIT(&PyType_Type)
-#else
-    PyObject_HEAD_INIT(NULL)
-#endif
-       0,
-    "hangul.hangulic",
-    sizeof(PY_HANGULIC),
-    0,
-    (destructor)PY_HANGULIC_dealloc,
-    0,
-    (getattrfunc)PY_HANGULIC_getattr,
-    0,
-    0,
-    (reprfunc)PY_HANGULIC_repr,
-};
diff --git a/bindings/python/setup.py b/bindings/python/setup.py
deleted file mode 100755 (executable)
index f353e4f..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/usr/bin/env python
-
-import sys
-from distutils.core import setup, Extension 
-
-classifiers = """\
-Development Status :: 4 - Beta
-Intended Audience :: Developers
-License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)
-Programming Language :: Python
-Programming Language :: C
-Topic :: Software Development :: Libraries :: Python Modules
-Operating System :: Microsoft :: Windows
-Operating System :: Unix
-"""
-if sys.platform == "win32": # for MinGW
-       include_dirs = [r'\MinGW\include', r'..\..\hangul']
-       library_dirs = [r'\MinGW\lib', r'..\..\hangul']
-       libraries = ['hangul']
-       data_files = []
-       
-else:
-       include_dirs = [ '../../hangul' ]
-       library_dirs = [ '../../hangul/.libs' ]
-       libraries = ['hangul']
-       data_files = []
-
-if sys.version_info < (2, 3):
-       _setup = setup
-       def setup(**kwargs):
-               if kwargs.has_key("classifiers"): 
-                       del kwargs["classifiers"]
-                       _setup(**kwargs)
-
-setup(name = "pyhangul", 
-       version = "0.0.1", 
-       description="libhangul for Python.",
-       author = "Joon-cheol Park", 
-       author_email="jooncheol@gmail.com", 
-       license = "LGPL",
-       url="http://hangul.kldp.net", 
-       ext_modules=[Extension("hangul", ["pyhangul.c"],
-                                include_dirs = include_dirs,
-                                library_dirs = library_dirs,
-                                libraries = libraries)],
-       classifiers = filter(None, classifiers.split("\n")),
-       data_files=data_files
-       ) 
diff --git a/bindings/python/test_pyhangul.py b/bindings/python/test_pyhangul.py
deleted file mode 100755 (executable)
index 448b2e3..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-# coding: utf-8
-#
-# Author: Gyoung-Yoon Noh <nohmad@gmail.com>
-# License: Same as libhangul.
-
-import sys
-import hangul
-import unittest
-
-class TestHangul(unittest.TestCase):
-    def setUp(self):
-        self.ic = hangul.create_ic('hangul2')
-
-    def testSimpleString(self):
-        input  = u"vkdlTjs gksrmf fkdlqmfjfl xptmxm"
-        output = u"파이썬 한글 라이브러리 테스트"
-        buffer = u''
-        for i in input:
-            ret = self.ic.process(ord(i))
-            buffer += self.ic.commit_string()
-            if not ret:
-                buffer += str(i)
-        buffer += self.ic.flush()
-        buffer += self.ic.commit_string()
-        self.assertEqual(output, buffer)
-
-if __name__ == '__main__':
-    unittest.main()
diff --git a/bindings/ruby/extconf.rb b/bindings/ruby/extconf.rb
deleted file mode 100755 (executable)
index d443963..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-require 'mkmf'
-
-dir_config('hangul')
-have_library('hangul', 'hangul_ic_new')
-create_makefile('hangul')
-
-# vim: set sts=2 sw=2 et:
diff --git a/bindings/ruby/hangul.c b/bindings/ruby/hangul.c
deleted file mode 100755 (executable)
index 664b634..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- *  Ruby extenstion library for libhangul.
- *
- *  * Author: Gyoung-Yoon Noh <nohmad@sub-port.net>
- *  * License: Same as libhangul.
- */
-
-#include <locale.h>
-
-#include "ruby.h"
-#include "hangul.h"
-
-static void
-rbhic_free(HangulInputContext *hic)
-{
-    hangul_ic_delete(hic);
-}
-
-static VALUE
-rbhic_alloc(VALUE klass)
-{
-    setlocale(LC_CTYPE, "");
-    HangulInputContext *hic = hangul_ic_new(HANGUL_KEYBOARD_2);
-    return Data_Wrap_Struct(klass, 0, rbhic_free, hic);
-}
-
-static VALUE
-rbhic_initialize(int argc, VALUE *argv, VALUE self)
-{
-    HangulInputContext *hic;
-    Data_Get_Struct(self, HangulInputContext, hic);
-    VALUE keyboard;
-    rb_scan_args(argc, argv, "01", &keyboard);
-    if (argc > 0) {
-        Check_Type(keyboard, T_FIXNUM);
-        hangul_ic_set_keyboard(hic, FIX2INT(keyboard));
-    }
-    return self;
-}
-
-static VALUE
-rbhic_filter(VALUE self, VALUE ch)
-{
-    Check_Type(ch, T_FIXNUM);
-    HangulInputContext *hic;
-    Data_Get_Struct(self, HangulInputContext, hic);
-
-    bool ret = hangul_ic_filter(hic, NUM2CHR(ch));
-    return ret ? Qtrue : Qfalse;
-}
-
-static VALUE
-rbhic_preedit_string(VALUE self)
-{
-}
-
-static VALUE
-rbhic_commit_string(VALUE self)
-{
-    HangulInputContext *hic;
-    Data_Get_Struct(self, HangulInputContext, hic);
-
-    char cbuf[32] = { '\0', };
-    wchar_t *wstr = (wchar_t *) hangul_ic_get_commit_string(hic);
-    int len = wcstombs(cbuf, wstr, sizeof(cbuf));
-    if (strlen(cbuf) > 0)
-        return rb_str_new(cbuf, len);
-    else
-        return Qnil;
-}
-
-static VALUE
-rbhic_backspace(VALUE self)
-{
-}
-
-static VALUE
-rbhic_reset(VALUE self)
-{
-    HangulInputContext *hic;
-    Data_Get_Struct(self, HangulInputContext, hic);
-    hangul_ic_reset(hic);
-    return Qnil;
-}
-
-static VALUE
-rbhic_flush(VALUE self)
-{
-    HangulInputContext *hic;
-    Data_Get_Struct(self, HangulInputContext, hic);
-    hangul_ic_flush(hic);
-    return Qnil;
-}
-
-void
-Init_hangul(void)
-{
-    /* ::Hangul module. */
-    VALUE rb_mHangul;
-    rb_mHangul = rb_define_module("Hangul");
-
-    /* Hangul::InputContext class. */
-    VALUE rb_cInputContext;
-    rb_cInputContext = rb_define_class_under(rb_mHangul, "InputContext", rb_cObject);
-    rb_define_alloc_func(rb_cInputContext, rbhic_alloc);
-
-    /* Hangul::InputContext methods. */
-    rb_define_method(rb_cInputContext, "initialize", rbhic_initialize, -1);
-    rb_define_method(rb_cInputContext, "filter", rbhic_filter, 1);
-    rb_define_method(rb_cInputContext, "commit_string", rbhic_commit_string, 0);
-    rb_define_method(rb_cInputContext, "preedit_string", rbhic_preedit_string, 0);
-    rb_define_method(rb_cInputContext, "backspace", rbhic_backspace, 0);
-    rb_define_method(rb_cInputContext, "flush", rbhic_flush, 0);
-    rb_define_method(rb_cInputContext, "reset", rbhic_reset, 0);
-
-    /* Hangul::KEYBOARD_* constants. */
-    rb_define_const(rb_mHangul, "KEYBOARD_2", INT2FIX(HANGUL_KEYBOARD_2));
-    rb_define_const(rb_mHangul, "KEYBOARD_32", INT2FIX(HANGUL_KEYBOARD_32));
-    rb_define_const(rb_mHangul, "KEYBOARD_3FINAL", INT2FIX(HANGUL_KEYBOARD_3FINAL));
-    rb_define_const(rb_mHangul, "KEYBOARD_390", INT2FIX(HANGUL_KEYBOARD_390));
-    rb_define_const(rb_mHangul, "KEYBOARD_3NOSHIFT", INT2FIX(HANGUL_KEYBOARD_3NOSHIFT));
-    rb_define_const(rb_mHangul, "KEYBOARD_3YETGUL", INT2FIX(HANGUL_KEYBOARD_3YETGUL));
-}
-
diff --git a/bindings/ruby/test-hangul.rb b/bindings/ruby/test-hangul.rb
deleted file mode 100755 (executable)
index f38abe1..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-require 'test/unit'
-require 'hangul'
-
-class TestHangulInputContext < Test::Unit::TestCase
-  def setup
-    @hic = Hangul::InputContext.new(Hangul::KEYBOARD_2)
-  end
-  def test_2bul_string
-    input = "fnql gksrmf fkdlqmfjfl xptmxm"
-    expected = "루비 한글 라이브러리 테스트"
-    buffer = ''
-    input.each_byte do |c|
-      ret = @hic.filter(c)
-      buffer << @hic.commit_string.to_s
-      buffer << c.chr unless ret
-    end
-    @hic.flush
-    buffer << @hic.commit_string.to_s
-    assert_equal expected, buffer
-  end
-end
-
-# vim: set sts=2 sw=2 et:
index ef28e7748e5226311abfcae2d48bbee371356fd9..e4434cf2cab2f3950e618e6071ce974a94f99114 100755 (executable)
@@ -2,14 +2,14 @@
 # Process this file with autoconf to produce a configure script.
 
 AC_PREREQ(2.57)
-AC_INIT(libhangul, 0.0.7, http://kldp.net/projects/hangul/)
+AC_INIT(libhangul, 0.0.10, http://kldp.net/projects/hangul/)
 AM_INIT_AUTOMAKE
 AC_CONFIG_SRCDIR([hangul/hangul.h])
 AC_CONFIG_HEADER([config.h])
 
 # library version
 LIBHANGUL_CURRENT=1
-LIBHANGUL_REVISION=0
+LIBHANGUL_REVISION=2
 LIBHANGUL_AGE=1
 
 AC_SUBST(LIBHANGUL_CURRENT)
@@ -26,23 +26,35 @@ AC_PROG_INSTALL
 
 # Checks for header files.
 AC_HEADER_STDC
-AC_CHECK_HEADERS([stdlib.h string.h])
+AC_CHECK_HEADERS([stdlib.h string.h limits.h])
 
 # Checks for typedefs, structures, and compiler characteristics.
 AC_HEADER_STDBOOL
 AC_C_BIGENDIAN
 AC_C_CONST
 AC_C_INLINE
-AC_TYPE_UINT32_T
+#AC_TYPE_UINT32_T
 
 # Checks for library functions.
+AC_FUNC_MEMCMP
+AC_FUNC_MMAP
+AC_FUNC_REALLOC
+AC_CHECK_FUNCS([munmap])
+AC_CHECK_FUNCS([strcasecmp])
+
+# Checks for unit test framework
+#PKG_PROG_PKG_CONFIG
+#if test -n "$PKG_CONFIG"; then
+#    PKG_CHECK_EXISTS(check, [ PKG_CHECK_MODULES([CHECK], [check]) ])
+#fi
+
 AC_CONFIG_FILES([
 Makefile
 hangul/Makefile
 data/Makefile
 data/hanja/Makefile
-bindings/Makefile
 test/Makefile
+doc/Doxyfile
 libhangul.pc
 ])
 
old mode 100755 (executable)
new mode 100644 (file)
index de3da35..78d8e81
 동:䴀:
 동:䵔:
 동:䶱:
-동:中洞:지명
 동가:東家:
 동가:同價:
 동가:動駕:
 벽전과:壁錢科:
 벽전화기:壁電話器:
 벽제:碧蹄:
-벽제:除:
+벽제:除:
 벽제관:碧蹄館:
 벽제관싸움:碧蹄館싸움:
 벽제동:碧蹄洞:지명
 벽조:碧潮:
 벽조목:霹棗木:
-벽좌우:左右:
+벽좌우:左右:
 벽주:壁柱:
 벽주:碧珠:
 벽중깃:壁中깃:
 북두진군:北斗眞君:
 북두칠성:北斗七星:
 북등:북燈:
-북량:北:
+북량:北:
 북로:北路:
 북로:北虜:
 북로고공:北路雇工:
 수우:秀羽:
 수우:樹羽:
 수우:殊尤:
+수우:愁憂:
 수우도:樹牛島:
 수우도:水牛島:
 수우죽백:垂于竹帛:
 수우피:水牛皮:
-수우:愁憂:
 수운:水雲:
 수운:輸運:
 수운:水運:
 에어러샛계획:에어러샛計劃:
 에어러솔폭탄:에어러솔爆彈:
 에어셔종:에어셔種:
-에염:�焰:
 에오세:에오世:
 에올리아조식:에올리아調式:
 에올리에제도:에올리에諸島:
 육연성:六連星:
 육연풍:陸軟風:
 육영:育英:
-육영:育:
+육영:育:
 육영공원:育英公院:
 육영사업:育英事業:
 육영수:陸英修:
 융모:絨毛:
 융모막:絨毛膜:
 융모상피종:絨毛上皮腫:
-융모성건초염:絨毛性腱炎:
+융모성건초염:絨毛性腱炎:
 융모치:絨毛齒:
 융모포:絨毛布:
 융병:戎兵:
 적다:摘茶:
 적다:赤多:
 적다마:赤多馬:
-적다:赤多:
 적담:赤痰:
 적담:敵膽:
 적당:賊黨:
 적록:赤鹿:
 적록색:赤綠色:
 적록색맹:赤綠色盲:
-적뢰:跡�:
+적뢰:摘蕾:
 적료:赤蓼:
 적료:寂廖:
 적료:寂寥:
 적사:敵使:
 적사:積邪:
 적사:謫徙:
-적사:�沙:
 적사구근:積仕久勤:
 적사인:積仕人:
 적사진:赤寫眞:
 족매:族妹:
 족멸:族滅:
 족문:足紋:
-족바지:足바지:
 족박자:足拍子:
 족반:足盤:
 족반거상:足反居上:
 척후병:斥候兵:
 척후장:斥候將:
 척후전:斥候戰:
-척다:隻다:
 천:天:하늘 천
 천:千:일천 천
 천:川:내 천
 청량:淸亮:
 청량:淸凉:
 청량:淸良:
-청량:淸�:
 청량감:淸凉感:
 청량동:淸凉洞:지명
 청량동:靑良洞:지명
 청량미:靑粱米:
 청량미:淸凉味:
 청량사육:淸凉飼育:
-청량산:淸山:
+청량산:淸山:
 청량속:靑梁粟:
 청량음료:淸凉飮料:
-청량음료:淸�飮料:
 청량음료점:淸凉飮料占:
-청량제:淸劑:
+청량제:淸劑:
 청량히:淸亮히:
 청량히:淸凉히:
 청려:靑藜:
 췌언:贅言:
 췌염:膵炎:
 췌용:悴容:
-췌우:贅�:
 췌육:贅肉:
 췌장:膵臟:
 췌장결석:膵臟結石:
 팔불취:八不取:
 팔사:八絲:
 팔사첨작오:八四添作五:
-팔사파문자:思巴文字:
+팔사파문자:思巴文字:
 팔삭:八朔:
 팔삭동:八朔童:
 팔삭동이:八朔童이:
 포자:胞子:
 포자:布子:
 포자:鋪子:
-포자:煮:
+포자:煮:
 포자경:胞子莖:
 포자군:胞子郡:
 포자낭:胞子囊:
 포장집:布帳집:
 포장화심:包藏禍心:
 포재:抱才:
-포재:宰:
+포재:宰:
 포저:蒲菹:
-포저:苞:
+포저:苞:
 포저화:布楮貨:
 포전:浦田:
 포전:圃田:
 포접:抱接:
 포접화합물:包接化合物:
 포정:砲艇:
-포정:丁:
+포정:丁:
 포정:布政:지명
 포정문:布政門:
 포정사:布政司:
 한필호:韓弼昊:
 한하운:韓何雲:
 한학:漢學:
-한학:寒:
+한학:寒:
 한학강:漢學講:
 한학교수:漢學敎授:
 한학문신전강:漢學文臣殿講:
 회흑색:灰黑色:
 회흘:回紇:
 회흙바위:灰흙바위:
-회:回寺:
 획:畵:畫의 俗字
 획:獲:얻을 획
 획:劃:쪼갤 획, 그을 획
index 5bca1d7ba3ecb1584889748103705a286471a3d8..c80d0572d67b26f6a63df2b3a111261e7d45d552 100755 (executable)
@@ -1,3 +1,11 @@
+libhangul (2.10-1) unstable; urgency=low
+
+  * upgrade to libhangul 0.10.0
+  * Git: 165.213.180.234:/git/slp/pkgs/libhangul
+  * Tag: libhangul_2.10-1
+
+ -- Jihoon Kim <jihoon48.kim@samsung.com>  Sat, 02 Apr 2011 17:32:22 +0900
+
 libhangul (2.1-4) unstable; urgency=low
 
   * uncomment dh_makeshlibs in debian/rules
@@ -42,4 +50,4 @@ libhangul (2.0) unstable; urgency=low
 
   * Initial Release.
 
- -- Wei Ye <wei.ye@samsung.com>  Tue, 04 Nov 2010 12:00:08 +0900
\ No newline at end of file
+ -- Wei Ye <wei.ye@samsung.com>  Tue, 04 Nov 2010 12:00:08 +0900
index 31ec95c0d28acb4a2ec47a81ca833322eae7f26c..13cf2f7805cfca317ac2e4af9bfc3c11d84cec63 100755 (executable)
@@ -1,26 +1,37 @@
 Source: libhangul
-Section: devel
-Priority: extra
+Section: libs
+Priority: optional
 Maintainer: Wei Ye <wei.ye@samsung.com>, Jihoon Kim <jihoon48.kim>
-Build-Depends: debhelper (>= 5), autotools-dev, pkg-config, libisf-dev
-Standards-Version: 3.7.2
+Standards-Version: 3.8.3
+Build-Depends: cdbs (>= 0.4.48), autotools-dev, debhelper (>= 5)
 
 Package: libhangul0
 Section: libs
 Architecture: any
-Depends: ${shlibs:Depends}, ${misc:Depends}
+Depends: libhangul0-data (= ${source:Version}), ${shlibs:Depends}, ${misc:Depends}
 Description: Hangul keyboard input library - runtime
  This library implements Hangul keyboard input with various types of
  Korean keyboards.  It is intended to be a base library of Korean
  input methods on multiple platforms.
  .
  This package contains the shared library and the runtime data.
-Version: 2.2
+
+Package: libhangul0-data
+Section: libs
+Architecture: all
+Depends: ${misc:Depends}
+Description: Hangul keyboard input library - data
+ This library implements Hangul keyboard input with various types of
+ Korean keyboards.  It is intended to be a base library of Korean
+ input methods on multiple platforms.
+ .
+ This package contains the architecture independent data.
 
 Package: libhangul0-dbg
 Section: debug
+Priority: extra
 Architecture: any
-Depends: libhangul0, ${shlibs:Depends}, ${misc:Depends}
+Depends: libhangul0 (= ${binary:Version}), ${misc:Depends}
 Description: Hangul keyboard input library - debugging symbols
  This library implements Hangul keyboard input with various types of
  Korean keyboards.  It is intended to be a base library of Korean
@@ -32,7 +43,7 @@ Description: Hangul keyboard input library - debugging symbols
 Package: libhangul-dev
 Section: libdevel
 Architecture: any
-Depends: libhangul0, ${misc:Depends}
+Depends: libhangul0 (= ${binary:Version}), ${misc:Depends}
 Description: Hangul keyboard input library - development files
  This library implements Hangul keyboard input with various types of
  Korean keyboards.  It is intended to be a base library of Korean
index 8a37e0a378f4bbbc3640a2beddf3095c93258838..5dfeaf494e58e36a2cc1de7e5d53dd3b69182e7d 100755 (executable)
@@ -1,5 +1,5 @@
-usr/include/*
-usr/lib/pkgconfig/*.pc
-usr/lib/*.a
-usr/lib/*.la
-
+debian/tmp/usr/include/* usr/include/
+debian/tmp/usr/lib/lib*.a usr/lib/
+debian/tmp/usr/lib/lib*.so usr/lib/
+debian/tmp/usr/lib/*.la usr/lib/
+debian/tmp/usr/lib/pkgconfig/* usr/lib/pkgconfig/
diff --git a/debian/libhangul0-data.install b/debian/libhangul0-data.install
new file mode 100644 (file)
index 0000000..030888d
--- /dev/null
@@ -0,0 +1 @@
+debian/tmp/usr/share/libhangul usr/share/
index 6d36a42312c4a63cd6d995158ab4045cced2e212..483b6b5da41ff2d98d4078fb25d4ddbd973ec0c7 100755 (executable)
@@ -1,2 +1 @@
-usr/share/*
-usr/lib/*.so*
+debian/tmp/usr/lib/lib*.so.* usr/lib/
index 4a4b5e44c25cb9f4e1ac0467e45572805767a2fe..ab6d2fdf6783a622b56bcad62e96d53c097478e6 100755 (executable)
@@ -1,107 +1,8 @@
 #!/usr/bin/make -f
-# -*- makefile -*-
-# Sample debian/rules that uses debhelper.
-# This file was originally written by Joey Hess and Craig Small.
-# As a special exception, when this file is copied by dh-make into a
-# dh-make output file, you may use that output file without restriction.
-# This special exception was added by Craig Small in version 0.37 of dh-make.
 
-# Uncomment this to turn on verbose mode.
-#export DH_VERBOSE=1
+DEB_DBG_PACKAGES = libhangul0-dbg
 
+DEB_DH_MAKESHLIBS_ARGS_libhangul0 := --version-info
 
-# These are used for cross-compiling and for saving the configure script
-# from having to guess our platform (since we know it already)
-DEB_HOST_GNU_TYPE   ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
-DEB_BUILD_GNU_TYPE  ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
-
-
-CFLAGS = -Wall -g
-
-ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
-       CFLAGS += -O0
-else
-       CFLAGS += -O2
-endif
-
-config.status:
-       dh_testdir
-       # Add here commands to configure the package.
-       ./configure --host=$(DEB_HOST_GNU_TYPE) --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info CFLAGS="$(CFLAGS)" LDFLAGS="-Wl,-z,defs"
-
-
-build: build-stamp
-
-build-stamp:  config.status
-       dh_testdir
-
-       # Add here commands to compile the package.
-       $(MAKE)
-       #docbook-to-man debian/pinyin.sgml > pinyin.1
-
-       touch $@
-
-clean:
-       dh_testdir
-       dh_testroot
-       rm -f build-stamp 
-
-       # Add here commands to clean up after the build process.
-       -$(MAKE) distclean
-ifneq "$(wildcard /usr/share/misc/config.sub)" ""
-       cp -f /usr/share/misc/config.sub config.sub
-endif
-ifneq "$(wildcard /usr/share/misc/config.guess)" ""
-       cp -f /usr/share/misc/config.guess config.guess
-endif
-
-
-       dh_clean 
-
-install: build
-       dh_testdir
-       dh_testroot
-       dh_clean -k 
-       dh_installdirs
-
-       # Add here commands to install the package into debian/tmp.
-       $(MAKE) DESTDIR=$(CURDIR)/debian/tmp install
-
-
-# Build architecture-independent files here.
-binary-indep: build install
-# We have nothing to do by default.
-
-# Build architecture-dependent files here.
-binary-arch: build install
-       dh_testdir
-       dh_testroot
-       dh_installchangelogs ChangeLog
-       dh_installdocs
-       dh_installexamples
-       dh_install --sourcedir=debian/tmp
-#      dh_installmenu
-#      dh_installdebconf       
-#      dh_installlogrotate
-#      dh_installemacsen
-#      dh_installpam
-#      dh_installmime
-#      dh_python
-#      dh_installinit
-#      dh_installcron
-#      dh_installinfo
-       dh_installman
-       dh_link
-       dh_strip --dbg-package=libhangul0-dbg
-       dh_compress
-       dh_fixperms
-#      dh_perl
-       dh_makeshlibs
-       dh_installdeb
-       dh_shlibdeps
-       dh_gencontrol
-       dh_md5sums
-       dh_builddeb
-
-binary: binary-indep binary-arch
-.PHONY: build clean binary-indep binary-arch binary install 
+include /usr/share/cdbs/1/rules/debhelper.mk
+include /usr/share/cdbs/1/class/autotools.mk
diff --git a/debian/watch b/debian/watch
new file mode 100644 (file)
index 0000000..b81b9fd
--- /dev/null
@@ -0,0 +1,2 @@
+version=3
+http://kldp.net/frs/?group_id=362 /frs/download.php/.*/libhangul-(.*)\.tar\.gz
diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in
new file mode 100644 (file)
index 0000000..dc865d5
--- /dev/null
@@ -0,0 +1,1230 @@
+# Doxyfile 1.4.3-20050530
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = @PACKAGE_NAME@
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. 
+# This could be handy for archiving the generated documentation or 
+# if some version control system is used.
+
+PROJECT_NUMBER         = "Version @VERSION@"
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
+# base path where the generated documentation will be put. 
+# If a relative path is entered, it will be relative to the location 
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       =
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 
+# 4096 sub-directories (in 2 levels) under the output directory of each output 
+# format and will distribute the generated files over these directories. 
+# Enabling this option can be useful when feeding doxygen a huge amount of 
+# source files, where putting all generated files in the same directory would 
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all 
+# documentation generated by doxygen is written. Doxygen will use this 
+# information to generate all constant output in the proper language. 
+# The default language is English, other supported languages are: 
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, 
+# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, 
+# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, 
+# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, 
+# Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE        = Korean
+
+# This tag can be used to specify the encoding used in the generated output. 
+# The encoding is not always determined by the language that is chosen, 
+# but also whether or not the output is meant for Windows or non-Windows users. 
+# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES 
+# forces the Windows encoding (this is the default for the Windows binary), 
+# whereas setting the tag to NO uses a Unix-style encoding (the default for 
+# all platforms other than Windows).
+
+USE_WINDOWS_ENCODING   = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 
+# include brief member descriptions after the members that are listed in 
+# the file and class documentation (similar to JavaDoc). 
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 
+# the brief description of a member or function before the detailed description. 
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator 
+# that is used to form the text in various listings. Each string 
+# in this list, if found as the leading text of the brief description, will be 
+# stripped from the text and the result after processing the whole list, is 
+# used as the annotated text. Otherwise, the brief description is used as-is. 
+# If left blank, the following values are used ("$name" is automatically 
+# replaced with the name of the entity): "The $name class" "The $name widget" 
+# "The $name file" "is" "provides" "specifies" "contains" 
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       = 
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 
+# Doxygen will generate a detailed section even if there is only a brief 
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all 
+# inherited members of a class in the documentation of that class as if those 
+# members were ordinary class members. Constructors, destructors and assignment 
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 
+# path before files name in the file list and in the header files. If set 
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 
+# can be used to strip a user-defined part of the path. Stripping is 
+# only done if one of the specified strings matches the left-hand part of 
+# the path. The tag can be used to show relative paths in the file list. 
+# If left blank the directory from which doxygen is run is used as the 
+# path to strip.
+
+STRIP_FROM_PATH        = 
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of 
+# the path mentioned in the documentation of a class, which tells 
+# the reader which header file to include in order to use a class. 
+# If left blank only the name of the header file containing the class 
+# definition is used. Otherwise one should specify the include paths that 
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    = 
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 
+# (but less readable) file names. This can be useful is your file systems 
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 
+# will interpret the first line (until the first dot) of a JavaDoc-style 
+# comment as the brief description. If set to NO, the JavaDoc 
+# comments will behave just like the Qt-style comments (thus requiring an 
+# explicit @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF      = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen 
+# treat a multi-line C++ special comment block (i.e. a block of //! or /// 
+# comments) as a brief description. This used to be the default behaviour. 
+# The new default is to treat a multi-line C++ comment block as a detailed 
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen 
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member 
+# documentation.
+
+DETAILS_AT_TOP         = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
+# member inherits the documentation from any documented member that it 
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 
+# tag is set to YES, then doxygen will reuse the documentation of the first 
+# member in the group (if any) for the other members of the group. By default 
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce 
+# a new page for each member. If set to NO, the documentation of a member will 
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. 
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts 
+# as commands in the documentation. An alias has the form "name=value". 
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to 
+# put the command \sideeffect (or @sideeffect) in the documentation, which 
+# will result in a user-defined paragraph with heading "Side Effects:". 
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                = 
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C 
+# sources only. Doxygen will then generate output that is more tailored for C. 
+# For instance, some of the names that are used will be different. The list 
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources 
+# only. Doxygen will then generate output that is more tailored for Java. 
+# For instance, namespaces will be presented as packages, qualified scopes 
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of 
+# the same type (for instance a group of public functions) to be put as a 
+# subgroup of that type (e.g. under the Public Functions section). Set it to 
+# NO to prevent subgrouping. Alternatively, this can be done per class using 
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 
+# documentation are documented, even if no documentation was available. 
+# Private class members and static file members will be hidden unless 
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file 
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) 
+# defined locally in source files will be included in the documentation. 
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = NO
+
+# This flag is only useful for Objective-C code. When set to YES local 
+# methods, which are defined in the implementation section but not in 
+# the interface are included in the documentation. 
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
+# undocumented members of documented classes, files or namespaces. 
+# If set to NO (the default) these members will be included in the 
+# various overviews, but no documentation section is generated. 
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 
+# undocumented classes that are normally visible in the class hierarchy. 
+# If set to NO (the default) these classes will be included in the various 
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 
+# friend (class|struct|union) declarations. 
+# If set to NO (the default) these declarations will be included in the 
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any 
+# documentation blocks found inside the body of a function. 
+# If set to NO (the default) these blocks will be appended to the 
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation 
+# that is typed after a \internal command is included. If the tag is set 
+# to NO (the default) then the documentation will be excluded. 
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate 
+# file names in lower-case letters. If set to YES upper-case letters are also 
+# allowed. This is useful if you have classes or files whose names only differ 
+# in case and if your file system supports case sensitive file names. Windows 
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
+# will show members with their full class and namespace scopes in the 
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
+# will put a list of the files that are included by a file in the documentation 
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 
+# will sort the (detailed) documentation of file and class members 
+# alphabetically by member name. If set to NO the members will appear in 
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the 
+# brief documentation of file, namespace and class members alphabetically 
+# by member name. If set to NO (the default) the members will appear in 
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be 
+# sorted by fully-qualified names, including namespaces. If set to 
+# NO (the default), the class list will be sorted only by class name, 
+# not including the namespace part. 
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the 
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or 
+# disable (NO) the todo list. This list is created by putting \todo 
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or 
+# disable (NO) the test list. This list is created by putting \test 
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or 
+# disable (NO) the bug list. This list is created by putting \bug 
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or 
+# disable (NO) the deprecated list. This list is created by putting 
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional 
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       = 
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines 
+# the initial value of a variable or define consists of for it to appear in 
+# the documentation. If the initializer consists of more lines than specified 
+# here it will be hidden. Use a value of 0 to hide initializers completely. 
+# The appearance of the initializer of individual variables and defines in the 
+# documentation can be controlled using \showinitializer or \hideinitializer 
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated 
+# at the bottom of the documentation of classes and structs. If set to YES the 
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# If the sources in your project are distributed over multiple directories 
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy 
+# in the documentation.
+
+SHOW_DIRECTORIES       = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that 
+# doxygen should invoke to get the current version for each file (typically from the 
+# version control system). Doxygen will invoke the program by executing (via 
+# popen()) the command <command> <input-file>, where <command> is the value of 
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file 
+# provided by doxygen. Whatever the progam writes to standard output 
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated 
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are 
+# generated by doxygen. Possible values are YES and NO. If left blank 
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will 
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for 
+# potential errors in the documentation, such as not documenting some 
+# parameters in a documented function, or documenting parameters that 
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for 
+# functions that are documented, but have no documentation for their parameters 
+# or return value. If set to NO (the default) doxygen will only warn about 
+# wrong or incomplete parameter documentation, but not about the absence of 
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that 
+# doxygen can produce. The string should contain the $file, $line, and $text 
+# tags, which will be replaced by the file and line number from which the 
+# warning originated and the warning text. Optionally the format may contain 
+# $version, which will be replaced by the version of the file (if it could 
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning 
+# and error messages should be written. If left blank the output is written 
+# to stderr.
+
+WARN_LOGFILE           = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain 
+# documented source files. You may enter file names like "myfile.cpp" or 
+# directories like "/usr/src/myproject". Separate the files or directories 
+# with spaces.
+
+INPUT                  = ../hangul/hangul.h \
+                        ../hangul/hangulctype.c \
+                        ../hangul/hangulinputcontext.c \
+                        ../hangul/hanja.c \
+                        mainpage.dox
+
+# If the value of the INPUT tag contains directories, you can use the 
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank the following patterns are tested: 
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx 
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm
+
+FILE_PATTERNS          = *.h *.c
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories 
+# should be searched for input files as well. Possible values are YES and NO. 
+# If left blank NO is used.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should 
+# excluded from the INPUT source files. This way you can easily exclude a 
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                = 
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or 
+# directories that are symbolic links (a Unix filesystem feature) are excluded 
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the 
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 
+# certain files from those directories.
+
+EXCLUDE_PATTERNS       = 
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or 
+# directories that contain example code fragments that are included (see 
+# the \include command).
+
+EXAMPLE_PATH           = 
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the 
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank all files are included.
+
+EXAMPLE_PATTERNS       = 
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be 
+# searched for input files to be used with the \include or \dontinclude 
+# commands irrespective of the value of the RECURSIVE tag. 
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or 
+# directories that contain image that are included in the documentation (see 
+# the \image command).
+
+IMAGE_PATH             = 
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should 
+# invoke to filter for each input file. Doxygen will invoke the filter program 
+# by executing (via popen()) the command <filter> <input-file>, where <filter> 
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an 
+# input file. Doxygen will then use the output that the filter program writes 
+# to standard output.  If FILTER_PATTERNS is specified, this tag will be 
+# ignored.
+
+INPUT_FILTER           = 
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern 
+# basis.  Doxygen will compare the file name with each pattern and apply the 
+# filter if there is a match.  The filters are a list of the form: 
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further 
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER 
+# is applied to all files.
+
+FILTER_PATTERNS        = 
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 
+# INPUT_FILTER) will be used to filter the input files when producing source 
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will 
+# be generated. Documented entities will be cross-referenced with these sources. 
+# Note: To get rid of all source code in the generated output, make sure also 
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body 
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
+# doxygen to hide any special comment blocks from generated source code 
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default) 
+# then for each documented function all documented 
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default) 
+# then for each documented function all documented entities 
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code 
+# will point to the HTML generated by the htags(1) tool instead of doxygen 
+# built-in source browser. The htags tool is part of GNU's global source 
+# tagging system (see http://www.gnu.org/software/global/global.html). You 
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
+# will generate a verbatim copy of the header file for each class for 
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 
+# of all compounds will be generated. Enable this if the project 
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all 
+# classes will be put under the same header in the alphabetical index. 
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that 
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for 
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank 
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard header.
+
+HTML_HEADER            = 
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard footer.
+
+HTML_FOOTER            = 
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading 
+# style sheet that is used by each HTML page. It can be used to 
+# fine-tune the look of the HTML output. If the tag is left blank doxygen 
+# will generate a default style sheet. Note that doxygen will try to copy 
+# the style sheet file to the HTML output directory, so don't put your own 
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        = 
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 
+# files or namespaces will be aligned in HTML using tables. If set to 
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files 
+# will be generated that can be used as input for tools like the 
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) 
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 
+# be used to specify the file name of the resulting .chm file. You 
+# can add a path in front of the file if the result should not be 
+# written to the html output directory.
+
+CHM_FILE               = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can 
+# be used to specify the location (absolute path including file name) of 
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run 
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 
+# controls if a separate .chi index file is generated (YES) or that 
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 
+# controls whether a binary table of contents is generated (YES) or a 
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members 
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at 
+# top of each HTML page. The value NO (the default) enables the index and 
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20]) 
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that 
+# is generated for HTML Help). For this to work a browser that supports 
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, 
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are 
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be 
+# used to set the initial width (in pixels) of the frame in which the tree 
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
+# generate Latex output.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be 
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 
+# generate index for LaTeX. If left blank `makeindex' will be used as the 
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 
+# LaTeX documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used 
+# by the printer. Possible values are: a4, a4wide, letter, legal and 
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         = 
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for 
+# the generated latex document. The header should contain everything until 
+# the first chapter. If it is left blank doxygen will generate a 
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           = 
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will 
+# contain links (just like the HTML output) instead of page references 
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 
+# plain latex in the generated Makefile. Set this option to YES to get a 
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 
+# command to the generated LaTeX files. This will instruct LaTeX to keep 
+# running if errors occur, instead of asking the user for help. 
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not 
+# include the index chapters (such as File Index, Compound Index, etc.) 
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 
+# The RTF output is optimized for Word 97 and may not look very pretty with 
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact 
+# RTF documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 
+# will contain hyperlink fields. The RTF file will 
+# contain links (just like the HTML output) instead of page references. 
+# This makes the output suitable for online browsing using WORD or other 
+# programs which support those fields. 
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's 
+# config file, i.e. a series of assignments. You only have to provide 
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    = 
+
+# Set optional variables used in the generation of an rtf document. 
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to 
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output, 
+# then it will generate one additional man file for each entity 
+# documented in the real man page(s). These additional files 
+# only source the real man page, but without them the man command 
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will 
+# generate an XML file that captures the structure of 
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_SCHEMA             = 
+
+# The XML_DTD tag can be used to specify an XML DTD, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_DTD                = 
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will 
+# dump the program listings (including syntax highlighting 
+# and cross-referencing information) to the XML output. Note that 
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 
+# generate an AutoGen Definitions (see autogen.sf.net) file 
+# that captures the structure of the code including all 
+# documentation. Note that this feature is still experimental 
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will 
+# generate a Perl module file that captures the structure of 
+# the code including all documentation. Note that this 
+# feature is still experimental and incomplete at the 
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate 
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able 
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be 
+# nicely formatted so it can be parsed by a human reader.  This is useful 
+# if you want to understand what is going on.  On the other hand, if this 
+# tag is set to NO the size of the Perl module output will be much smaller 
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file 
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. 
+# This is useful so different doxyrules.make files included by the same 
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX = 
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
+# evaluate all C-preprocessor directives found in the sources and include 
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 
+# names in the source code. If set to NO (the default) only conditional 
+# compilation will be performed. Macro expansion can be done in a controlled 
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
+# then the macro expansion is limited to the macros specified with the 
+# PREDEFINED and EXPAND_AS_PREDEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that 
+# contain include files that are not input files but should be processed by 
+# the preprocessor.
+
+INCLUDE_PATH           = 
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 
+# patterns (like *.h and *.hpp) to filter out the header-files in the 
+# directories. If left blank, the patterns specified with FILE_PATTERNS will 
+# be used.
+
+INCLUDE_FILE_PATTERNS  = 
+
+# The PREDEFINED tag can be used to specify one or more macro names that 
+# are defined before the preprocessor is started (similar to the -D option of 
+# gcc). The argument of the tag is a list of macros of the form: name 
+# or name=definition (no spaces). If the definition and the = are 
+# omitted =1 is assumed. To prevent a macro definition from being 
+# undefined via #undef or recursively expanded use the := operator 
+# instead of the = operator.
+
+PREDEFINED             = 
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 
+# this tag can be used to specify a list of macro names that should be expanded. 
+# The macro definition that is found in the sources will be used. 
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      = 
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 
+# doxygen's preprocessor will remove all function-like macros that are alone 
+# on a line, have an all uppercase name, and do not end with a semicolon. Such 
+# function macros are typically used for boiler-plate code, and will confuse 
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references   
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles. 
+# Optionally an initial location of the external documentation 
+# can be added for each tagfile. The format of a tag file without 
+# this location is as follows: 
+#   TAGFILES = file1 file2 ... 
+# Adding location for the tag files is done as follows: 
+#   TAGFILES = file1=loc1 "file2 = loc2" ... 
+# where "loc1" and "loc2" can be relative or absolute paths or 
+# URLs. If a location is present for each tag, the installdox tool 
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen 
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               = 
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create 
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       = 
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed 
+# in the class index. If set to NO only the inherited external classes 
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed 
+# in the modules index. If set to NO, only the current project's groups will 
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script 
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool   
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base 
+# or super classes. Setting the tag to NO turns the diagrams off. Note that 
+# this option is superseded by the HAVE_DOT option below. This is only a 
+# fallback. It is recommended to install and use dot, since it yields more 
+# powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide 
+# inheritance and usage relations if the target is undocumented 
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 
+# available from the path. This tool is part of Graphviz, a graph visualization 
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section 
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect inheritance relations. Setting this tag to YES will force the 
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect implementation dependencies (inheritance, containment, and 
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and 
+# collaboration diagrams in a style similar to the OMG's Unified Modeling 
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the 
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 
+# tags are set to YES then doxygen will generate a graph for each documented 
+# file showing the direct and indirect include dependencies of the file with 
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each 
+# documented header file showing the documented files that directly or 
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will 
+# generate a call dependency graph for every global function or class method. 
+# Note that enabling this option will significantly increase the time of a run. 
+# So in most cases it will be better to enable call graphs for selected 
+# functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES 
+# then doxygen will show the dependencies a directory has on other directories 
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be 
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               = 
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that 
+# contain dot files that are included in the documentation (see the 
+# \dotfile command).
+
+DOTFILE_DIRS           = 
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width 
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than 
+# this value, doxygen will try to truncate the graph, so that it fits within 
+# the specified constraint. Beware that most browsers cannot cope with very 
+# large images.
+
+MAX_DOT_GRAPH_WIDTH    = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height 
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than 
+# this value, doxygen will try to truncate the graph, so that it fits within 
+# the specified constraint. Beware that most browsers cannot cope with very 
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT   = 1024
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the 
+# graphs generated by dot. A depth value of 3 means that only nodes reachable 
+# from the root by following a path via at most 3 edges will be shown. Nodes 
+# that lay further from the root node will be omitted. Note that setting this 
+# option to 1 or 2 may greatly reduce the computation time needed for large 
+# code bases. Also note that a graph may be further truncated if the graph's 
+# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH 
+# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), 
+# the graph is not depth-constrained.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent 
+# background. This is disabled by default, which results in a white background. 
+# Warning: Depending on the platform used, enabling this option may lead to 
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to 
+# read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output 
+# files in one run (i.e. multiple -o and -T options on the command line). This 
+# makes dot run faster, but since only newer versions of dot (>1.8.10) 
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 
+# generate a legend page explaining the meaning of the various boxes and 
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 
+# remove the intermediate dot files that are used to generate 
+# the various graphs.
+
+DOT_CLEANUP            = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine   
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be 
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE           = NO
diff --git a/doc/Makefile b/doc/Makefile
new file mode 100644 (file)
index 0000000..03172d6
--- /dev/null
@@ -0,0 +1,9 @@
+doc:
+       doxygen
+
+clean:
+       rm -rf html
+
+upload:
+       cd html ; \
+       scp -pr * $(USER)@hangul.kldp.net:/var/lib/gforge/chroot/home/groups/hangul/htdocs
diff --git a/doc/mainpage.dox b/doc/mainpage.dox
new file mode 100644 (file)
index 0000000..7278e20
--- /dev/null
@@ -0,0 +1,42 @@
+/**
+
+@mainpage
+
+@section introduction libhangul 소개
+libhangul은 기본적인 한글 관련 루틴들을 구현한 라이브러리입니다.
+주로 한글 입력기능을 구현한 것으로 이 라이브러리를 사용하면 비교적 손쉽게
+한글 입력기를 구현할 수 있습니다. 현재 많은 linux의 입력기들이 이 라이브러리로
+구현되어 있습니다.
+
+@section documentation 개발 문서
+libhangul에서 제공하는 기능들은 다음 레퍼런스에서 찾아볼 수 있습니다.
+@li @ref hangulctype : 유니코드에서 한글 글자를 구분하고 조작하는 함수들입니다.
+이 함수들을 이용하면 자모 코드를 음절로 조합할 수 있고 또 음절을 자모 코드로 분리할 수 있습니다.
+@li @ref hangulicusage : 한글 입력 기능을 제공합니다. 이 함수들을 이용하여 키 입력에 따른 한글 조합 기능을 손쉽게 구현할 수 있습니다.
+@li @ref hanjadictionaryusage : 한자 사전 파일 관련 기능을 제공합니다. 이 함수들을 이용하여 libhangul에서 제공하는 한자 사전 파일을 찾아볼 수 있습니다.
+
+@section download 다운로드
+최근 릴리스들은 libhangul의 프로젝트 페이지에서 받을 수 있습니다.
+@li http://kldp.net/frs/?group_id=362
+
+개발버젼의 소스는 <a href="http://kldp.net/">KLDP.net</a>의 subversion 
+repository에서 받을 수 있습니다.
+@li subversion: http://kldp.net/scm/?group_id=362
+
+@section bug 버그리포트
+libhangul의 버그는 <a href="http://kldp.net/">KLDP.net</a>의 버그트래커로
+관리하고 있습니다.
+
+@li 버그트래커: http://kldp.net/tracker/?group_id=362
+
+@section mailinglist 메일링 리스트
+@li 메일링리스트: http://lists.kldp.net/mailman/listinfo/hangul-hackers
+@li 메일링리스트 아카이브: http://lists.kldp.net/pipermail/hangul-hackers/
+
+@section website 웹주소
+libhangul은 <a href="http://kldp.net/">KLDP.net</a>에서 호스팅되고 있습니다.
+ @li Home page: http://hangul.kldp.net/
+ @li Project page: http://kldp.net/projects/hangul/
+ @li Wiki page: http://wiki.kldp.org/wiki.php/libhangul
+
+ */
old mode 100755 (executable)
new mode 100644 (file)
index 8103d26..26e1871
 #include <stdbool.h>
 #include <inttypes.h>
 
+#ifdef __GNUC__
+#define LIBHANGUL_DEPRECATED __attribute__((deprecated));
+#else
+#define LIBHANGUL_DEPRECATED
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -41,25 +47,31 @@ bool hangul_is_choseong_conjoinable(ucschar c);
 bool hangul_is_jungseong_conjoinable(ucschar c);
 bool hangul_is_jongseong_conjoinable(ucschar c);
 bool hangul_is_syllable(ucschar c);
-bool hangul_is_jaso(ucschar c);
 bool hangul_is_jamo(ucschar c);
+bool hangul_is_cjamo(ucschar c);
 
-ucschar hangul_jaso_to_jamo(ucschar ch);
-ucschar hangul_choseong_to_jamo(ucschar ch);
-ucschar hangul_jungseong_to_jamo(ucschar ch);
-ucschar hangul_jongseong_to_jamo(ucschar ch);
+ucschar hangul_jamo_to_cjamo(ucschar ch);
 
 ucschar hangul_choseong_to_jongseong(ucschar ch);
 ucschar hangul_jongseong_to_choseong(ucschar ch);
 void    hangul_jongseong_dicompose(ucschar ch, ucschar* jong, ucschar* cho);
 
-ucschar hangul_jaso_to_syllable(ucschar choseong,
+const ucschar* hangul_syllable_iterator_prev(const ucschar* str,
+                                            const ucschar* begin);
+const ucschar* hangul_syllable_iterator_next(const ucschar* str,
+                                            const ucschar* end);
+
+int     hangul_syllable_len(const ucschar* str, int max_len);
+
+ucschar hangul_jamo_to_syllable(ucschar choseong,
                                ucschar jungseong,
                                ucschar jongseong);
-void    hangul_syllable_to_jaso(ucschar syllable,
+void    hangul_syllable_to_jamo(ucschar syllable,
                                ucschar* choseong,
                                ucschar* jungseong,
                                ucschar* jongseong);
+int     hangul_jamos_to_syllables(ucschar* dest, int destlen,
+                                 const ucschar* src, int srclen);
 
 /* hangulinputcontext.c */
 typedef struct _HangulKeyboard        HangulKeyboard;
@@ -74,7 +86,8 @@ enum {
 
 enum {
     HANGUL_KEYBOARD_TYPE_JAMO,
-    HANGUL_KEYBOARD_TYPE_JASO
+    HANGUL_KEYBOARD_TYPE_JASO,
+    HANGUL_KEYBOARD_TYPE_ROMAJA
 };
 
 /* keyboard */
@@ -102,8 +115,6 @@ bool hangul_ic_has_choseong(HangulInputContext *hic);
 bool hangul_ic_has_jungseong(HangulInputContext *hic);
 bool hangul_ic_has_jongseong(HangulInputContext *hic);
 
-int  hangul_ic_dvorak_to_qwerty(int qwerty);
-
 void hangul_ic_set_output_mode(HangulInputContext *hic, int mode);
 void hangul_ic_set_keyboard(HangulInputContext *hic,
                            const HangulKeyboard *keyboard);
@@ -124,6 +135,7 @@ typedef struct _HanjaList HanjaList;
 typedef struct _HanjaTable HanjaTable;
 
 HanjaTable*  hanja_table_load(const char *filename);
+HanjaList*   hanja_table_match_exact(const HanjaTable* table, const char *key);
 HanjaList*   hanja_table_match_prefix(const HanjaTable* table, const char *key);
 HanjaList*   hanja_table_match_suffix(const HanjaTable* table, const char *key);
 void         hanja_table_delete(HanjaTable *table);
@@ -131,6 +143,7 @@ void         hanja_table_delete(HanjaTable *table);
 int          hanja_list_get_size(const HanjaList *list);
 const char*  hanja_list_get_key(const HanjaList *list);
 const Hanja* hanja_list_get_nth(const HanjaList *list, unsigned int n);
+const char*  hanja_list_get_nth_key(const HanjaList *list, unsigned int n);
 const char*  hanja_list_get_nth_value(const HanjaList *list, unsigned int n);
 const char*  hanja_list_get_nth_comment(const HanjaList *list, unsigned int n);
 void         hanja_list_delete(HanjaList *list);
@@ -141,12 +154,25 @@ const char*  hanja_get_comment(const Hanja* hanja);
 
 
 /* deprecated */
+bool hangul_is_jaso(ucschar c) LIBHANGUL_DEPRECATED;
+ucschar hangul_jaso_to_jamo(ucschar ch) LIBHANGUL_DEPRECATED;
+ucschar hangul_jaso_to_syllable(ucschar choseong,
+                               ucschar jungseong,
+                               ucschar jongseong) LIBHANGUL_DEPRECATED;
+void    hangul_syllable_to_jaso(ucschar syllable,
+                               ucschar* choseong,
+                               ucschar* jungseong,
+                               ucschar* jongseong) LIBHANGUL_DEPRECATED;
 typedef bool (*HangulICFilter) (ucschar*, ucschar, ucschar, ucschar, void*);
 void hangul_ic_set_filter(HangulInputContext *hic,
-                         HangulICFilter func, void *user_data);
+                         HangulICFilter func, void *user_data) LIBHANGUL_DEPRECATED;
+int  hangul_ic_dvorak_to_qwerty(int qwerty) LIBHANGUL_DEPRECATED;
+
 
 #ifdef __cplusplus
 }
 #endif
 
+#undef LIBHANGUL_DEPRECATED
+
 #endif /* libhangul_hangul_h */
old mode 100755 (executable)
new mode 100644 (file)
index e861aff..4bda161
@@ -1,10 +1,5 @@
-/**
- * @file    hangulctype.c
- * @brief   hangulctype source file
- */
-
 /* libhangul
- * Copyright (C) 2004 - 2006 Choe Hwanjin
+ * Copyright (C) 2004 - 2009 Choe Hwanjin
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 
 #include "hangul.h"
 
-static const ucschar hangul_base    = 0xac00;
+/**
+ * @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;
 static const ucschar jongseong_base = 0x11a7;
@@ -37,59 +57,87 @@ static const int njungseong = 21;
 static const int njongseong = 28;
 
 /**
- * @brief check for a choseong
- * @param c ucs4 code value
- * @return true if the character c falls into choseong class
- *
- * This function check whether c, which must have ucs4 value, falls into
- * choseong (leading consonants) class.
+ * @ingroup hangulctype
+ * @brief 초성인지 확인하는 함수
+ * @param c UCS4 코드 값
+ * @return @a c 가 초성에 해당하면 true를 리턴함, 아니면 false
+ * 
+ * @a c 로 주어진 UCS4 코드가 초성인지 확인한다.
+ * Unicode 5.2 지원
  */
 bool
 hangul_is_choseong(ucschar c)
 {
-    return c >= 0x1100 && c <= 0x1159;
+    return (c >= 0x1100 && c <= 0x115f) ||
+          (c >= 0xa960 && c <= 0xa97c);
+;
 }
 
 /**
- * @brief check for a jungseong
- * @param c ucs4 code value
- * @return true if the character c falls into jungseong class
- *
- * This function check whether c, which must have ucs4 value, falls into
- * jungseong (vowels) class.
+ * @ingroup hangulctype
+ * @brief 중성인지 확인하는 함수
+ * @param c UCS4 코드 값
+ * @return @a c 가 중성에 해당하면 true를 리턴함, 아니면 false
+ * 
+ * @a c 로 주어진 UCS4 코드가 중성인지 확인한다.
+ * Unicode 5.2 지원
  */
 bool
 hangul_is_jungseong(ucschar c)
 {
-    return c >= 0x1161 && c <= 0x11a2;
+    return (c >= 0x1161 && c <= 0x11a2) ||
+          (c >= 0xd7b0 && c <= 0xd7c6);
 }
 
 /**
- * @brief check for a jongseong
- * @param c ucs4 code value
- * @return true if the character c falls into jongseong class
- *
- * This function check whether c, which must have ucs4 value, falls into
- * jongseong (trailing consonants) class.
+ * @ingroup hangulctype
+ * @brief 종성인지 확인하는 함수
+ * @param c UCS4 코드 값
+ * @return @a c 가 종성에 해당하면 true를 리턴함, 아니면 false
+ * 
+ * @a c 로 주어진 UCS4 코드가 종성인지 확인한다.
+ * Unicode 5.2 지원
  */
 bool
 hangul_is_jongseong(ucschar c)
 {
-    return c >= 0x11a8 && c <= 0x11f9;
+    return (c >= 0x11a8 && c <= 0x11f9) ||
+          (c >= 0xd7cb && c <= 0xd7fb);
 }
 
+bool
+hangul_is_combining_mark(ucschar c)
+{
+    return  c == 0x302e || c == 0x302f  ||
+          (c >= 0x0300 && c <= 0x036F) ||
+          (c >= 0x1dc0 && c <= 0x1dff) ||
+          (c >= 0xfe20 && c <= 0xfe2f);
+}
+
+/**
+ * @ingroup hangulctype
+ * @brief 초성이고 조합 가능한지 확인
+ */
 bool
 hangul_is_choseong_conjoinable(ucschar c)
 {
     return c >= 0x1100 && c <= 0x1112;
 }
 
+/**
+ * @ingroup hangulctype
+ * @brief 중성이고 조합 가능한지 확인
+ */
 bool
 hangul_is_jungseong_conjoinable(ucschar c)
 {
     return c >= 0x1161 && c <= 0x1175;
 }
 
+/**
+ * @ingroup hangulctype
+ * @brief 종성이고 조합 가능한지 확인
+ */
 bool
 hangul_is_jongseong_conjoinable(ucschar c)
 {
@@ -97,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)
@@ -111,131 +160,443 @@ hangul_is_syllable(ucschar c)
 }
 
 /**
- * @brief check for a jaso
- * @param c ucs4 code value
- * @return true if the character c falls into jaso class
+ * @ingroup hangulctype
+ * @brief 자모 인지 확인
+ * @param c UCS4 코드 값
+ * @return @a c 가 자모 코드이면 true를 리턴, 그외에는 false
  *
- * This function check whether c, which must have ucs4 value, falls into
- * jaso class; that is choseong, jungseong or jongseong.
+ * @a c 로 주어진 UCS4 코드가 자모 코드인지 확인한다.
+ * Unicode 5.2 지원
  */
 bool
-hangul_is_jaso(ucschar c)
+hangul_is_jamo(ucschar c)
 {
     return hangul_is_choseong(c) ||
           hangul_is_jungseong(c) ||
           hangul_is_jongseong(c);
 }
 
+/** @deprecated 이 함수 대신 hangul_is_jamo()함수를 사용한다. */
+bool
+hangul_is_jaso(ucschar c)
+{
+    return hangul_is_jamo(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_jamo(ucschar c)
+hangul_is_cjamo(ucschar c)
 {
     return c >= 0x3131 && c <= 0x318e;
 }
 
 /**
- * @brief convert a jaso 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 jaso c, which must have ucs4 value, to
- * comaptibility jamo or c if the conversion is failed
+ * 이 함수는 @a c 로 주어진 자모 코드와 같은 형태를 가진 호환 자모 값을
+ * 리턴한다.  자모와 같은 형태를 가진 호환 자모가 없는 경우에는 @a c 의 
+ * 값을 그대로 리턴한다.
  */
 ucschar
-hangul_jaso_to_jamo(ucschar c)
+hangul_jamo_to_cjamo(ucschar c)
 {
-    static ucschar choseong[] = {
-       0x3131,     /* 0x1100 */
-       0x3132,     /* 0x1101 */
-       0x3134,     /* 0x1102 */
-       0x3137,     /* 0x1103 */
-       0x3138,     /* 0x1104 */
-       0x3139,     /* 0x1105 */
-       0x3141,     /* 0x1106 */
-       0x3142,     /* 0x1107 */
-       0x3143,     /* 0x1108 */
-       0x3145,     /* 0x1109 */
-       0x3146,     /* 0x110a */
-       0x3147,     /* 0x110b */
-       0x3148,     /* 0x110c */
-       0x3149,     /* 0x110d */
-       0x314a,     /* 0x110e */
-       0x314b,     /* 0x110f */
-       0x314c,     /* 0x1110 */
-       0x314d,     /* 0x1111 */
-       0x314e,     /* 0x1112 */
+    static unsigned short jamo_table[] = {
+       0x3131,     /* 0x1100 */
+       0x3132,     /* 0x1101 */
+       0x3134,     /* 0x1102 */
+       0x3137,     /* 0x1103 */
+       0x3138,     /* 0x1104 */
+       0x3139,     /* 0x1105 */
+       0x3141,     /* 0x1106 */
+       0x3142,     /* 0x1107 */
+       0x3143,     /* 0x1108 */
+       0x3145,     /* 0x1109 */
+       0x3146,     /* 0x110a */
+       0x3147,     /* 0x110b */
+       0x3148,     /* 0x110c */
+       0x3149,     /* 0x110d */
+       0x314a,     /* 0x110e */
+       0x314b,     /* 0x110f */
+       0x314c,     /* 0x1110 */
+       0x314d,     /* 0x1111 */
+       0x314e,     /* 0x1112 */
+       0x0000,     /* 0x1113 */
+       0x3165,     /* 0x1114 */
+       0x3166,     /* 0x1115 */
+       0x0000,     /* 0x1116 */
+       0x0000,     /* 0x1117 */
+       0x0000,     /* 0x1118 */
+       0x0000,     /* 0x1119 */
+       0x3140,     /* 0x111a */
+       0x0000,     /* 0x111b */
+       0x316e,     /* 0x111c */
+       0x3171,     /* 0x111d */
+       0x3172,     /* 0x111e */
+       0x0000,     /* 0x111f */
+       0x3173,     /* 0x1120 */
+       0x3144,     /* 0x1121 */
+       0x3174,     /* 0x1122 */
+       0x3175,     /* 0x1123 */
+       0x0000,     /* 0x1124 */
+       0x0000,     /* 0x1125 */
+       0x0000,     /* 0x1126 */
+       0x3176,     /* 0x1127 */
+       0x0000,     /* 0x1128 */
+       0x3177,     /* 0x1129 */
+       0x0000,     /* 0x112a */
+       0x3178,     /* 0x112b */
+       0x3179,     /* 0x112c */
+       0x317a,     /* 0x112d */
+       0x317b,     /* 0x112e */
+       0x317c,     /* 0x112f */
+       0x0000,     /* 0x1130 */
+       0x0000,     /* 0x1131 */
+       0x317d,     /* 0x1132 */
+       0x0000,     /* 0x1133 */
+       0x0000,     /* 0x1134 */
+       0x0000,     /* 0x1135 */
+       0x317e,     /* 0x1136 */
+       0x0000,     /* 0x1137 */
+       0x0000,     /* 0x1138 */
+       0x0000,     /* 0x1139 */
+       0x0000,     /* 0x113a */
+       0x0000,     /* 0x113b */
+       0x0000,     /* 0x113c */
+       0x0000,     /* 0x113d */
+       0x0000,     /* 0x113e */
+       0x0000,     /* 0x113f */
+       0x317f,     /* 0x1140 */
+       0x0000,     /* 0x1141 */
+       0x0000,     /* 0x1142 */
+       0x0000,     /* 0x1143 */
+       0x0000,     /* 0x1144 */
+       0x0000,     /* 0x1145 */
+       0x0000,     /* 0x1146 */
+       0x3180,     /* 0x1147 */
+       0x0000,     /* 0x1148 */
+       0x0000,     /* 0x1149 */
+       0x0000,     /* 0x114a */
+       0x0000,     /* 0x114b */
+       0x3181,     /* 0x114c */
+       0x0000,     /* 0x114d */
+       0x0000,     /* 0x114e */
+       0x0000,     /* 0x114f */
+       0x0000,     /* 0x1150 */
+       0x0000,     /* 0x1151 */
+       0x0000,     /* 0x1152 */
+       0x0000,     /* 0x1153 */
+       0x0000,     /* 0x1154 */
+       0x0000,     /* 0x1155 */
+       0x0000,     /* 0x1156 */
+       0x3184,     /* 0x1157 */
+       0x3185,     /* 0x1158 */
+       0x3186,     /* 0x1159 */
+       0x0000,     /* 0x115a */
+       0x0000,     /* 0x115b */
+       0x0000,     /* 0x115c */
+       0x0000,     /* 0x115d */
+       0x0000,     /* 0x115e */
+       0x0000,     /* 0x115f */
+       0x3164,     /* 0x1160 */
+       0x314f,     /* 0x1161 */
+       0x3150,     /* 0x1162 */
+       0x3151,     /* 0x1163 */
+       0x3152,     /* 0x1164 */
+       0x3153,     /* 0x1165 */
+       0x3154,     /* 0x1166 */
+       0x3155,     /* 0x1167 */
+       0x3156,     /* 0x1168 */
+       0x3157,     /* 0x1169 */
+       0x3158,     /* 0x116a */
+       0x3159,     /* 0x116b */
+       0x315a,     /* 0x116c */
+       0x315b,     /* 0x116d */
+       0x315c,     /* 0x116e */
+       0x315d,     /* 0x116f */
+       0x315e,     /* 0x1170 */
+       0x315f,     /* 0x1171 */
+       0x3160,     /* 0x1172 */
+       0x3161,     /* 0x1173 */
+       0x3162,     /* 0x1174 */
+       0x3163,     /* 0x1175 */
+       0x0000,     /* 0x1176 */
+       0x0000,     /* 0x1177 */
+       0x0000,     /* 0x1178 */
+       0x0000,     /* 0x1179 */
+       0x0000,     /* 0x117a */
+       0x0000,     /* 0x117b */
+       0x0000,     /* 0x117c */
+       0x0000,     /* 0x117d */
+       0x0000,     /* 0x117e */
+       0x0000,     /* 0x117f */
+       0x0000,     /* 0x1180 */
+       0x0000,     /* 0x1181 */
+       0x0000,     /* 0x1182 */
+       0x0000,     /* 0x1183 */
+       0x3187,     /* 0x1184 */
+       0x3188,     /* 0x1185 */
+       0x0000,     /* 0x1186 */
+       0x0000,     /* 0x1187 */
+       0x3189,     /* 0x1188 */
+       0x0000,     /* 0x1189 */
+       0x0000,     /* 0x118a */
+       0x0000,     /* 0x118b */
+       0x0000,     /* 0x118c */
+       0x0000,     /* 0x118d */
+       0x0000,     /* 0x118e */
+       0x0000,     /* 0x118f */
+       0x0000,     /* 0x1190 */
+       0x318a,     /* 0x1191 */
+       0x318b,     /* 0x1192 */
+       0x0000,     /* 0x1193 */
+       0x318c,     /* 0x1194 */
+       0x0000,     /* 0x1195 */
+       0x0000,     /* 0x1196 */
+       0x0000,     /* 0x1197 */
+       0x0000,     /* 0x1198 */
+       0x0000,     /* 0x1199 */
+       0x0000,     /* 0x119a */
+       0x0000,     /* 0x119b */
+       0x0000,     /* 0x119c */
+       0x0000,     /* 0x119d */
+       0x318d,     /* 0x119e */
+       0x0000,     /* 0x119f */
+       0x0000,     /* 0x11a0 */
+       0x318e,     /* 0x11a1 */
+       0x0000,     /* 0x11a2 */
+       0x0000,     /* 0x11a3 */
+       0x0000,     /* 0x11a4 */
+       0x0000,     /* 0x11a5 */
+       0x0000,     /* 0x11a6 */
+       0x0000,     /* 0x11a7 */
+       0x0000,     /* 0x11a8 */
+       0x0000,     /* 0x11a9 */
+       0x3133,     /* 0x11aa */
+       0x0000,     /* 0x11ab */
+       0x3135,     /* 0x11ac */
+       0x3136,     /* 0x11ad */
+       0x0000,     /* 0x11ae */
+       0x0000,     /* 0x11af */
+       0x313a,     /* 0x11b0 */
+       0x313b,     /* 0x11b1 */
+       0x313c,     /* 0x11b2 */
+       0x313d,     /* 0x11b3 */
+       0x313e,     /* 0x11b4 */
+       0x313f,     /* 0x11b5 */
+       0x0000,     /* 0x11b6 */
+       0x0000,     /* 0x11b7 */
+       0x0000,     /* 0x11b8 */
+       0x0000,     /* 0x11b9 */
+       0x0000,     /* 0x11ba */
+       0x0000,     /* 0x11bb */
+       0x0000,     /* 0x11bc */
+       0x0000,     /* 0x11bd */
+       0x0000,     /* 0x11be */
+       0x0000,     /* 0x11bf */
+       0x0000,     /* 0x11c0 */
+       0x0000,     /* 0x11c1 */
+       0x0000,     /* 0x11c2 */
+       0x0000,     /* 0x11c3 */
+       0x0000,     /* 0x11c4 */
+       0x0000,     /* 0x11c5 */
+       0x0000,     /* 0x11c6 */
+       0x3167,     /* 0x11c7 */
+       0x3168,     /* 0x11c8 */
+       0x0000,     /* 0x11c9 */
+       0x0000,     /* 0x11ca */
+       0x0000,     /* 0x11cb */
+       0x3169,     /* 0x11cc */
+       0x0000,     /* 0x11cd */
+       0x316a,     /* 0x11ce */
+       0x0000,     /* 0x11cf */
+       0x0000,     /* 0x11d0 */
+       0x0000,     /* 0x11d1 */
+       0x0000,     /* 0x11d2 */
+       0x316b,     /* 0x11d3 */
+       0x0000,     /* 0x11d4 */
+       0x0000,     /* 0x11d5 */
+       0x0000,     /* 0x11d6 */
+       0x316c,     /* 0x11d7 */
+       0x0000,     /* 0x11d8 */
+       0x316d,     /* 0x11d9 */
+       0x0000,     /* 0x11da */
+       0x0000,     /* 0x11db */
+       0x0000,     /* 0x11dc */
+       0x316f,     /* 0x11dd */
+       0x0000,     /* 0x11de */
+       0x3170,     /* 0x11df */
+       0x0000,     /* 0x11e0 */
+       0x0000,     /* 0x11e1 */
+       0x0000,     /* 0x11e2 */
+       0x0000,     /* 0x11e3 */
+       0x0000,     /* 0x11e4 */
+       0x0000,     /* 0x11e5 */
+       0x0000,     /* 0x11e6 */
+       0x0000,     /* 0x11e7 */
+       0x0000,     /* 0x11e8 */
+       0x0000,     /* 0x11e9 */
+       0x0000,     /* 0x11ea */
+       0x0000,     /* 0x11eb */
+       0x0000,     /* 0x11ec */
+       0x0000,     /* 0x11ed */
+       0x0000,     /* 0x11ee */
+       0x0000,     /* 0x11ef */
+       0x0000,     /* 0x11f0 */
+       0x3182,     /* 0x11f1 */
+       0x3183,     /* 0x11f2 */
+       0x0000,     /* 0x11f3 */
+       0x0000,     /* 0x11f4 */
+       0x0000,     /* 0x11f5 */
+       0x0000,     /* 0x11f6 */
+       0x0000,     /* 0x11f7 */
+       0x0000,     /* 0x11f8 */
+       0x0000,     /* 0x11f9 */
+       0x0000,     /* 0x11fa */
+       0x0000,     /* 0x11fb */
+       0x0000,     /* 0x11fc */
+       0x0000,     /* 0x11fd */
+       0x0000,     /* 0x11fe */
+       0x0000,     /* 0x11ff */
     };
 
-    static ucschar jungseong[] = {
-       0x314f,     /* 0x1161 */
-       0x3150,     /* 0x1162 */
-       0x3151,     /* 0x1163 */
-       0x3152,     /* 0x1164 */
-       0x3153,     /* 0x1165 */
-       0x3154,     /* 0x1166 */
-       0x3155,     /* 0x1167 */
-       0x3156,     /* 0x1168 */
-       0x3157,     /* 0x1169 */
-       0x3158,     /* 0x116a */
-       0x3159,     /* 0x116b */
-       0x315a,     /* 0x116c */
-       0x315b,     /* 0x116d */
-       0x315c,     /* 0x116e */
-       0x315d,     /* 0x116f */
-       0x315e,     /* 0x1170 */
-       0x315f,     /* 0x1171 */
-       0x3160,     /* 0x1172 */
-       0x3161,     /* 0x1173 */
-       0x3162,     /* 0x1174 */
-       0x3163      /* 0x1175 */
+    static unsigned short jamo_ext_A_table[] = {
+       0x0000,     /* 0xa960 */
+       0x0000,     /* 0xa961 */
+       0x0000,     /* 0xa962 */
+       0x0000,     /* 0xa963 */
+       0x313a,     /* 0xa964 */
+       0x0000,     /* 0xa965 */
+       0x316a,     /* 0xa966 */
+       0x0000,     /* 0xa967 */
+       0x313b,     /* 0xa968 */
+       0x313c,     /* 0xa969 */
+       0x0000,     /* 0xa96a */
+       0x0000,     /* 0xa96b */
+       0x313d,     /* 0xa96c */
+       0x0000,     /* 0xa96d */
+       0x0000,     /* 0xa96e */
+       0x0000,     /* 0xa96f */
+       0x0000,     /* 0xa970 */
+       0x316f,     /* 0xa971 */
+       0x0000,     /* 0xa972 */
+       0x0000,     /* 0xa973 */
+       0x0000,     /* 0xa974 */
+       0x0000,     /* 0xa975 */
+       0x0000,     /* 0xa976 */
+       0x0000,     /* 0xa977 */
+       0x0000,     /* 0xa978 */
+       0x0000,     /* 0xa979 */
+       0x0000,     /* 0xa97a */
+       0x0000,     /* 0xa97b */
+       0x0000,     /* 0xa97c */
     };
 
-    static ucschar jongseong[] = {
-       0x3131,     /* 0x11a8 */
-       0x3132,     /* 0x11a9 */
-       0x3133,     /* 0x11aa */
-       0x3134,     /* 0x11ab */
-       0x3135,     /* 0x11ac */
-       0x3136,     /* 0x11ad */
-       0x3137,     /* 0x11ae */
-       0x3139,     /* 0x11af */
-       0x313a,     /* 0x11b0 */
-       0x313b,     /* 0x11b1 */
-       0x313c,     /* 0x11b2 */
-       0x313d,     /* 0x11b3 */
-       0x313e,     /* 0x11b4 */
-       0x313f,     /* 0x11b5 */
-       0x3140,     /* 0x11b6 */
-       0x3141,     /* 0x11b7 */
-       0x3142,     /* 0x11b8 */
-       0x3144,     /* 0x11b9 */
-       0x3145,     /* 0x11ba */
-       0x3146,     /* 0x11bb */
-       0x3147,     /* 0x11bc */
-       0x3148,     /* 0x11bd */
-       0x314a,     /* 0x11be */
-       0x314b,     /* 0x11bf */
-       0x314c,     /* 0x11c0 */
-       0x314d,     /* 0x11c1 */
-       0x314e      /* 0x11c2 */
+    static unsigned short jamo_ext_B_table[] = {
+       0x0000,     /* 0xd7b0 */
+       0x0000,     /* 0xd7b1 */
+       0x0000,     /* 0xd7b2 */
+       0x0000,     /* 0xd7b3 */
+       0x0000,     /* 0xd7b4 */
+       0x0000,     /* 0xd7b5 */
+       0x0000,     /* 0xd7b6 */
+       0x0000,     /* 0xd7b7 */
+       0x0000,     /* 0xd7b8 */
+       0x0000,     /* 0xd7b9 */
+       0x0000,     /* 0xd7ba */
+       0x0000,     /* 0xd7bb */
+       0x0000,     /* 0xd7bc */
+       0x0000,     /* 0xd7bd */
+       0x0000,     /* 0xd7be */
+       0x0000,     /* 0xd7bf */
+       0x0000,     /* 0xd7c0 */
+       0x0000,     /* 0xd7c1 */
+       0x0000,     /* 0xd7c2 */
+       0x0000,     /* 0xd7c3 */
+       0x0000,     /* 0xd7c4 */
+       0x0000,     /* 0xd7c5 */
+       0x0000,     /* 0xd7c6 */
+       0x0000,     /* 0xd7cb */
+       0x0000,     /* 0xd7cc */
+       0x3138,     /* 0xd7cd */
+       0x0000,     /* 0xd7ce */
+       0x0000,     /* 0xd7cf */
+       0x0000,     /* 0xd7d0 */
+       0x0000,     /* 0xd7d1 */
+       0x0000,     /* 0xd7d2 */
+       0x0000,     /* 0xd7d3 */
+       0x0000,     /* 0xd7d4 */
+       0x0000,     /* 0xd7d5 */
+       0x0000,     /* 0xd7d6 */
+       0x0000,     /* 0xd7d7 */
+       0x0000,     /* 0xd7d8 */
+       0x0000,     /* 0xd7d9 */
+       0x0000,     /* 0xd7da */
+       0x0000,     /* 0xd7db */
+       0x0000,     /* 0xd7dc */
+       0x0000,     /* 0xd7dd */
+       0x0000,     /* 0xd7de */
+       0x0000,     /* 0xd7df */
+       0x0000,     /* 0xd7e0 */
+       0x0000,     /* 0xd7e1 */
+       0x0000,     /* 0xd7e2 */
+       0x3173,     /* 0xd7e3 */
+       0x0000,     /* 0xd7e4 */
+       0x0000,     /* 0xd7e5 */
+       0x3143,     /* 0xd7e6 */
+       0x3175,     /* 0xd7e7 */
+       0x3176,     /* 0xd7e8 */
+       0x0000,     /* 0xd7e9 */
+       0x0000,     /* 0xd7ea */
+       0x0000,     /* 0xd7eb */
+       0x0000,     /* 0xd7ec */
+       0x0000,     /* 0xd7ed */
+       0x0000,     /* 0xd7ee */
+       0x317e,     /* 0xd7ef */
+       0x0000,     /* 0xd7f0 */
+       0x0000,     /* 0xd7f1 */
+       0x0000,     /* 0xd7f2 */
+       0x0000,     /* 0xd7f3 */
+       0x0000,     /* 0xd7f4 */
+       0x0000,     /* 0xd7f5 */
+       0x0000,     /* 0xd7f6 */
+       0x0000,     /* 0xd7f7 */
+       0x0000,     /* 0xd7f8 */
+       0x3149,     /* 0xd7f9 */
+       0x0000,     /* 0xd7fa */
+       0x0000,     /* 0xd7fb */
     };
 
-    if (c >= 0x1100 && c <= 0x1112) {
-       return choseong[c - 0x1100];
-    } else if (c >= 0x1161 && c <= 0x1175) {
-       return jungseong[c - 0x1161];
-    } else if (c >= 0x11a8 && c <= 0x11c2) {
-       return jongseong[c - 0x11a8];
+    ucschar ret = 0;
+
+    if (c >= 0x1100 && c <= 0x11ff) {
+       ret = jamo_table[c - 0x1100];
+    } else if (c >= 0xa960 && c <= 0xa97c) {
+       ret = jamo_ext_A_table[c - 0xa960];
+    } else if (c >= 0xd7b0 && c <= 0xd7fb) {
+       ret = jamo_ext_B_table[c - 0xd7b0];
     }
 
-    return c;
+    if (ret == 0)
+       ret = c;
+
+    return ret;
+}
+
+/** @deprecated 이 함수 대신 hangul_jamo_to_cjamo()함수를 사용한다. */
+ucschar
+hangul_jaso_to_jamo(ucschar c)
+{
+    return hangul_jamo_to_cjamo(c);
 }
 
 ucschar
@@ -342,17 +703,21 @@ 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 jaso 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_jaso_to_syllable(ucschar choseong, ucschar jungseong, ucschar jongseong)
+hangul_jamo_to_syllable(ucschar choseong, ucschar jungseong, ucschar jongseong)
 {
     ucschar c;
 
@@ -372,12 +737,32 @@ hangul_jaso_to_syllable(ucschar choseong, ucschar jungseong, ucschar jongseong)
     jongseong -= jongseong_base;
 
     c = ((choseong * njungseong) + jungseong) * njongseong + jongseong
-       + hangul_base;
+       + syllable_base;
     return c;
 }
 
+/** @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_jaso(ucschar syllable,
+hangul_syllable_to_jamo(ucschar syllable,
                        ucschar* choseong,
                        ucschar* jungseong,
                        ucschar* jongseong)
@@ -392,7 +777,7 @@ hangul_syllable_to_jaso(ucschar syllable,
     if (!hangul_is_syllable(syllable))
        return;
 
-    syllable -= hangul_base;
+    syllable -= syllable_base;
     if (jongseong != NULL) {
        if (syllable % njongseong != 0)
            *jongseong = jongseong_base + syllable % njongseong;
@@ -408,3 +793,377 @@ hangul_syllable_to_jaso(ucschar syllable,
        *choseong = choseong_base + syllable;
     }
 }
+
+/** @deprecated 이 함수 대신 hangul_syllable_to_jamo함수를 사용한다. */
+void
+hangul_syllable_to_jaso(ucschar syllable,
+                       ucschar* choseong,
+                       ucschar* jungseong,
+                       ucschar* jongseong)
+{
+    return hangul_syllable_to_jamo(syllable, choseong, jungseong, jongseong);
+}
+
+static inline bool 
+is_syllable_boundary(ucschar prev, ucschar next)
+{
+    if (hangul_is_choseong(prev)) {
+       if (hangul_is_choseong(next))
+           return false;
+       if (hangul_is_jungseong(next))
+           return false;
+       if (hangul_is_syllable(next))
+           return false;
+       if (hangul_is_combining_mark(next))
+           return false;
+       if (next == HANGUL_JUNGSEONG_FILLER)
+           return false;
+    } else if (prev == HANGUL_CHOSEONG_FILLER) {
+       if (hangul_is_jungseong(next))
+           return false;
+       if (next == HANGUL_JUNGSEONG_FILLER)
+           return false;
+    } else if (hangul_is_jungseong(prev)) {
+       if (hangul_is_jungseong(next))
+           return false;
+       if (hangul_is_jongseong(next))
+           return false;
+       if (hangul_is_combining_mark(next))
+           return false;
+    } else if (prev == HANGUL_JUNGSEONG_FILLER) {
+       if (hangul_is_jongseong(next))
+           return false;
+    } else if (hangul_is_jongseong(prev)) {
+       if (hangul_is_jongseong(next))
+           return false;
+       if (hangul_is_combining_mark(next))
+           return false;
+    } else if (hangul_is_syllable(prev)) {
+       if ((prev - syllable_base) % njongseong == 0) {
+           // 종성이 없는 음절: LV
+           if (hangul_is_jungseong(next))
+               return false;
+           if (hangul_is_jongseong(next))
+               return false;
+       } else {
+           // 종성이 있는 음절: LVT
+           if (hangul_is_jongseong(next))
+               return false;
+       }
+       if (hangul_is_combining_mark(next))
+           return false;
+    }
+    
+    return true;
+}
+
+static inline ucschar
+choseong_compress(ucschar a, ucschar b)
+{
+    if (a == 0)
+       return b;
+
+    if (a == 0x1100 && b == 0x1100)
+       return 0x1101;
+    if (a == 0x1103 && b == 0x1103)
+       return 0x1104;
+    if (a == 0x1107 && b == 0x1107)
+       return 0x1108;
+    if (a == 0x1109 && b == 0x1109)
+       return 0x110A;
+    if (a == 0x110c && b == 0x110c)
+       return 0x110d;
+    return 0;
+}
+
+static inline ucschar
+jungseong_compress(ucschar a, ucschar b)
+{
+    if (a == 0)
+       return b;
+
+    if (a == 0x1169) {
+       if (b == 0x1161)
+           return 0x116a;
+       if (b == 0x1162)
+           return 0x116b;
+       if (b == 0x1175)
+           return 0x116c;
+    }
+    if (a == 0x116e) {
+       if (b == 0x1165)
+           return 0x116f;
+       if (b == 0x1166)
+           return 0x1170;
+       if (b == 0x1175)
+           return 0x1171;
+    }
+    if (b == 0x1175) {
+       if (a == 0x1173)
+           return 0x1174;
+       if (a == 0x1161)
+           return 0x1162;
+       if (a == 0x1163)
+           return 0x1164;
+       if (a == 0x1165)
+           return 0x1166;
+       if (a == 0x1167)
+           return 0x1168;
+    }
+
+    return 0;
+}
+
+static inline ucschar
+jongseong_compress(ucschar a, ucschar b)
+{
+    if (a == 0)
+       return b;
+    
+    if (a == 0x11a8) {
+       if (b == 0x11a8)
+           return 0x11a9;
+       if (b == 0x11ba)
+           return 0x11aa;
+    }
+    if (a == 0x11ab) {
+       if (b == 0x11b0)
+           return 0x11ab;
+       if (b == 0x11c2)
+           return 0x11ad;
+    }
+    if (a == 0x11af) {
+       if (b == 0x11a8)
+           return 0x11b0;
+       if (b == 0x11b7)
+           return 0x11b1;
+       if (b == 0x11b8)
+           return 0x11b2;
+       if (b == 0x11ba)
+           return 0x11b3;
+       if (b == 0x11c0)
+           return 0x11b4;
+       if (b == 0x11c1)
+           return 0x11b5;
+       if (b == 0x11c2)
+           return 0x11b6;
+    }
+    if (a == 0x11b8 && b == 0x11ba)
+       return 0x11b9;
+    if (a == 0x11ba && b == 0x11ba)
+       return 0x11bb;
+
+    return 0;
+}
+
+static inline ucschar
+build_syllable(const ucschar* str, size_t len)
+{
+    int i;
+    ucschar cho = 0, jung = 0, jong = 0;
+
+    i = 0;
+    while (i < len && hangul_is_choseong_conjoinable(str[i])) {
+       cho = choseong_compress(cho, str[i]);
+       if (cho == 0)
+           return 0;
+       i++;
+    }
+
+    while (i < len && hangul_is_jungseong_conjoinable(str[i])) {
+       jung = jungseong_compress(jung, str[i]);
+       if (jung == 0)
+           return 0;
+       i++;
+    }
+
+    while (i < len && hangul_is_jongseong_conjoinable(str[i])) {
+       jong = jongseong_compress(jong, str[i]);
+       if (jong == 0)
+           return 0;
+       i++;
+    }
+
+    if (i < len)
+       return 0;
+
+    return hangul_jamo_to_syllable(cho, jung, jong);
+}
+
+/**
+ * @ingroup hangulctype
+ * @brief 한 음절에 해당하는 코드의 갯수를 구하는 함수
+ * @param str 음절의 길이를 구할 스트링
+ * @param max_len @a str 에서 읽을 길이의 제한값
+ * @return 한 음절에 해당하는 코드의 갯수
+ *
+ * 이 함수는 @a str 에서 한 음절에 해당하는 코드의 갯수를 구한다. 
+ * 한 음절에 해당하는 코드의 갯수가 @a max_len 보다 많다면 @a max_len 을 
+ * 반환한다. 한 음절이라고 판단하는 기준은 L*V*T+ 패턴에 따른다. 이 패턴은
+ * regular expression의 컨벤션을 따른 것으로, 1개 이상의 초성과 중성, 0개
+ * 이상의 종성이 모인 자모 스트링을 한 음절로 인식한다는 뜻이다. 예를 들면
+ * 다음과 같은 자모 스트링도 한 음절로 인식한다.
+ *
+ *  예) "ㅂ ㅂ ㅜ ㅔ ㄹ ㄱ" -> "쀍"
+ * 
+ * 따라서 위 경우에는 6을 반환하게 된다. 
+ *
+ * 일반적으로는 방점(U+302E, U+302F)까지 한 음절로 인식하겠지만, 이 함수는
+ * 음절과 자모간 변환을 편리하게 하기 위해 구현된 것으로 방점은 다른 음절로 
+ * 인식한다.
+ *
+ * @a str 이 자모 코드에 해당하지 않는 경우에는 1을 반환한다.
+ *
+ * 이 함수는 자모 스트링에서 총 음절의 갯수를 구하는 함수가 아님에 주의한다.
+ */
+int
+hangul_syllable_len(const ucschar* str, int max_len)
+{
+    int i = 0;
+
+    if (max_len == 0)
+       return 0;
+
+    if (str[i] != 0) {
+       for (i = 1; i < max_len; i++) {
+           if (str[i] == 0)
+               break;
+
+           if (is_syllable_boundary(str[i - 1], str[i]))
+               break;
+       }
+    }
+
+    return i;
+}
+
+/**
+ * @ingroup hangulctype
+ * @brief @a iter를 기준으로 이전 음절의 첫자모 글자에 대한 포인터를 구하는 함수
+ * @param iter 현재 위치
+ * @param begin 스트링의 시작위치, 포인터가 이동할 한계값
+ * @return 이전 음절의 첫번째 자모에 대한 포인터
+ *
+ * 이 함수는 @a iter로 주어진 자모 스트링의 포인터를 기준으로 이전 음절의 
+ * 첫번째 자모에 대한 포인터를 리턴한다. 음절을 찾기위해서 begin보다 
+ * 앞쪽으로 이동하지 않는다. 
+ *
+ * 한 음절이라고 판단하는 기준은 L*V*T+M? 패턴에 따른다.
+ */
+const ucschar*
+hangul_syllable_iterator_prev(const ucschar* iter, const ucschar* begin)
+{
+    if (iter > begin)
+       iter--;
+
+    while (iter > begin) {
+       ucschar prev = iter[-1];
+       ucschar curr = iter[0];
+       if (is_syllable_boundary(prev, curr))
+           break;
+       iter--;
+    }
+
+    return iter;
+}
+
+/**
+ * @ingroup hangulctype
+ * @brief @a iter를 기준으로 다음 음절의 첫자모 글자에 대한 포인터를 구하는 함수
+ * @param iter 현재 위치
+ * @param end 스트링의 끝위치, 포인터가 이동할 한계값
+ * @return 다음 음절의 첫번째 자모에 대한 포인터
+ *
+ * 이 함수는 @a iter로 주어진 자모 스트링의 포인터를 기준으로 다음 음절의 
+ * 첫번째 자모에 대한 포인터를 리턴한다. 음절을 찾기위해서 end를 넘어
+ * 이동하지 않는다. 
+ *
+ * 한 음절이라고 판단하는 기준은 L*V*T+M? 패턴에 따른다.
+ */
+const ucschar*
+hangul_syllable_iterator_next(const ucschar* iter, const ucschar* end)
+{
+    if (iter < end)
+       iter++;
+
+    while (iter < end) {
+       ucschar prev = iter[-1];
+       ucschar curr = iter[0];
+       if (is_syllable_boundary(prev, curr))
+           break;
+       iter++;
+    }
+
+    return iter;
+}
+
+/**
+ * @ingroup hangulctype
+ * @brief 자모 스트링을 음절 스트링으로 변환
+ * @param dest 음절형으로 변환된 결과가 저장될 버퍼
+ * @param destlen 결과를 저장할 버퍼의 길이(ucschar 코드 단위)
+ * @param src 변환할 자모 스트링
+ * @param srclen 변환할 자모 스트링의 길이(ucschar 코드 단위)
+ * @return @a destlen 에 저장한 코드의 갯수
+ *
+ * 이 함수는 L+V+T*M? 패턴에 따라 자모 스트링 변환을 시도한다. 한 음절을 
+ * 판단하는 기준은 @ref hangul_syllable_len 을 참조한다.
+ * 만일 @a src 가 적절한 음절형태로 변환이 불가능한 경우에는 자모 스트링이
+ * 그대로 복사된다.
+ *
+ * 이 함수는 자모 스트링 @a src 를 음절형으로 변환하여 @a dest 에 저장한다.
+ * @a srclen 에 지정된 갯수만큼 읽고, @a destlen 에 지정된 길이 이상 쓰지
+ * 않는다.  @a srclen 이 -1이라면 @a src 는 0으로 끝나는 스트링으로 가정하고
+ * 0을 제외한 길이까지 변환을 시도한다. 따라서 변환된 결과 스트링은 0으로 
+ * 끝나지 않는다. 만일 0으로 끝나는 스트링을 만들고 싶다면 다음과 같이 한다.
+ *
+ * @code
+ * int n = hangul_jamos_to_syllables(dest, destlen, src, srclen);
+ * dest[n] = 0;
+ * @endcode
+ */
+int
+hangul_jamos_to_syllables(ucschar* dest, int destlen, const ucschar* src, int srclen)
+{
+    ucschar* d;
+    const ucschar* s;
+
+    int inleft;
+    int outleft;
+    int n;
+
+    if (srclen < 0) {
+       s = src;
+       while (*s != 0)
+           s++;
+       srclen = s - src;
+    }
+
+    s = src;
+    d = dest;
+    inleft = srclen;
+    outleft = destlen;
+
+    n = hangul_syllable_len(s, inleft);
+    while (n > 0 && inleft > 0 && outleft > 0) {
+       ucschar c = build_syllable(s, n);
+       if (c != 0) {
+           *d = c;
+           d++;
+           outleft--;
+       } else {
+           int i;
+           for (i = 0; i < n && i < outleft; i++) {
+               d[i] = s[i];
+           }
+           d += i;
+           outleft -= i;
+       }
+
+       s += n;
+       inleft -= n;
+       n = hangul_syllable_len(s, inleft);
+    }
+
+    return destlen - outleft;
+}
old mode 100755 (executable)
new mode 100644 (file)
index 0f92957..6e47da2
@@ -1,5 +1,5 @@
 /* libhangul
- * Copyright (C) 2004 - 2006 Choe Hwanjin
+ * Copyright (C) 2004 - 2009 Choe Hwanjin
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -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
  */
 
 #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
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
 #define HANGUL_KEYBOARD_TABLE_SIZE 0x80
 
 typedef void   (*HangulOnTranslate)  (HangulInputContext*,
@@ -87,6 +231,8 @@ struct _HangulInputContext {
 
     HangulICFilter filter;
     void *filter_data;
+
+    unsigned int use_jamo_mode_only : 1;
 };
 
 #include "hangulkeyboard.h"
@@ -121,11 +267,21 @@ static const HangulKeyboard hangul_keyboard_3yet = {
     (ucschar*)hangul_keyboard_table_3yet
 };
 
+static const HangulKeyboard hangul_keyboard_romaja = {
+    HANGUL_KEYBOARD_TYPE_ROMAJA,
+    (ucschar*)hangul_keyboard_table_romaja
+};
+
 static const HangulCombination hangul_combination_default = {
     N_ELEMENTS(hangul_combination_table_default),
     (HangulCombinationItem*)hangul_combination_table_default
 };
 
+static const HangulCombination hangul_combination_romaja = {
+    N_ELEMENTS(hangul_combination_table_romaja),
+    (HangulCombinationItem*)hangul_combination_table_romaja
+};
+
 static const HangulCombination hangul_combination_full = {
     N_ELEMENTS(hangul_combination_table_full),
     (HangulCombinationItem*)hangul_combination_table_full
@@ -400,18 +556,18 @@ hangul_jaso_to_string(ucschar cho, ucschar jung, ucschar jong,
     if (cho) {
        if (jung) {
            /* have cho, jung, jong or no jong */
-           ch = hangul_jaso_to_syllable(cho, jung, jong);
+           ch = hangul_jamo_to_syllable(cho, jung, jong);
            buf[n++] = ch;
        } else {
            if (jong) {
                /* have cho, jong */
-               ch = hangul_jaso_to_jamo(cho);
+               ch = hangul_jamo_to_cjamo(cho);
                buf[n++] = ch;
-               ch = hangul_jaso_to_jamo(jong);
+               ch = hangul_jamo_to_cjamo(jong);
                buf[n++] = ch;
            } else {
                /* have cho */
-               ch = hangul_jaso_to_jamo(cho);
+               ch = hangul_jamo_to_cjamo(cho);
                buf[n++] = ch;
            }
        }
@@ -419,19 +575,19 @@ hangul_jaso_to_string(ucschar cho, ucschar jung, ucschar jong,
        if (jung) {
            if (jong) {
                /* have jung, jong */
-               ch = hangul_jaso_to_jamo(jung);
+               ch = hangul_jamo_to_cjamo(jung);
                buf[n++] = ch;
-               ch = hangul_jaso_to_jamo(jong);
+               ch = hangul_jamo_to_cjamo(jong);
                buf[n++] = ch;
            } else {
                /* have jung */
-               ch = hangul_jaso_to_jamo(jung);
+               ch = hangul_jamo_to_cjamo(jung);
                buf[n++] = ch;
            }
        } else {
            if (jong) { 
                /* have jong */
-               ch = hangul_jaso_to_jamo(jong);
+               ch = hangul_jamo_to_cjamo(jong);
                buf[n++] = ch;
            } else {
                /* have nothing */
@@ -461,17 +617,24 @@ hangul_buffer_backspace(HangulBuffer *buffer)
        if (ch == 0)
            return false;
 
-       if (hangul_is_choseong(ch)) {
-           ch = hangul_buffer_peek(buffer);
-           buffer->choseong = hangul_is_choseong(ch) ? ch : 0;
-           return true;
-       } else if (hangul_is_jungseong(ch)) {
-           ch = hangul_buffer_peek(buffer);
-           buffer->jungseong = hangul_is_jungseong(ch) ? ch : 0;
-           return true;
-       } else if (hangul_is_jongseong(ch)) {
-           ch = hangul_buffer_peek(buffer);
-           buffer->jongseong = hangul_is_jongseong(ch) ? ch : 0;
+       if (buffer->index >= 0) {
+           if (hangul_is_choseong(ch)) {
+               ch = hangul_buffer_peek(buffer);
+               buffer->choseong = hangul_is_choseong(ch) ? ch : 0;
+               return true;
+           } else if (hangul_is_jungseong(ch)) {
+               ch = hangul_buffer_peek(buffer);
+               buffer->jungseong = hangul_is_jungseong(ch) ? ch : 0;
+               return true;
+           } else if (hangul_is_jongseong(ch)) {
+               ch = hangul_buffer_peek(buffer);
+               buffer->jongseong = hangul_is_jongseong(ch) ? ch : 0;
+               return true;
+           }
+       } else {
+           buffer->choseong = 0;
+           buffer->jungseong = 0;
+           buffer->jongseong = 0;
            return true;
        }
     }
@@ -507,7 +670,7 @@ hangul_ic_push(HangulInputContext *hic, ucschar c)
            return false;
        }
     } else {
-       if (!hangul_is_jaso(c)) {
+       if (!hangul_is_jamo(c)) {
            hangul_ic_flush_internal(hic);
            return false;
        }
@@ -587,7 +750,7 @@ hangul_ic_process_jamo(HangulInputContext *hic, ucschar ch)
     ucschar jong;
     ucschar combined;
 
-    if (!hangul_is_jaso(ch) && ch > 0) {
+    if (!hangul_is_jamo(ch) && ch > 0) {
        hangul_ic_save_commit_string(hic);
        hangul_ic_append_commit_string(hic, ch);
        return true;
@@ -802,6 +965,209 @@ hangul_ic_process_jaso(HangulInputContext *hic, ucschar ch)
     return true;
 }
 
+static bool
+hangul_ic_process_romaja(HangulInputContext *hic, int ascii, ucschar ch)
+{
+    ucschar jong;
+    ucschar combined;
+
+    if (!hangul_is_jamo(ch) && ch > 0) {
+       hangul_ic_save_commit_string(hic);
+       hangul_ic_append_commit_string(hic, ch);
+       return true;
+    }
+
+    if (isupper(ascii)) {
+       hangul_ic_save_commit_string(hic);
+    }
+
+    if (hic->buffer.jongseong) {
+       if (ascii == 'x' || ascii == 'X') {
+           ch = 0x110c;
+           hangul_ic_save_commit_string(hic);
+           if (!hangul_ic_push(hic, ch)) {
+               return false;
+           }
+       } else if (hangul_is_choseong(ch) || hangul_is_jongseong(ch)) {
+           if (hangul_is_jongseong(ch))
+               jong = ch;
+           else
+               jong = hangul_choseong_to_jongseong(ch);
+           combined = hangul_combination_combine(hic->combination,
+                                             hic->buffer.jongseong, jong);
+           if (hangul_is_jongseong(combined)) {
+               if (!hangul_ic_push(hic, combined)) {
+                   if (!hangul_ic_push(hic, ch)) {
+                       return false;
+                   }
+               }
+           } else {
+               hangul_ic_save_commit_string(hic);
+               if (!hangul_ic_push(hic, ch)) {
+                   return false;
+               }
+           }
+       } else if (hangul_is_jungseong(ch)) {
+           if (hic->buffer.jongseong == 0x11bc) {
+               hangul_ic_save_commit_string(hic);
+               hic->buffer.choseong = 0x110b;
+               hangul_ic_push(hic, ch);
+           } else {
+               ucschar pop, peek;
+               pop = hangul_ic_pop(hic);
+               peek = hangul_ic_peek(hic);
+
+               if (hangul_is_jungseong(peek)) {
+                   if (pop == 0x11aa) {
+                       hic->buffer.jongseong = 0x11a8;
+                   } else {
+                       hic->buffer.jongseong = 0;
+                   }
+                   hangul_ic_save_commit_string(hic);
+                   hangul_ic_push(hic, hangul_jongseong_to_choseong(pop));
+                   if (!hangul_ic_push(hic, ch)) {
+                       return false;
+                   }
+               } else {
+                   ucschar choseong = 0, jongseong = 0; 
+                   hangul_jongseong_dicompose(hic->buffer.jongseong,
+                                              &jongseong, &choseong);
+                   hic->buffer.jongseong = jongseong;
+                   hangul_ic_save_commit_string(hic);
+                   hangul_ic_push(hic, choseong);
+                   if (!hangul_ic_push(hic, ch)) {
+                       return false;
+                   }
+               }
+           }
+       } else {
+           goto flush;
+       }
+    } else if (hic->buffer.jungseong) {
+       if (hangul_is_choseong(ch)) {
+           if (hic->buffer.choseong) {
+               jong = hangul_choseong_to_jongseong(ch);
+               if (hangul_is_jongseong(jong)) {
+                   if (!hangul_ic_push(hic, jong)) {
+                       if (!hangul_ic_push(hic, ch)) {
+                           return false;
+                       }
+                   }
+               } else {
+                   hangul_ic_save_commit_string(hic);
+                   if (!hangul_ic_push(hic, ch)) {
+                       return false;
+                   }
+               }
+           } else {
+               if (!hangul_ic_push(hic, ch)) {
+                   if (!hangul_ic_push(hic, ch)) {
+                       return false;
+                   }
+               }
+           }
+       } else if (hangul_is_jungseong(ch)) {
+           combined = hangul_combination_combine(hic->combination,
+                                                 hic->buffer.jungseong, ch);
+           if (hangul_is_jungseong(combined)) {
+               if (!hangul_ic_push(hic, combined)) {
+                   return false;
+               }
+           } else {
+               hangul_ic_save_commit_string(hic);
+               hic->buffer.choseong = 0x110b;
+               if (!hangul_ic_push(hic, ch)) {
+                   return false;
+               }
+           }
+       } else if (hangul_is_jongseong(ch)) {
+           if (!hangul_ic_push(hic, ch)) {
+               if (!hangul_ic_push(hic, ch)) {
+                   return false;
+               }
+           }
+       } else {
+           goto flush;
+       }
+    } else if (hic->buffer.choseong) {
+       if (hangul_is_choseong(ch)) {
+           combined = hangul_combination_combine(hic->combination,
+                                                 hic->buffer.choseong, ch);
+           if (combined == 0) {
+               hic->buffer.jungseong = 0x1173;
+               hangul_ic_flush_internal(hic);
+               if (!hangul_ic_push(hic, ch)) {
+                   return false;
+               }
+           } else {
+               if (!hangul_ic_push(hic, combined)) {
+                   if (!hangul_ic_push(hic, ch)) {
+                       return false;
+                   }
+               }
+           }
+       } else if (hangul_is_jongseong(ch)) {
+           hic->buffer.jungseong = 0x1173;
+           hangul_ic_save_commit_string(hic);
+           if (ascii == 'x' || ascii == 'X')
+               ch = 0x110c;
+           if (!hangul_ic_push(hic, ch)) {
+               return false;
+           }
+       } else {
+           if (!hangul_ic_push(hic, ch)) {
+               if (!hangul_ic_push(hic, ch)) {
+                   return false;
+               }
+           }
+       }
+    } else {
+       if (ascii == 'x' || ascii == 'X') {
+           ch = 0x110c;
+       }
+
+       if (!hangul_ic_push(hic, ch)) {
+           return false;
+       } else {
+           if (hic->buffer.choseong == 0 && hic->buffer.jungseong != 0)
+               hic->buffer.choseong = 0x110b;
+       }
+    }
+
+    hangul_ic_save_preedit_string(hic);
+    return true;
+
+flush:
+    hangul_ic_flush_internal(hic);
+    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)
 {
@@ -819,10 +1185,24 @@ hangul_ic_process(HangulInputContext *hic, int ascii)
 
     if (hangul_keyboard_get_type(hic->keyboard) == HANGUL_KEYBOARD_TYPE_JAMO)
        return hangul_ic_process_jamo(hic, c);
-    else
+    else if (hangul_keyboard_get_type(hic->keyboard) == HANGUL_KEYBOARD_TYPE_JASO)
        return hangul_ic_process_jaso(hic, c);
+    else
+       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)
 {
@@ -832,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)
 {
@@ -841,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)
 {
@@ -865,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)
 {
@@ -875,14 +1298,33 @@ hangul_ic_flush(HangulInputContext *hic)
     hic->preedit_string[0] = 0;
     hic->commit_string[0] = 0;
     hic->flushed_string[0] = 0;
-    hangul_buffer_get_string(&hic->buffer, hic->flushed_string,
-                            N_ELEMENTS(hic->flushed_string));
+
+    if (hic->output_mode == HANGUL_OUTPUT_JAMO) {
+       hangul_buffer_get_jamo_string(&hic->buffer, hic->flushed_string,
+                                N_ELEMENTS(hic->flushed_string));
+    } else {
+       hangul_buffer_get_string(&hic->buffer, hic->flushed_string,
+                                N_ELEMENTS(hic->flushed_string));
+    }
 
     hangul_buffer_clear(&hic->buffer);
 
     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)
 {
@@ -891,6 +1333,9 @@ hangul_ic_backspace(HangulInputContext *hic)
     if (hic == NULL)
        return false;
 
+    hic->preedit_string[0] = 0;
+    hic->commit_string[0] = 0;
+
     ret = hangul_buffer_backspace(&hic->buffer);
     if (ret)
        hangul_ic_save_preedit_string(hic);
@@ -1003,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)
 {
@@ -1033,7 +1514,8 @@ hangul_ic_set_output_mode(HangulInputContext *hic, int mode)
     if (hic == NULL)
        return;
 
-    hic->output_mode = mode;
+    if (!hic->use_jamo_mode_only)
+       hic->output_mode = mode;
 }
 
 void
@@ -1088,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)
 {
@@ -1100,21 +1603,38 @@ hangul_ic_select_keyboard(HangulInputContext *hic, const char* id)
     if (strcmp(id, "32") == 0) {
        hic->keyboard = &hangul_keyboard_32;
        hic->combination = &hangul_combination_default;
+       hic->output_mode = HANGUL_OUTPUT_SYLLABLE;
+       hic->use_jamo_mode_only = FALSE;
     } else if (strcmp(id, "39") == 0) {
        hic->keyboard = &hangul_keyboard_390;
        hic->combination = &hangul_combination_default;
+       hic->output_mode = HANGUL_OUTPUT_SYLLABLE;
+       hic->use_jamo_mode_only = FALSE;
     } else if (strcmp(id, "3f") == 0) {
        hic->keyboard = &hangul_keyboard_3final;
        hic->combination = &hangul_combination_default;
+       hic->output_mode = HANGUL_OUTPUT_SYLLABLE;
+       hic->use_jamo_mode_only = FALSE;
     } else if (strcmp(id, "3s") == 0) {
        hic->keyboard = &hangul_keyboard_3sun;
        hic->combination = &hangul_combination_default;
+       hic->output_mode = HANGUL_OUTPUT_SYLLABLE;
+       hic->use_jamo_mode_only = FALSE;
     } else if (strcmp(id, "3y") == 0) {
        hic->keyboard = &hangul_keyboard_3yet;
        hic->combination = &hangul_combination_full;
+       hic->output_mode = HANGUL_OUTPUT_JAMO;
+       hic->use_jamo_mode_only = TRUE;
+    } else if (strcmp(id, "ro") == 0) {
+       hic->keyboard = &hangul_keyboard_romaja;
+       hic->combination = &hangul_combination_romaja;
+       hic->output_mode = HANGUL_OUTPUT_SYLLABLE;
+       hic->use_jamo_mode_only = FALSE;
     } else {
        hic->keyboard = &hangul_keyboard_2;
        hic->combination = &hangul_combination_default;
+       hic->output_mode = HANGUL_OUTPUT_SYLLABLE;
+       hic->use_jamo_mode_only = FALSE;
     }
 }
 
@@ -1128,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)
 {
@@ -1137,11 +1669,6 @@ hangul_ic_new(const char* keyboard)
     if (hic == NULL)
        return NULL;
 
-    hangul_ic_set_output_mode(hic, HANGUL_OUTPUT_SYLLABLE);
-    hangul_ic_select_keyboard(hic, keyboard);
-
-    hangul_buffer_clear(&hic->buffer);
-
     hic->preedit_string[0] = 0;
     hic->commit_string[0] = 0;
     hic->flushed_string[0] = 0;
@@ -1152,9 +1679,27 @@ hangul_ic_new(const char* keyboard)
     hic->on_transition      = NULL;
     hic->on_transition_data = NULL;
 
+    hic->use_jamo_mode_only = FALSE;
+
+    hangul_ic_set_output_mode(hic, HANGUL_OUTPUT_SYLLABLE);
+    hangul_ic_select_keyboard(hic, keyboard);
+
+    hangul_buffer_clear(&hic->buffer);
+
     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)
 {
old mode 100755 (executable)
new mode 100644 (file)
index aa609ea..e3cccd4
@@ -784,6 +784,137 @@ static const ucschar hangul_keyboard_table_3yet[] = {
     0x0000      /* 0x7F delete                                       */
 };
 
+static const ucschar hangul_keyboard_table_romaja[] = {
+    0x0000,     /* 0x00 null                                         */
+    0x0000,     /* 0x01 start of heading                             */
+    0x0000,     /* 0x02 start of text                                */
+    0x0000,     /* 0x03 end of text                                  */
+    0x0000,     /* 0x04 end of transmission                          */
+    0x0000,     /* 0x05 enquiry                                      */
+    0x0000,     /* 0x06 acknowledge                                  */
+    0x0000,     /* 0x07 bell                                         */
+    0x0000,     /* 0x08 backspace                                    */
+    0x0000,     /* 0x09 character tabulation                         */
+    0x0000,     /* 0x0A line feed (lf)                               */
+    0x0000,     /* 0x0B line tabulation                              */
+    0x0000,     /* 0x0C form feed (ff)                               */
+    0x0000,     /* 0x0D carriage return (cr)                         */
+    0x0000,     /* 0x0E shift out                                    */
+    0x0000,     /* 0x0F shift in                                     */
+    0x0000,     /* 0x10 data link escape                             */
+    0x0000,     /* 0x11 device control one                           */
+    0x0000,     /* 0x12 device control two                           */
+    0x0000,     /* 0x13 device control three                         */
+    0x0000,     /* 0x14 device control four                          */
+    0x0000,     /* 0x15 negative acknowledge                         */
+    0x0000,     /* 0x16 synchronous idle                             */
+    0x0000,     /* 0x17 end of transmission block                    */
+    0x0000,     /* 0x18 cancel                                       */
+    0x0000,     /* 0x19 end of medium                                */
+    0x0000,     /* 0x1A substitute                                   */
+    0x0000,     /* 0x1B escape                                       */
+    0x0000,     /* 0x1C information separator four                   */
+    0x0000,     /* 0x1D information separator three                  */
+    0x0000,     /* 0x1E information separator two                    */
+    0x0000,     /* 0x1F information separator one                    */
+    0x0000,     /* 0x20 space                                        */
+    0x0021,     /* 0x21 exclam:       exclamation mark               */
+    0x0022,     /* 0x22 quotedbl:     quotation mark                 */
+    0x0023,     /* 0x23 numbersign:   number sign                    */
+    0x0024,     /* 0x24 dollar:       dollar sign                    */
+    0x0025,     /* 0x25 percent:      percent sign                   */
+    0x0026,     /* 0x26 ampersand:    ampersand                      */
+    0x0027,     /* 0x27 apostrophe:   apostrophe                     */
+    0x0028,     /* 0x28 parenleft:    left parenthesis               */
+    0x0029,     /* 0x29 parenright:   right parenthesis              */
+    0x002a,     /* 0x2A asterisk:     asterisk                       */
+    0x002b,     /* 0x2B plus:         plus sign                      */
+    0x002c,     /* 0x2C comma:        comma                          */
+    0x002d,     /* 0x2D minus:        minus sign                     */
+    0x002e,     /* 0x2E period:       period                         */
+    0x002f,     /* 0x2F slash:        slash                          */
+    0x0030,     /* 0x30 0:            0                              */
+    0x0031,     /* 0x31 1:            1                              */
+    0x0032,     /* 0x32 2:            2                              */
+    0x0033,     /* 0x33 3:            3                              */
+    0x0034,     /* 0x34 4:            4                              */
+    0x0035,     /* 0x35 5:            5                              */
+    0x0036,     /* 0x36 6:            6                              */
+    0x0037,     /* 0x37 7:            7                              */
+    0x0038,     /* 0x38 8:            8                              */
+    0x0039,     /* 0x39 9:            9                              */
+    0x003a,     /* 0x3A colon:        colon                          */
+    0x003b,     /* 0x3B semicolon:    semicolon                      */
+    0x003c,     /* 0x3C less:         less-than sign                 */
+    0x003d,     /* 0x3D equal:        equals sign                    */
+    0x003e,     /* 0x3E greater:      greater-than sign              */
+    0x003f,     /* 0x3F question:     question mark                  */
+    0x0040,     /* 0x40 at:           commercial at                  */
+    0x1161,     /* 0x41 A:            jungseong a                    */
+    0x1107,     /* 0x42 B:            choseong  pieup                */
+    0x110e,     /* 0x43 C:            choseong  chieuch              */
+    0x1103,     /* 0x44 D:            choseong  tikeut               */
+    0x1166,     /* 0x45 E:            jungseong e                    */
+    0x1111,     /* 0x46 F:            choseong  phieuph              */
+    0x1100,     /* 0x47 G:            choseong  kiyeok               */
+    0x1112,     /* 0x48 H:            choseong  heiuh                */
+    0x1175,     /* 0x49 I:            jungseong i                    */
+    0x110c,     /* 0x4A J:            choseong  cieuc                */
+    0x110f,     /* 0x4B K:            choseong  khieukh              */
+    0x1105,     /* 0x4C L:            choseong  rieul                */
+    0x1106,     /* 0x4D M:            choseong  mieum                */
+    0x1102,     /* 0x4E N:            choseong  nieun                */
+    0x1169,     /* 0x4F O:            jungseong o                    */
+    0x1111,     /* 0x50 P:            choseong  phieuph              */
+    0x110f,     /* 0x51 Q:            choseong  khieukh              */
+    0x1105,     /* 0x52 R:            choseong  rieul                */
+    0x1109,     /* 0x53 S:            choseong  sios                 */
+    0x1110,     /* 0x54 T:            choseong  thieuth              */
+    0x116e,     /* 0x55 U:            jungseong u                    */
+    0x1107,     /* 0x56 V:            choseong  pieup                */
+    0x116e,     /* 0x57 W:            jungseong u                    */
+    0x110c,     /* 0x58 X:            choseong  cieuc                */
+    0x1175,     /* 0x59 Y:            jungseong i                    */
+    0x110c,     /* 0x5A Z:            choseong  cieuc                */
+    0x005b,     /* 0x5B bracketleft:  left bracket                   */
+    0x005c,     /* 0x5C backslash:    backslash                      */
+    0x005d,     /* 0x5D bracketright: right bracket                  */
+    0x005e,     /* 0x5E asciicircum:  circumflex accent              */
+    0x005f,     /* 0x5F underscore:   underscore                     */
+    0x0060,     /* 0x60 quoteleft:    grave accent                   */
+    0x1161,     /* 0x61 a:            jungseong a                    */
+    0x1107,     /* 0x62 b:            choseong  pieup                */
+    0x110e,     /* 0x63 c:            choseong  chieuch              */
+    0x1103,     /* 0x64 d:            choseong  tikeut               */
+    0x1166,     /* 0x65 e:            jungseong e                    */
+    0x1111,     /* 0x66 f:            choseong  phieuph              */
+    0x1100,     /* 0x67 g:            choseong  kiyeok               */
+    0x1112,     /* 0x68 h:            choseong  hieuh                */
+    0x1175,     /* 0x69 i:            jungseong i                    */
+    0x110c,     /* 0x6A j:            choseong  cieuc                */
+    0x110f,     /* 0x6B k:            choseong  khieukh              */
+    0x1105,     /* 0x6C l:            choseong  rieul                */
+    0x1106,     /* 0x6D m:            choseong  mieum                */
+    0x1102,     /* 0x6E n:            choseong  nieun                */
+    0x1169,     /* 0x6F o:            jungseong o                    */
+    0x1111,     /* 0x70 p:            choseong  pieup                */
+    0x110f,     /* 0x71 q:            choseong  khieukh              */
+    0x1105,     /* 0x72 r:            choseong  rieul                */
+    0x1109,     /* 0x73 s:            choseong  sios                 */
+    0x1110,     /* 0x74 t:            choseong  thieuth              */
+    0x116e,     /* 0x75 u:            jungseong u                    */
+    0x1107,     /* 0x76 v:            choseong  phieuph              */
+    0x116e,     /* 0x77 w:            jungseong u                    */
+    0x11aa,     /* 0x78 x:            jongseong kiyeoksios           */
+    0x1175,     /* 0x79 y:            jungseong i                    */
+    0x110c,     /* 0x7A z:            choseong  cieuc                */
+    0x007b,     /* 0x7B braceleft:    left brace                     */
+    0x007c,     /* 0x7C bar:          vertical bar                   */
+    0x007d,     /* 0x7D braceright:   right brace                    */
+    0x007e,     /* 0x7E asciitilde:   tilde                          */
+    0x0000      /* 0x7F delete                                       */
+};
+
 static const HangulCombinationItem hangul_combination_table_default[] = {
   { 0x11001100, 0x1101 }, /* choseong  kiyeok + kiyeok  = ssangkiyeok   */
   { 0x11031103, 0x1104 }, /* choseong  tikeut + tikeut  = ssangtikeut   */
@@ -812,6 +943,54 @@ static const HangulCombinationItem hangul_combination_table_default[] = {
   { 0x11ba11ba, 0x11bb }, /* jongseong sios   + sios    = ssangsios     */
 };
 
+static const HangulCombinationItem hangul_combination_table_romaja[] = {
+  { 0x11001100, 0x1101 }, /* choseong  kiyeok + kiyeok  = ssangkiyeok   */
+  { 0x11031103, 0x1104 }, /* choseong  tikeut + tikeut  = ssangtikeut   */
+  { 0x11071107, 0x1108 }, /* choseong  pieup  + pieup   = ssangpieup    */
+  { 0x11091109, 0x110a }, /* choseong  sios   + sios    = ssangsios     */
+  { 0x110c110c, 0x110d }, /* choseong  cieuc  + cieuc   = ssangcieuc    */
+  { 0x110e1112, 0x110e }, /* choseong  chieuch+ hieuh   = chieuch       */
+  { 0x11611166, 0x1162 }, /* jungseong a      + e       = ae            */
+  { 0x11611175, 0x1162 }, /* jungseong a      + i       = ae            */
+  { 0x11631166, 0x1164 }, /* jungseong ya     + e       = yae           */
+  { 0x11631175, 0x1164 }, /* jungseong ya     + i       = yae           */
+  { 0x11661169, 0x1165 }, /* jungseong e      + o       = eo            */
+  { 0x1166116e, 0x1173 }, /* jungseong e      + u       = eu            */
+  { 0x11681169, 0x1167 }, /* jungseong ye     + o       = yeo           */
+  { 0x11691161, 0x116a }, /* jungseong o      + a       = wa            */
+  { 0x11691162, 0x116b }, /* jungseong o      + ae      = wae           */
+  { 0x11691175, 0x116c }, /* jungseong o      + i       = oe            */
+  { 0x116a1166, 0x116b }, /* jungseong wa     + e       = wae           */
+  { 0x116a1175, 0x116b }, /* jungseong wa     + i       = wae           */
+  { 0x116e1161, 0x116a }, /* jungseong u      + a       = wa            */
+  { 0x116e1165, 0x116f }, /* jungseong u      + eo      = weo           */
+  { 0x116e1166, 0x1170 }, /* jungseong u      + e       = we            */
+  { 0x116e1169, 0x116f }, /* jungseong u      + o       = weo           */
+  { 0x116e1175, 0x1171 }, /* jungseong u      + i       = wi            */
+  { 0x11701169, 0x116f }, /* jungseong we     + o       = weo           */
+  { 0x11731175, 0x1174 }, /* jungseong eu     + i       = yi            */
+  { 0x11751161, 0x1163 }, /* jungseong i      + a       = ya            */
+  { 0x11751162, 0x1164 }, /* jungseong i      + ae      = yae           */
+  { 0x11751165, 0x1167 }, /* jungseong i      + eo      = yeo           */
+  { 0x11751166, 0x1168 }, /* jungseong i      + e       = ye            */
+  { 0x11751169, 0x116d }, /* jungseong i      + o       = yo            */
+  { 0x1175116e, 0x1172 }, /* jungseong i      + u       = yu            */
+  { 0x11a811a8, 0x11a9 }, /* jongseong kiyeok + kiyeok  = ssangekiyeok  */
+  { 0x11a811ba, 0x11aa }, /* jongseong kiyeok + sios    = kiyeok-sois   */
+  { 0x11ab11a8, 0x11bc }, /* jongseong nieun  + kiyeok  = ieung         */
+  { 0x11ab11bd, 0x11ac }, /* jongseong nieun  + cieuc   = nieun-cieuc   */
+  { 0x11ab11c2, 0x11ad }, /* jongseong nieun  + hieuh   = nieun-hieuh   */
+  { 0x11af11a8, 0x11b0 }, /* jongseong rieul  + kiyeok  = rieul-kiyeok  */
+  { 0x11af11b7, 0x11b1 }, /* jongseong rieul  + mieum   = rieul-mieum   */
+  { 0x11af11b8, 0x11b2 }, /* jongseong rieul  + pieup   = rieul-pieup   */
+  { 0x11af11ba, 0x11b3 }, /* jongseong rieul  + sios    = rieul-sios    */
+  { 0x11af11c0, 0x11b4 }, /* jongseong rieul  + thieuth = rieul-thieuth */
+  { 0x11af11c1, 0x11b5 }, /* jongseong rieul  + phieuph = rieul-phieuph */
+  { 0x11af11c2, 0x11b6 }, /* jongseong rieul  + hieuh   = rieul-hieuh   */
+  { 0x11b811ba, 0x11b9 }, /* jongseong pieup  + sios    = pieup-sios    */
+  { 0x11ba11ba, 0x11bb }, /* jongseong sios   + sios    = ssangsios     */
+};
+
 static const HangulCombinationItem hangul_combination_table_full[] = {
   { 0x11001100, 0x1101 }, /* choseong ssangkiyeok           = kiyeok + kiyeok */
   { 0x11021100, 0x1113 }, /* choseong nieun-kiyeok          = nieun + kiyeok */
old mode 100755 (executable)
new mode 100644 (file)
index eade6bc..6d2de65
@@ -1,5 +1,5 @@
 /* libhangul
- * Copyright (C) 2005 Choe Hwanjin
+ * Copyright (C) 2005-2009 Choe Hwanjin
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 #include <config.h>
 #endif
 
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#ifdef HAVE_MMAP
+#include <sys/mman.h>
+#endif
+
 #include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include "hangul.h"
 #include "hangulinternals.h"
 
+#ifndef TRUE
+#define TRUE  1
+#endif
+
+#ifndef FALSE
+#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;
 typedef struct _HanjaPairArray HanjaPairArray;
 
 struct _Hanja {
-    char *key;
-    char *value;
-    char *comment;
+    uint32_t key_offset;
+    uint32_t value_offset;
+    uint32_t comment_offset;
 };
 
 struct _HanjaList {
-    char *key;
-    unsigned int nitems;
-    Hanja **items; 
+    char*         key;
+    size_t        len;
+    size_t        alloc;
+    const Hanja** items; 
 };
 
-struct _HanjaTable {
-    unsigned int nmember;
-    HanjaList **base;
+struct _HanjaIndex {
+    unsigned offset;
+    char     key[8];
 };
 
-struct slist {
-    void *data;
-    struct slist *next;
+struct _HanjaTable {
+    HanjaIndex*    keytable;
+    unsigned       nkeys;
+    unsigned       key_size;
+    FILE*          file;
 };
 
 struct _HanjaPair {
@@ -65,13 +188,6 @@ struct _HanjaPairArray {
 
 #include "hanjacompatible.h"
 
-/* utility functions */
-static inline void h_free(void *ptr)
-{
-    if (ptr)
-       free(ptr);
-}
-
 static const char utf8_skip_table[256] = {
     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
@@ -83,130 +199,151 @@ static const char utf8_skip_table[256] = {
     3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1
 };
 
-static inline int h_char_len(const char *p)
+static inline int utf8_char_len(const char *p)
 {
     return utf8_skip_table[*(const unsigned char*)p];
 }
 
-static struct slist *
-slist_append(struct slist *head, void *data)
+static inline const char* utf8_next(const char *str)
 {
-    struct slist *tail;
-
-    if (data == NULL)
-       return head;
-
-    if (head == NULL) {
-       head = malloc(sizeof(struct slist));
-       if (head != NULL) {
-           head->data = data;
-           head->next = NULL;
-       }
+    int n = utf8_char_len(str);
 
-       return head;
+    while (n > 0) {
+       str++;
+       if (*str == '\0')
+           return str;
+       n--;
     }
 
-    for (tail = head; tail->next != NULL; tail = tail->next)
-       continue;
-
-    tail->next = malloc(sizeof(struct slist));
-    if (tail->next != NULL) {
-       tail->next->data = data;
-       tail->next->next = NULL;
-    }
-
-    return head;
+    return str;
 }
 
-static void
-slist_delete(struct slist *head)
+static inline char* utf8_prev(const char *str, const char *p)
 {
-    struct slist *item;
-    while (head != NULL) {
-       item = head;
-       head = head->next;
-       free(item);
-    }
-}
-
-static unsigned int
-slist_length(struct slist *head)
-{
-    unsigned int n = 0;
-    while (head != NULL) {
-       head = head->next;
-       n++;
+    for (--p; p >= str; --p) {
+       if ((*p & 0xc0) != 0x80)
+           break;
     }
-    return n;
+    return (char*)p;
 }
 
 /* hanja searching functions */
 static Hanja *
 hanja_new(const char *key, const char *value, const char *comment)
 {
-    Hanja *item;
-
-    item = malloc(sizeof(Hanja));
-    if (item != NULL) {
-       item->key = strdup(key);
-       item->value = strdup(value);
-       if (comment != NULL)
-           item->comment = strdup(comment);
-       else
-           item->comment = strdup("");
-    }
+    Hanja* hanja;
+    size_t size;
+    size_t keylen;
+    size_t valuelen;
+    size_t commentlen;
+    char*  p;
+
+    keylen = strlen(key) + 1;
+    valuelen = strlen(value) + 1;
+    if (comment != NULL)
+       commentlen = strlen(comment) + 1;
+    else
+       commentlen = 1;
+
+    size = sizeof(*hanja) + keylen + valuelen + commentlen;
+    hanja = malloc(size);
+    if (hanja == NULL)
+       return NULL;
 
-    return item;
+    p = (char*)hanja + sizeof(*hanja);
+    strcpy(p, key);
+    p += keylen;
+    strcpy(p, value);
+    p += valuelen;
+    if (comment != NULL)
+       strcpy(p, comment);
+    else
+       *p = '\0';
+    p += valuelen;
+
+    hanja->key_offset     = sizeof(*hanja);
+    hanja->value_offset   = sizeof(*hanja) + keylen;
+    hanja->comment_offset = sizeof(*hanja) + keylen + valuelen;
+
+    return hanja;
 }
 
+static void
+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)
 {
-    if (hanja != NULL)
-       return hanja->key;
+    if (hanja != NULL) {
+       const char* p  = (const char*)hanja;
+       return p + hanja->key_offset;
+    }
     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)
 {
-    if (hanja != NULL)
-       return hanja->value;
+    if (hanja != NULL) {
+       const char* p  = (const char*)hanja;
+       return p + hanja->value_offset;
+    }
     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)
 {
-    if (hanja != NULL)
-       return hanja->comment;
+    if (hanja != NULL) {
+       const char* p  = (const char*)hanja;
+       return p + hanja->comment_offset;
+    }
     return NULL;
 }
 
 static HanjaList *
-hanja_list_new_from_slist(const char *key, struct slist *items)
+hanja_list_new(const char *key)
 {
-    unsigned int nitems;
     HanjaList *list;
 
-    nitems = slist_length(items);
-    if (nitems > ULONG_MAX / sizeof(Hanja*))
-       return NULL;
-
-    list = malloc(sizeof(HanjaList));
+    list = malloc(sizeof(*list));
     if (list != NULL) {
-       int i;
        list->key = strdup(key);
-       list->nitems = nitems;
-       list->items = malloc(sizeof(Hanja*) * list->nitems);
-       if (list->items != NULL) {
-           for (i = 0; i < list->nitems; i++) {
-               list->items[i] = items->data;
-               items = items->next;
-           }
-       } else {
-           if (list->key != NULL)
-               free(list->key);
+       list->len = 0;
+       list->alloc = 1;
+       list->items = malloc(list->alloc * sizeof(list->items[0]));
+       if (list->items == NULL) {
            free(list);
            list = NULL;
        }
@@ -215,60 +352,141 @@ hanja_list_new_from_slist(const char *key, struct slist *items)
     return list;
 }
 
-static HanjaTable *
-hanja_table_new_from_slist(struct slist *lists)
+static void
+hanja_list_reserve(HanjaList* list, size_t n)
 {
-    unsigned int nitems;
-    HanjaTable *table;
+    size_t size = list->alloc;
 
-    nitems = slist_length(lists);
-    if (nitems > ULONG_MAX / sizeof(HanjaList*))
-       return NULL;
+    if (n > SIZE_MAX / sizeof(list->items[0]) - list->len)
+       return;
 
-    table = malloc(sizeof(HanjaTable));
-    if (table) {
-       int i;
-       table->nmember = nitems;
-       table->base = malloc(sizeof(HanjaList*) * table->nmember);
-       if (table->base != NULL) {
-           for (i = 0; i < table->nmember; i++) {
-               table->base[i] = lists->data;
-               lists = lists->next;
-           }
+    while (size < list->len + n)
+       size *= 2;
+
+    if (size > SIZE_MAX / sizeof(list->items[0]))
+       return;
+
+    if (list->alloc < list->len + n) {
+       const Hanja** data;
+
+       data = realloc(list->items, size * sizeof(list->items[0]));
+       if (data != NULL) {
+           list->alloc = size;
+           list->items = data;
+       }
+    }
+}
+
+static void
+hanja_list_append_n(HanjaList* list, const Hanja* hanja, int n)
+{
+    hanja_list_reserve(list, n);
+
+    if (list->alloc >= list->len + n) {
+       unsigned int i;
+       for (i = 0; i < n ; i++)
+           list->items[list->len + i] = hanja + i;
+       list->len += n;
+    }
+}
+
+static void
+hanja_table_match(const HanjaTable* table,
+                 const char* key, HanjaList** list)
+{
+    int low, high, mid;
+    int res = -1;
+
+    low = 0;
+    high = table->nkeys - 1;
+
+    while (low < high) {
+       mid = (low + high) / 2;
+       res = strncmp(table->keytable[mid].key, key, table->key_size);
+       if (res < 0) {
+           low = mid + 1;
+       } else if (res > 0) {
+           high = mid - 1;
        } else {
-           free(table);
-           table = NULL;
+           break;
+       }
+    }
+
+    if (res != 0) {
+       mid = low;
+       res = strncmp(table->keytable[mid].key, key, table->key_size);
+    }
+
+    if (res == 0) {
+       unsigned offset;
+       char buf[512];
+
+       offset = table->keytable[mid].offset;
+       fseek(table->file, offset, SEEK_SET);
+
+       while (fgets(buf, sizeof(buf), table->file) != NULL) {
+           char* save = NULL;
+           char* p = strtok_r(buf, ":", &save);
+           res = strcmp(p, key);
+           if (res == 0) {
+               char* value   = strtok_r(NULL, ":", &save);
+               char* comment = strtok_r(NULL, "\r\n", &save);
+
+               Hanja* hanja = hanja_new(p, value, comment);
+
+               if (*list == NULL) {
+                   *list = hanja_list_new(key);
+               }
+
+               hanja_list_append_n(*list, hanja, 1);
+           } else if (res > 0) {
+               break;
+           }
        }
     }
-    return 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)
+hanja_table_load(const charfilename)
 {
-    char *save_ptr = NULL;
-    char *key;
-    char *value;
-    char *comment;
-    char listkey[64] = { 0, };
-    char buf[1024];
-
-    FILE *file;
-    HanjaTable *table;
-    HanjaList *list;
-    Hanja *item;
-    struct slist *items = NULL;
-    struct slist *lists = NULL;
+    unsigned nkeys;
+    char buf[512];
+    int key_size = 5;
+    char last_key[8] = { '\0', };
+    char* save_ptr = NULL;
+    char* key;
+    long offset;
+    unsigned i;
+    FILE* file;
+    HanjaIndex* keytable;
+    HanjaTable* table;
 
     if (filename == NULL)
        filename = LIBHANGUL_DEFAULT_HANJA_DIC;
 
     file = fopen(filename, "r");
     if (file == NULL) {
-       printf("cant open file: %s\n", filename);
        return NULL;
     }
-    
+
+    nkeys = 0;
     while (fgets(buf, sizeof(buf), file) != NULL) {
        /* skip comments and empty lines */
        if (buf[0] == '#' || buf[0] == '\r' || buf[0] == '\n' || buf[0] == '\0')
@@ -276,172 +494,198 @@ hanja_table_load(const char *filename)
 
        save_ptr = NULL;
        key = strtok_r(buf, ":", &save_ptr);
-       value = strtok_r(NULL, ":", &save_ptr);
-       comment = strtok_r(NULL, "\r\n", &save_ptr);
-
-       if (strlen(listkey) == 0 ||
-           strncmp(listkey, key, strlen(listkey)) != 0) {
-           if (items != NULL) {
-               list = hanja_list_new_from_slist(listkey, items);
-               slist_delete(items);
-               items = NULL;
 
-               lists = slist_append(lists, list);
-           }
+       if (key == NULL || strlen(key) == 0)
+           continue;
 
-           strncpy(listkey, key, sizeof(listkey));
+       if (strncmp(last_key, key, key_size) != 0) {
+           nkeys++;
+           strncpy(last_key, key, key_size);
        }
-       
-       item = hanja_new(key, value, comment);
-       items = slist_append(items, item);
     }
 
-    if (items != NULL) {
-       list = hanja_list_new_from_slist(listkey, items);
-       slist_delete(items);
-       items = NULL;
-
-       lists = slist_append(lists, list);
-    }
+    rewind(file);
+    keytable = malloc(nkeys * sizeof(keytable[0]));
+    memset(keytable, 0, nkeys * sizeof(keytable[0]));
 
-    table = hanja_table_new_from_slist(lists);
-    slist_delete(lists);
-    lists = NULL;
+    i = 0;
+    offset = ftell(file);
+    while (fgets(buf, sizeof(buf), file) != NULL) {
+       /* skip comments and empty lines */
+       if (buf[0] == '#' || buf[0] == '\r' || buf[0] == '\n' || buf[0] == '\0')
+           continue;
 
-    fclose(file);
+       save_ptr = NULL;
+       key = strtok_r(buf, ":", &save_ptr);
 
-    return table;
-}
+       if (key == NULL || strlen(key) == 0)
+           continue;
 
-static void
-delete_last_char(char *str)
-{
-    char *end = strchr(str, '\0');
-    for (--end; end >= str; --end) {
-       if ((*end & 0xc0) != 0x80) {
-           break;
+       if (strncmp(last_key, key, key_size) != 0) {
+           keytable[i].offset = offset;
+           strncpy(keytable[i].key, key, key_size);
+           strncpy(last_key, key, key_size);
+           i++;
        }
+       offset = ftell(file);
     }
 
-    while (*end != '\0') {
-       *end++ = '\0';
+    table = malloc(sizeof(*table));
+    if (table == NULL) {
+       free(keytable);
+       fclose(file);
+       return NULL;
     }
+
+    table->keytable = keytable;
+    table->nkeys = nkeys;
+    table->key_size = key_size;
+    table->file = file;
+
+    return table;
 }
 
-static int
-hanja_table_compare(const void *key, const void *item)
+/**
+ * @ingroup hanjadictionary
+ * @brief 한자 사전 object를 free하는 함수
+ * @param table free할 한자 사전 object
+ */
+void
+hanja_table_delete(HanjaTable *table)
 {
-    return strncmp((const char*)key, (*((HanjaList**)item))->key, strlen(key));
+    if (table != NULL) {
+       free(table->keytable);
+       fclose(table->file);
+       free(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_prefix(const HanjaTable* table, const char *key)
+hanja_table_match_exact(const HanjaTable* table, const char *key)
 {
-    char *p;
-    char newkey[64] = { '\0', };
-    HanjaList **list;
-    HanjaList *ret;
-    struct slist *items = NULL;
-
-    strncpy(newkey, key, sizeof(newkey));
-    p = newkey + h_char_len(newkey);
-    *p = '\0';
-
-    list = bsearch(newkey,
-                   table->base, table->nmember,
-                   sizeof(HanjaList*),
-                   hanja_table_compare);
-    if (list != NULL) {
-       int i;
-       strncpy(newkey, key, sizeof(newkey));
-       for (; strlen(newkey) > 0; delete_last_char(newkey)) {
-           for (i = 0; i < (*list)->nitems; i++) {
-               if (strcmp(newkey, (*list)->items[i]->key) == 0) {
-                   items = slist_append(items, (*list)->items[i]);
-               }
-           }
-       }
+    HanjaList* ret = NULL;
 
-       if (items) {
-           ret = hanja_list_new_from_slist(key, items);
-           slist_delete(items);
-           return ret;
-       }
-    }
-    
-    return NULL;
+    if (key == NULL || key[0] == '\0' || table == NULL)
+       return NULL;
+
+    hanja_table_match(table, key, &ret);
+
+    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)
+hanja_table_match_prefix(const HanjaTable* table, const char *key)
 {
-    const char *p;
-    char newkey[64] = { '\0', };
-    HanjaList **list = NULL;
-    HanjaList *ret;
-    struct slist *items = NULL;
+    char* p;
+    char* newkey;
+    HanjaList* ret = NULL;
 
-    p = key;
-    strncpy(newkey, p, sizeof(newkey));
-    newkey[h_char_len(newkey)] = '\0';
-    while (strlen(newkey) > 0) {
-       list = bsearch(newkey,
-                      table->base, table->nmember,
-                      sizeof(HanjaList*),
-                      hanja_table_compare);
-
-       if (list != NULL) {
-           int i;
-           for (i = 0; i < (*list)->nitems; i++) {
-               if (strcmp(p, (*list)->items[i]->key) == 0) {
-                   items = slist_append(items, (*list)->items[i]);
-               }
-           }
-       }
+    if (key == NULL || key[0] == '\0' || table == NULL)
+       return NULL;
 
-       p += h_char_len(p);
-       strncpy(newkey, p, sizeof(newkey));
-       newkey[h_char_len(newkey)] = '\0';
-    }
+    newkey = strdup(key);
+    if (newkey == NULL)
+       return NULL;
 
-    if (items != NULL) {
-       ret = hanja_list_new_from_slist(key, items);
-       slist_delete(items);
-       return ret;
+    p = strchr(newkey, '\0');
+    while (newkey[0] != '\0') {
+       hanja_table_match(table, newkey, &ret);
+       p = utf8_prev(newkey, p);
+       p[0] = '\0';
     }
+    free(newkey);
 
-    return NULL;
+    return ret;
 }
 
-void
-hanja_table_delete(HanjaTable *table)
+/**
+ * @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)
 {
-    if (table) {
-       int i, j;
-       for (j = 0; j < table->nmember; j++) {
-           for (i = 0; i < table->base[j]->nitems; i++) {
-               h_free((char*)table->base[j]->items[i]->key);
-               h_free((char*)table->base[j]->items[i]->value);
-               h_free((char*)table->base[j]->items[i]->comment);
-               h_free(table->base[j]->items[i]);
-           }
-           h_free((char*)table->base[j]->key);
-           h_free(table->base[j]->items);
-           h_free(table->base[j]);
-       }
-       h_free(table->base);
-       h_free(table);
+    const char* p;
+    HanjaList* ret = NULL;
+
+    if (key == NULL || key[0] == '\0' || table == NULL)
+       return NULL;
+
+    p = key;
+    while (p[0] != '\0') {
+       hanja_table_match(table, p, &ret);
+       p = utf8_next(p);
     }
+
+    return ret;
 }
 
+/**
+ * @ingroup hanjadictionary
+ * @brief @ref HanjaList가 가지고 있는 아이템의 갯수를 구하는 함수
+ */
 int
 hanja_list_get_size(const HanjaList *list)
 {
     if (list != NULL)
-       return list->nitems;
+       return list->len;
     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)
 {
@@ -450,16 +694,66 @@ 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)
 {
     if (list != NULL) {
-       if (n < list->nitems)
+       if (n < list->len)
            return list->items[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)
+{
+    const Hanja* hanja = hanja_list_get_nth(list, 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)
 {
@@ -467,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)
 {
@@ -474,13 +775,25 @@ 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)
 {
     if (list) {
-       h_free(list->items);
-       h_free((char*)list->key);
-       h_free(list);
+       size_t i;
+       for (i = 0; i < list->len; i++) {
+           hanja_delete((Hanja*)list->items[i]);
+       }
+       free(list->items);
+       free(list->key);
+       free(list);
     }
 }
 
@@ -546,4 +859,3 @@ hanja_unified_form(ucschar* str, size_t n)
 
     return nconverted;
 }
-
index 25aebd5b973639221bacb99f6a8f8cff1accb955..e53aa228a346866d7feb0a24e28e41f15c99bde0 100755 (executable)
@@ -8,3 +8,9 @@ hangul_LDADD = ../hangul/libhangul.la
 hanja_CFLAGS =
 hanja_SOURCES = hanja.c
 hanja_LDADD = ../hangul/libhangul.la
+
+TESTS = test
+check_PROGRAMS = test
+test_SOURCES = test.c ../hangul/hangul.h
+test_CFLAGS = @CHECK_CFLAGS@
+test_LDADD = @CHECK_LIBS@ $(top_builddir)/hangul/libhangul.la
old mode 100755 (executable)
new mode 100644 (file)
index d9a0f30..4023759
 #define UCS4 "UCS-4LE"
 #endif
 
-bool filter(ucschar *str, ucschar cho, ucschar jung, ucschar jong, void *data)
-{
-    //printf("Filter: %x %x %x\n", cho, jung, jong);
-    //return jong == 0;
-    return true;
-}
-
 void ucs4_to_utf8(char *buf, const ucschar *ucs4, size_t bufsize)
 {
     size_t n;
@@ -75,7 +68,6 @@ main(int argc, char *argv[])
        printf("hic is null\n");
        return -1;
     }
-    hangul_ic_set_filter(hic, filter, NULL);
 
     for (ascii = getchar(); ascii != EOF; ascii = getchar()) {
        int ret = hangul_ic_process(hic, ascii);
old mode 100755 (executable)
new mode 100644 (file)
index 88ce15d..78f231f
@@ -12,8 +12,9 @@ main(int argc, char *argv[])
     if (argc > 1)
        hanja_table_file = argv[1];
 
-    HanjaTable *table = hanja_table_load(hanja_table_file);
-    
+    HanjaTable *table;
+    table = hanja_table_load(hanja_table_file);
     while (fgets(buf, sizeof(buf), stdin) != NULL) {
        char* p = strchr(buf, '\n');
        if (p != NULL)
@@ -24,8 +25,10 @@ main(int argc, char *argv[])
        int i, n;
        n = hanja_list_get_size(list);
        for (i = 0; i < n; i++) {
-           const char* value = hanja_list_get_nth_value(list, i);
-           printf("%s\n", value);
+           const char* key     = hanja_list_get_nth_key(list, i);
+           const char* value   = hanja_list_get_nth_value(list, i);
+           const char* comment = hanja_list_get_nth_comment(list, i);
+           printf("%s:%s:%s\n", key, value, comment);
        }
 
        hanja_list_delete(list);
diff --git a/test/test.c b/test/test.c
new file mode 100644 (file)
index 0000000..484a0c1
--- /dev/null
@@ -0,0 +1,261 @@
+#include <stdlib.h>
+#include <check.h>
+
+#include "../hangul/hangul.h"
+
+#define countof(x)  ((sizeof(x)) / (sizeof(x[0])))
+
+START_TEST(test_hangul_ic_process_romaja)
+{
+    HangulInputContext* ic;
+    const ucschar* preedit;
+    const ucschar* commit;
+
+    // romaja keyboard test
+    ic = hangul_ic_new("ro");
+
+    // basic test: han produces 한
+    hangul_ic_process(ic, 'h');
+    hangul_ic_process(ic, 'a');
+    hangul_ic_process(ic, 'n');
+
+    preedit = hangul_ic_get_preedit_string(ic);
+    commit = hangul_ic_get_commit_string(ic);
+    fail_unless(preedit[0] == 0xd55c); // 한
+    fail_unless(commit[0] == 0);
+
+    hangul_ic_reset(ic);
+
+    // insert ㅇ when a syllable is not started with consonant
+    hangul_ic_process(ic, 'a');
+
+    preedit = hangul_ic_get_preedit_string(ic);
+    commit = hangul_ic_get_commit_string(ic);
+    fail_unless(preedit[0] == 0xc544); // 아
+    fail_unless(commit[0] == 0);
+
+    // remove correctly when automatically ㅇ was inserted
+    hangul_ic_backspace(ic);
+
+    preedit = hangul_ic_get_preedit_string(ic);
+    commit = hangul_ic_get_commit_string(ic);
+    fail_unless(preedit[0] == 0);
+    fail_unless(commit[0] == 0);
+
+    // append ㅡ when a syllable is not ended with vowel
+    hangul_ic_process(ic, 't');
+    hangul_ic_process(ic, 't');
+
+    preedit = hangul_ic_get_preedit_string(ic);
+    commit = hangul_ic_get_commit_string(ic);
+    fail_unless(preedit[0] == 0x314c); // ㅌ
+    fail_unless(commit[0] == 0xd2b8);  // 트
+
+    // ng makes trailing ㅇ
+    hangul_ic_reset(ic);
+    hangul_ic_process(ic, 'g');
+    hangul_ic_process(ic, 'a');
+    hangul_ic_process(ic, 'n');
+    hangul_ic_process(ic, 'g');
+
+    preedit = hangul_ic_get_preedit_string(ic);
+    commit = hangul_ic_get_commit_string(ic);
+    fail_unless(preedit[0] == 0xac15); // 강
+    fail_unless(commit[0] == 0);
+
+    // gangi makes 강이
+    hangul_ic_process(ic, 'i');
+
+    preedit = hangul_ic_get_preedit_string(ic);
+    commit = hangul_ic_get_commit_string(ic);
+    fail_unless(preedit[0] == 0xc774); // 이
+    fail_unless(commit[0] == 0xac15);  // 강
+
+    // nanG makes 난ㄱ
+    // uppercase makes new syllable
+    hangul_ic_process(ic, 'n');
+    hangul_ic_process(ic, 'a');
+    hangul_ic_process(ic, 'n');
+    hangul_ic_process(ic, 'G');
+
+    preedit = hangul_ic_get_preedit_string(ic);
+    commit = hangul_ic_get_commit_string(ic);
+    fail_unless(preedit[0] == 0x3131); // ㄱ
+    fail_unless(commit[0] == 0xb09c);  // 난
+
+    // special operation for x
+    // x generate ㅈ for leading consonant
+    hangul_ic_reset(ic);
+    hangul_ic_process(ic, 'x');
+    hangul_ic_process(ic, 'x');
+
+    preedit = hangul_ic_get_preedit_string(ic);
+    commit = hangul_ic_get_commit_string(ic);
+    fail_unless(preedit[0] == 0x3148); // 지
+    fail_unless(commit[0] == 0xc988);
+
+    hangul_ic_reset(ic);
+    hangul_ic_process(ic, 'x');
+    hangul_ic_process(ic, 'y');
+
+    preedit = hangul_ic_get_preedit_string(ic);
+    commit = hangul_ic_get_commit_string(ic);
+    fail_unless(preedit[0] == 0xc9c0); // 지
+    fail_unless(commit[0] == 0x0);
+
+    // x generate ㄱㅅ for trailing consonant
+    // and ㅅ will be transferred to next syllable when next input
+    // character is vowel.
+    hangul_ic_reset(ic);
+    hangul_ic_process(ic, 's');
+    hangul_ic_process(ic, 'e');
+    hangul_ic_process(ic, 'x');
+    hangul_ic_process(ic, 'y');
+
+    preedit = hangul_ic_get_preedit_string(ic);
+    commit = hangul_ic_get_commit_string(ic);
+    fail_unless(preedit[0] == 0xc2dc); // 시
+    fail_unless(commit[0] == 0xc139);  // 섹
+    
+    hangul_ic_delete(ic);
+}
+END_TEST
+
+START_TEST(test_syllable_iterator)
+{
+    ucschar str[] = {
+       // L L V V T T
+       0x1107, 0x1107, 0x116e, 0x1166, 0x11af, 0x11a8,          // 0
+       // L V T
+       0x1108, 0x1170, 0x11b0,                                  // 6
+       // L L V V T T M
+       0x1107, 0x1107, 0x116e, 0x1166, 0x11af, 0x11a8, 0x302E,  // 9
+       // L V T M
+       0x1108, 0x1170, 0x11b0, 0x302F,                          // 16
+       // Lf V
+       0x115f, 0x1161,                                          // 20
+       // L Vf
+       0x110c, 0x1160,                                          // 22
+       // L LVT T
+       0x1107, 0xbc14, 0x11a8,                                  // 24
+       // L LV T
+       0x1100, 0xac00, 0x11a8,                                  // 27
+       // LVT
+       0xc00d,                                                  // 30 
+       // other
+       'a',                                                     // 31
+       0                                                        // 32
+    };
+
+    const ucschar* begin = str;
+    const ucschar* end = str + countof(str) - 1;
+    const ucschar* s = str;
+
+    s = hangul_syllable_iterator_next(s, end);
+    fail_unless(s - str == 6,
+               "error: next syllable: L L V V T T");
+
+    s = hangul_syllable_iterator_next(s, end);
+    fail_unless(s - str == 9,
+               "error: next syllable: L V T");
+
+    s = hangul_syllable_iterator_next(s, end);
+    fail_unless(s - str == 16,
+               "error: next syllable: L L V V T T M");
+
+    s = hangul_syllable_iterator_next(s, end);
+    fail_unless(s - str == 20,
+               "error: next syllable: L V T M");
+
+    s = hangul_syllable_iterator_next(s, end);
+    fail_unless(s - str == 22,
+               "error: next syllable: Lf V");
+
+    s = hangul_syllable_iterator_next(s, end);
+    fail_unless(s - str == 24,
+               "error: next syllable: L Vf");
+
+    s = hangul_syllable_iterator_next(s, end);
+    fail_unless(s - str == 27,
+               "error: next syllable: L LVT T");
+
+    s = hangul_syllable_iterator_next(s, end);
+    fail_unless(s - str == 30,
+               "error: next syllable: L LV T");
+
+    s = hangul_syllable_iterator_next(s, end);
+    fail_unless(s - str == 31,
+               "error: next syllable: LVT");
+
+    s = hangul_syllable_iterator_next(s, end);
+    fail_unless(s - str == 32,
+               "error: next syllable: other");
+
+    s = end;
+    s = hangul_syllable_iterator_prev(s, begin);
+    fail_unless(s - str == 31,
+               "error: prev syllable: other");
+
+    s = hangul_syllable_iterator_prev(s, begin);
+    fail_unless(s - str == 30,
+               "error: prev syllable: LVT");
+
+    s = hangul_syllable_iterator_prev(s, begin);
+    fail_unless(s - str == 27,
+               "error: prev syllable: L LV T");
+
+    s = hangul_syllable_iterator_prev(s, begin);
+    fail_unless(s - str == 24,
+               "error: prev syllable: L LVT T");
+
+    s = hangul_syllable_iterator_prev(s, begin);
+    fail_unless(s - str == 22,
+               "error: prev syllable: L Vf");
+
+    s = hangul_syllable_iterator_prev(s, begin);
+    fail_unless(s - str == 20,
+               "error: prev syllable: Lf V");
+
+    s = hangul_syllable_iterator_prev(s, begin);
+    fail_unless(s - str == 16,
+               "error: prev syllable: L V T M");
+
+    s = hangul_syllable_iterator_prev(s, begin);
+    fail_unless(s - str == 9,
+               "error: prev syllable: L L V V T T M");
+
+    s = hangul_syllable_iterator_prev(s, begin);
+    fail_unless(s - str == 6,
+               "error: prev syllable: L V T");
+
+    s = hangul_syllable_iterator_prev(s, begin);
+    fail_unless(s - str == 0,
+               "error: prev syllable: L L V V T T");
+}
+END_TEST
+
+Suite* libhangul_suite()
+{
+    Suite* s = suite_create("libhangul");
+
+    TCase* hangul = tcase_create("hangul");
+    tcase_add_test(hangul, test_hangul_ic_process_romaja);
+    tcase_add_test(hangul, test_syllable_iterator);
+    suite_add_tcase(s, hangul);
+
+    return s;
+}
+
+int main()
+{
+    int number_failed;
+    Suite* s = libhangul_suite();
+    SRunner* sr = srunner_create(s);
+
+    srunner_run_all(sr, CK_NORMAL);
+
+    number_failed = srunner_ntests_failed(sr);
+    srunner_free(sr);
+
+    return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}