+------------------------------------------------------------------------
+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:
-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 ; \
+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
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
+++ /dev/null
-EXTRA_DIST = \
- python/test_pyhangul.py \
- python/setup.py \
- python/pyhangul.c \
- python/Makefile \
- ruby/hangul.c \
- ruby/test-hangul.rb \
- ruby/extconf.rb
+++ /dev/null
-# 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:
+++ /dev/null
-
-all:
- python setup.py build
-
-clean:
- rm -rf build
-
-install:
- python setup.py install
+++ /dev/null
-#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,
-};
+++ /dev/null
-#!/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
- )
-
+++ /dev/null
-# 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()
+++ /dev/null
-require 'mkmf'
-
-dir_config('hangul')
-have_library('hangul', 'hangul_ic_new')
-create_makefile('hangul')
-
-# vim: set sts=2 sw=2 et:
+++ /dev/null
-/*
- * 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));
-}
-
+++ /dev/null
-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:
# 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)
# 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
])
동:䴀:
동:䵔:
동:䶱:
-동:中洞:지명
동가:東家:
동가:同價:
동가:動駕:
벽전과:壁錢科:
벽전화기:壁電話器:
벽제:碧蹄:
-벽제:�除:
+벽제:辟除:
벽제관:碧蹄館:
벽제관싸움:碧蹄館싸움:
벽제동:碧蹄洞:지명
벽조:碧潮:
벽조목:霹棗木:
-벽좌우:�左右:
+벽좌우:辟左右:
벽주:壁柱:
벽주:碧珠:
벽중깃:壁中깃:
북두진군:北斗眞君:
북두칠성:北斗七星:
북등:북燈:
-북량:北�:
+북량:北凉:
북로:北路:
북로:北虜:
북로고공:北路雇工:
수우:秀羽:
수우:樹羽:
수우:殊尤:
+수우:愁憂:
수우도:樹牛島:
수우도:水牛島:
수우죽백:垂于竹帛:
수우피:水牛皮:
-수우:愁憂:
수운:水雲:
수운:輸運:
수운:水運:
에어러샛계획:에어러샛計劃:
에어러솔폭탄:에어러솔爆彈:
에어셔종:에어셔種:
-에염:�焰:
에오세:에오世:
에올리아조식:에올리아調式:
에올리에제도:에올리에諸島:
육연성:六連星:
육연풍:陸軟風:
육영:育英:
-육영:育:
+육영:育嬰:
육영공원:育英公院:
육영사업:育英事業:
육영수:陸英修:
융모:絨毛:
융모막:絨毛膜:
융모상피종:絨毛上皮腫:
-융모성건초염:絨毛性腱�炎:
+융모성건초염:絨毛性腱鞘炎:
융모치:絨毛齒:
융모포:絨毛布:
융병:戎兵:
적다:摘茶:
적다:赤多:
적다마:赤多馬:
-적다:赤多:
적담:赤痰:
적담:敵膽:
적당:賊黨:
적록:赤鹿:
적록색:赤綠色:
적록색맹:赤綠色盲:
-적뢰:跡�:
+적뢰:摘蕾:
적료:赤蓼:
적료:寂廖:
적료:寂寥:
적사:敵使:
적사:積邪:
적사:謫徙:
-적사:�沙:
적사구근:積仕久勤:
적사인:積仕人:
적사진:赤寫眞:
족매:族妹:
족멸:族滅:
족문:足紋:
-족바지:足바지:
족박자:足拍子:
족반:足盤:
족반거상:足反居上:
척후병:斥候兵:
척후장:斥候將:
척후전:斥候戰:
-척다:隻다:
천:天:하늘 천
천:千:일천 천
천:川:내 천
청량:淸亮:
청량:淸凉:
청량:淸良:
-청량:淸�:
청량감:淸凉感:
청량동:淸凉洞:지명
청량동:靑良洞:지명
청량미:靑粱米:
청량미:淸凉味:
청량사육:淸凉飼育:
-청량산:淸�山:
+청량산:淸凉山:
청량속:靑梁粟:
청량음료:淸凉飮料:
-청량음료:淸�飮料:
청량음료점:淸凉飮料占:
-청량제:淸�劑:
+청량제:淸凉劑:
청량히:淸亮히:
청량히:淸凉히:
청려:靑藜:
췌언:贅言:
췌염:膵炎:
췌용:悴容:
-췌우:贅�:
췌육:贅肉:
췌장:膵臟:
췌장결석:膵臟結石:
팔불취:八不取:
팔사:八絲:
팔사첨작오:八四添作五:
-팔사파문자:�思巴文字:
+팔사파문자:八思巴文字:
팔삭:八朔:
팔삭동:八朔童:
팔삭동이:八朔童이:
포자:胞子:
포자:布子:
포자:鋪子:
-포자:�煮:
+포자:炮煮:
포자경:胞子莖:
포자군:胞子郡:
포자낭:胞子囊:
포장집:布帳집:
포장화심:包藏禍心:
포재:抱才:
-포재:�宰:
+포재:庖宰:
포저:蒲菹:
-포저:苞�:
+포저:苞苴:
포저화:布楮貨:
포전:浦田:
포전:圃田:
포접:抱接:
포접화합물:包接化合物:
포정:砲艇:
-포정:�丁:
+포정:庖丁:
포정:布政:지명
포정문:布政門:
포정사:布政司:
한필호:韓弼昊:
한하운:韓何雲:
한학:漢學:
-한학:寒:
+한학:寒瘧:
한학강:漢學講:
한학교수:漢學敎授:
한학문신전강:漢學文臣殿講:
회흑색:灰黑色:
회흘:回紇:
회흙바위:灰흙바위:
-회:回寺:
획:畵:畫의 俗字
획:獲:얻을 획
획:劃:쪼갤 획, 그을 획
+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
* 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
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
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
-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/
--- /dev/null
+debian/tmp/usr/share/libhangul usr/share/
-usr/share/*
-usr/lib/*.so*
+debian/tmp/usr/lib/lib*.so.* usr/lib/
#!/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
--- /dev/null
+version=3
+http://kldp.net/frs/?group_id=362 /frs/download.php/.*/libhangul-(.*)\.tar\.gz
--- /dev/null
+# 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
--- /dev/null
+doc:
+ doxygen
+
+clean:
+ rm -rf html
+
+upload:
+ cd html ; \
+ scp -pr * $(USER)@hangul.kldp.net:/var/lib/gforge/chroot/home/groups/hangul/htdocs
--- /dev/null
+/**
+
+@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
+
+ */
#include <stdbool.h>
#include <inttypes.h>
+#ifdef __GNUC__
+#define LIBHANGUL_DEPRECATED __attribute__((deprecated));
+#else
+#define LIBHANGUL_DEPRECATED
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif
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;
enum {
HANGUL_KEYBOARD_TYPE_JAMO,
- HANGUL_KEYBOARD_TYPE_JASO
+ HANGUL_KEYBOARD_TYPE_JASO,
+ HANGUL_KEYBOARD_TYPE_ROMAJA
};
/* keyboard */
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);
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);
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);
/* 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 */
-/**
- * @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;
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)
{
}
/**
- * @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)
}
/**
- * @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
}
/**
- * @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;
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)
if (!hangul_is_syllable(syllable))
return;
- syllable -= hangul_base;
+ syllable -= syllable_base;
if (jongseong != NULL) {
if (syllable % njongseong != 0)
*jongseong = jongseong_base + syllable % njongseong;
*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;
+}
/* 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
* 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*,
HangulICFilter filter;
void *filter_data;
+
+ unsigned int use_jamo_mode_only : 1;
};
#include "hangulkeyboard.h"
(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
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;
}
}
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 */
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;
}
}
return false;
}
} else {
- if (!hangul_is_jaso(c)) {
+ if (!hangul_is_jamo(c)) {
hangul_ic_flush_internal(hic);
return false;
}
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;
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)
{
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)
{
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)
{
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)
{
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)
{
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)
{
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);
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)
{
if (hic == NULL)
return;
- hic->output_mode = mode;
+ if (!hic->use_jamo_mode_only)
+ hic->output_mode = mode;
}
void
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)
{
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;
}
}
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)
{
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;
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)
{
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 */
{ 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 */
/* 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 {
#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,
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;
}
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 char* filename)
{
- 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')
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)
{
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)
{
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)
{
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);
}
}
return nconverted;
}
-
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
#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;
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);
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)
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);
--- /dev/null
+#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;
+}