pax_global_header00006660000000000000000000000064126271671160014523gustar00rootroot0000000000000052 comment=1773851d34abbffa917c299c06de50df2f13b1be yaskkserv-1.1.0/000077500000000000000000000000001262716711600135445ustar00rootroot00000000000000yaskkserv-1.1.0/COPYING000066400000000000000000000431041262716711600146010ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. yaskkserv-1.1.0/Makefile000066400000000000000000000067011262716711600152100ustar00rootroot00000000000000# -*- Makefile -*- include Makefile.config ifdef DEBUG export VAR_PATH = $(PROJECT_ROOT)/var/$(ARCHITECTURE_LOWER_CASE)/debug else # DEBUG export VAR_PATH = $(PROJECT_ROOT)/var/$(ARCHITECTURE_LOWER_CASE)/release endif # DEBUG export MAKEFILE = Makefile.$(ARCHITECTURE_LOWER_CASE) export MAKEDEPEND = $(PERL) -w $(PROJECT_ROOT)/tools/build/makedepend.$(ARCHITECTURE_LOWER_CASE) ifeq ($(ARCHITECTURE),BSD_CYGWIN_LINUX_GCC) SOURCE_PATH = ./source PRE_COMMAND = else # ($(ARCHITECTURE),BSD_CYGWIN_LINUX_GCC) include UNKNOWN_ARCHITECTURE_or_Makefile.config_not_found__please_execute_configure__dummy_include_file endif # ($(ARCHITECTURE),BSD_CYGWIN_LINUX_GCC) .PHONY : all clean run makerun break makebreak kill makekill debugger vlist vhist vreport tags depend cleandepend install package test setup all : setup $(PRE_COMMAND) $(MAKE) --no-print-directory -C $(SOURCE_PATH) -f $(MAKEFILE) all run : setup $(MAKE) --no-print-directory -C $(SOURCE_PATH) -f $(MAKEFILE) run makerun : setup $(PRE_COMMAND) $(MAKE) --no-print-directory -C $(SOURCE_PATH) -f $(MAKEFILE) makerun break : setup $(MAKE) --no-print-directory -C $(SOURCE_PATH) -f $(MAKEFILE) break makebreak : setup $(MAKE) --no-print-directory -C $(SOURCE_PATH) -f $(MAKEFILE) makebreak clean : setup $(MAKE) --no-print-directory -C $(SOURCE_PATH) -f $(MAKEFILE) clean realclean : setup $(RM) -rf ./var $(RM) -rf Makefile.config distclean : realclean depend : setup $(PRE_COMMAND) $(MAKE) --no-print-directory -C $(SOURCE_PATH) -f $(MAKEFILE) depend cleandepend : setup $(MAKE) --no-print-directory -C $(SOURCE_PATH) -f $(MAKEFILE) cleandepend test : $(MAKE) --no-print-directory -C $(SOURCE_PATH) -f $(MAKEFILE) test install_common_ : $(MKDIR) -p $(PREFIX)/bin $(INSTALL) $(VAR_PATH)/yaskkserv_make_dictionary/yaskkserv_make_dictionary $(PREFIX)/bin/yaskkserv_make_dictionary install : install_normal install_all : install_common_ $(MKDIR) -p $(PREFIX)/sbin $(INSTALL) $(VAR_PATH)/yaskkserv_simple/yaskkserv_simple $(PREFIX)/sbin/yaskkserv_simple $(INSTALL) $(VAR_PATH)/yaskkserv_normal/yaskkserv_normal $(PREFIX)/sbin/yaskkserv_normal $(INSTALL) $(VAR_PATH)/yaskkserv_hairy/yaskkserv_hairy $(PREFIX)/sbin/yaskkserv_hairy install_simple : install_common_ $(MKDIR) -p $(PREFIX)/sbin $(INSTALL) $(VAR_PATH)/yaskkserv_simple/yaskkserv_simple $(PREFIX)/sbin/yaskkserv install_normal : install_common_ $(MKDIR) -p $(PREFIX)/sbin $(INSTALL) $(VAR_PATH)/yaskkserv_normal/yaskkserv_normal $(PREFIX)/sbin/yaskkserv install_hairy : install_common_ $(MKDIR) -p $(PREFIX)/sbin $(INSTALL) $(VAR_PATH)/yaskkserv_hairy/yaskkserv_hairy $(PREFIX)/sbin/yaskkserv package : $(MKDIR) -p var &&\ $(MKDIR) -p var/package &&\ $(RM) -rf var/package/yaskkserv-$(PROJECT_VERSION).tar.gz &&\ $(RM) -rf var/package/yaskkserv-$(PROJECT_VERSION).tar.xz &&\ git archive --prefix=yaskkserv-$(PROJECT_VERSION)/ HEAD -o var/package/yaskkserv-$(PROJECT_VERSION).tar &&\ # hg archive var/package/yaskkserv-$(PROJECT_VERSION) &&\ cd var/package &&\ gzip -c -9 yaskkserv-$(PROJECT_VERSION).tar > yaskkserv-$(PROJECT_VERSION).tar.gz &&\ xz -9 yaskkserv-$(PROJECT_VERSION).tar &&\ sha1sum yaskkserv-$(PROJECT_VERSION).tar.gz yaskkserv-$(PROJECT_VERSION).tar.xz setup : mkdir -p $(VAR_PATH)/skk/architecture/$(ARCHITECTURE_LOWER_CASE) mkdir -p $(VAR_PATH)/yaskkserv_hairy mkdir -p $(VAR_PATH)/yaskkserv_make_dictionary mkdir -p $(VAR_PATH)/yaskkserv_normal mkdir -p $(VAR_PATH)/yaskkserv_simple yaskkserv-1.1.0/Makefile.noperl000066400000000000000000000076251262716711600165140ustar00rootroot00000000000000# -*- Makefile -*- .SUFFIXES : .PHONY : all setup clean install_common_ install install_all install_simple install_normal install_hairy PREFIX := /usr/local CXXFLAGS_CONFIG = -D YASKKSERV_VERSION=\"0.5.5\" CXXFLAGS_CONFIG += -Os # CXXFLAGS_CONFIG += -march=native CXXFLAGS_CONFIG += -D YASKKSERV_ARCHITECTURE_BSD_CYGWIN_LINUX_GCC CXXFLAGS_CONFIG += -D YASKKSERV_ARCHITECTURE_BYTE_ORDER_VAX CXXFLAGS_CONFIG += -D YASKKSERV_CONFIG_ENABLE_SYSLOG CXXFLAGS_CONFIG += -D YASKKSERV_CONFIG_ENABLE_ERROR_MESSAGE CXXFLAGS_CONFIG += -D YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT CXXFLAGS_CONFIG += -D YASKKSERV_CONFIG_HEADER_HAVE_ICONV_H ifneq (${shell uname}, Darwin) CXXFLAGS_CONFIG += -D YASKKSERV_CONFIG_MACRO_HAVE_SYMBOL_MSG_NOSIGNAL CXXFLAGS_CONFIG += -D YASKKSERV_CONFIG_FUNCTION_HAVE_TIMER_CREATE endif ARCHITECTURE_LOWER_CASE := bsd_cygwin_linux_gcc INCLUDE_FLAGS := -I . -I source/skk -I source/skk/architecture -I source/skk/architecture/$(ARCHITECTURE_LOWER_CASE) LIBRARY_FLAGS := -L/usr/lib CXXFLAGS := $(INCLUDE_FLAGS) $(CXXFLAGS_CONFIG) LDFLAGS := -lm -L/usr/lib ifeq (${shell uname}, Darwin) LDFLAGS := -liconv else LDFLAGS := -lrt endif CXX := g++ LD := $(CXX) RM := rm CP := cp MKDIR := mkdir INSTALL := install SKKLIB_SOURCES := ${wildcard source/skk/architecture/$(ARCHITECTURE_LOWER_CASE)/*.cpp} SKKLIB_OBJECTS := $(SKKLIB_SOURCES:.cpp=.o) MAKE_DICTIONARY_SOURCES := ${wildcard source/yaskkserv_make_dictionary/*.cpp} MAKE_DICTIONARY_OBJECTS := $(MAKE_DICTIONARY_SOURCES:.cpp=.o) SIMPLE_SOURCES := ${wildcard source/yaskkserv_simple/*.cpp} SIMPLE_OBJECTS := $(SIMPLE_SOURCES:.cpp=.o) NORMAL_SOURCES := ${wildcard source/yaskkserv_normal/*.cpp} NORMAL_OBJECTS := $(NORMAL_SOURCES:.cpp=.o) HAIRY_SOURCES := ${wildcard source/yaskkserv_hairy/*.cpp} HAIRY_OBJECTS := $(HAIRY_SOURCES:.cpp=.o) OBJECTS := $(SKKLIB_OBJECTS) $(MAKE_DICTIONARY_OBJECTS) $(SIMPLE_OBJECTS) $(NORMAL_OBJECTS) $(HAIRY_OBJECTS) TARGETS := source/yaskkserv_make_dictionary/yaskkserv_make_dictionary source/yaskkserv_simple/yaskkserv_simple source/yaskkserv_normal/yaskkserv_normal source/yaskkserv_hairy/yaskkserv_hairy all : setup $(TARGETS) setup : $(CP) -v source/skk/architecture/$(ARCHITECTURE_LOWER_CASE)/skk_gcc_precompile.h.in ./skk_gcc_precompile.h clean : -$(RM) $(OBJECTS) -$(RM) $(TARGETS) -$(RM) ./skk_gcc_precompile.h install_common_ : $(MKDIR) -p $(PREFIX)/bin $(INSTALL) source/yaskkserv_make_dictionary/yaskkserv_make_dictionary $(PREFIX)/bin/yaskkserv_make_dictionary install : install_normal install_all : install_common_ $(MKDIR) -p $(PREFIX)/sbin $(INSTALL) source/yaskkserv_simple/yaskkserv_simple $(PREFIX)/sbin/yaskkserv_simple $(INSTALL) source/yaskkserv_normal/yaskkserv_normal $(PREFIX)/sbin/yaskkserv_normal $(INSTALL) source/yaskkserv_hairy/yaskkserv_hairy $(PREFIX)/sbin/yaskkserv_hairy install_simple : install_common_ $(MKDIR) -p $(PREFIX)/sbin $(INSTALL) source/yaskkserv_simple/yaskkserv_simple $(PREFIX)/sbin/yaskkserv install_normal : install_common_ $(MKDIR) -p $(PREFIX)/sbin $(INSTALL) source/yaskkserv_normal/yaskkserv_normal $(PREFIX)/sbin/yaskkserv install_hairy : install_common_ $(MKDIR) -p $(PREFIX)/sbin $(INSTALL) source/yaskkserv_hairy/yaskkserv_hairy $(PREFIX)/sbin/yaskkserv source/yaskkserv_make_dictionary/yaskkserv_make_dictionary : skk $(MAKE_DICTIONARY_OBJECTS) $(LD) $(LDFLAGS) -o $@ ${wordlist 2, 99, $^} $(SKKLIB_OBJECTS) source/yaskkserv_simple/yaskkserv_simple : skk $(SIMPLE_OBJECTS) $(LD) $(LDFLAGS) -o $@ ${wordlist 2, 99, $^} $(SKKLIB_OBJECTS) source/yaskkserv_normal/yaskkserv_normal : skk $(NORMAL_OBJECTS) $(LD) $(LDFLAGS) -o $@ ${wordlist 2, 99, $^} $(SKKLIB_OBJECTS) source/yaskkserv_hairy/yaskkserv_hairy : skk $(HAIRY_OBJECTS) $(LD) $(LDFLAGS) -o $@ ${wordlist 2, 99, $^} $(SKKLIB_OBJECTS) skk : $(SKKLIB_OBJECTS) $(OBJECTS) : %.o : %.cpp $(CXX) $(CXXFLAGS) -c -o $@ $< yaskkserv-1.1.0/README.md000066400000000000000000000134261262716711600150310ustar00rootroot00000000000000# install yaskkserv をビルドすると、以下のプログラム群が作成されます。
yaskkserv_simple
もっともシンプルなサーバ
yaskkserv_normal
一般的なサーバ
yaskkserv_hairy
なんでもありサーバになる予定
yaskkserv_make_dictionary
yaskkserv 用辞書変換ユーティリティ
## configure 大抵の環境で、以下のように configure 一発でビルドできます。 ```sh $ ./configure $ make ``` configure は Perl スクリプトです。 Perl がない場合は後述の Makefile.noperl を使用します。 インストールすると PREFIX/bin にツールが、 PREFIX/sbin にサーバがインストールされます。 インストールするバイナリごとに仮想ターゲットを用意しています。 ### yaskkserv_normal を yaskkserv という名前でインストール ```sh # make install ``` or ```sh # make install_normal ``` ### yaskkserv_simple を yaskkserv という名前でインストール ```sh # make install_simple ``` ### yaskkserv_hairy を yaskkserv という名前でインストール ```sh # make install_hairy ``` ### yaskkserv_simple, yaskkserv_normal と yaskkserv_hairy をそのままの名前でインストール ```sh # make install_all ``` ### Perl が無い場合 Makefile.noperl を手で編集して、以下のようなコマンドでビルドできます。 ```sh $ make -f Makefile.noperl ``` インストールは Perl がある場合と同様、以下のように実行します。 ``` # make -f Makefile.noperl install_all ``` ## configure オプション
--gplusplus=G++
g++ の実行ファイルを指定します。特定バージョンの g++ を使う場合に便利です。
--help
使用法を表示します。
--enable-google-japanese-input
yaskkserv_hairy の google japanese input を有効にします。(デフォルト)
--disable-google-japanese-input
yaskkserv_hairy の google japanese input を無効にします。
--enable-google-suggest
yaskkserv_hairy の google suggest を有効にします。
--disable-google-suggest
yaskkserv_hairy の google suggest を無効にします。(デフォルト)
--enable-syslog
syslog 出力を有効にします。 (デフォルト)
--disable-error-message
syslog 出力を無効にします。
--enable-error-message
エラーメッセージ出力を有効にします。 (デフォルト)
--disable-error-message
エラーメッセージ出力を無効にします。ヘルプメッセージ等も表示されなくなるので注意が必要です。
--enable-systemd
systemd の socket activation を有効にします。 (デフォルト)
--disable-systemd
systemd の socket activation を無効にします。
--precompile
プリコンパイルヘッダを使用します。
--prefix=PREFIX
インストールディレクトリを指定します。
# つかいかた まず yaskkserv_make_dictionary で専用の辞書を作成する必要があります。 ```sh $ yaskkserv_make_dictionary SKK-JISYO.L SKK-JISYO.L.yaskkserv ``` 以上の操作で SKK-JISYO.L から SKK-JISYO.L.yaskkserv が作られます。 作成した辞書を指定してサーバを起動します。 ```sh $ yaskkserv SKK-JISYO.L.yaskkserv ``` ## google japanese input を辞書として使う google japanese input を有効にして --google-japanese-input=dictionary オプションを指定した場合、 yaskkserv_hairy では、辞書に「https://www.google.com」を指定できます。 https ではなく「http://www.google.com」を指定した場合は http でアクセスします。 ```sh $ yaskkserv --google-japanese-input=dictionary https://www.google.com ``` 同様に google suggest を有効にした場合、辞書に「https://suggest.google.com」を指定できます。 ```sh $ yaskkserv --google-japanese-input=dictionary https://suggest.google.com ``` 辞書は複数指定できます。 ```sh $ yaskkserv --google-japanese-input=dictionary LOCALDIC https://suggest.google.com https://www.google.com ``` google への問い合わせは --google-cache オプションでキャッシュすることも可能ですが、応答時間の違いから過去に変換した文字列を推測される恐れがあります。 ## ローカル辞書に見付からなかったときのみ google にアクセスする --google-japanese-input=notfound オプションを指定すると、辞書に候補が見付からなかったときにだけ google japanese input を検索します。以下のような組み合わせが可能です。 ### 辞書に候補が見付からなければ google japanese input に https でアクセス ```sh $ yaskkserv --google-japanese-input=notfound LOCALDIC ``` ### 辞書に候補が見付からなければ google suggest に https でアクセス ```sh $ yaskkserv --google-japanese-input=notfound --google-suggest LOCALDIC ``` ### 辞書に候補が見付からなければ google suggest の次に google japanese input に https でアクセス ```sh $ yaskkserv --google-japanese-input=notfound-suggest-input --google-suggest LOCALDIC ``` ### 辞書に候補が見付からなければ google japanese input の次に google suggest に https でアクセス ```sh $ yaskkserv --google-japanese-input=notfound-input-suggest --google-suggest LOCALDIC ``` --use-http オプションを付けることで https ではなく http でアクセスできます。 ## systemd の socket activation を利用する examples ディレクトリにある unit ファイルをインストールすることで、systemd の socket activation を利用して起動することができる。 yaskkserv-1.1.0/configure000077500000000000000000000573351262716711600154700ustar00rootroot00000000000000#!/usr/bin/perl -w use strict; use warnings; use Getopt::Long; use File::Temp; my %global_options = ( 'prefix' => '/usr/local', 'enable-google-japanese-input' => !0, 'enable-https' => !0, 'enable-gnutls' => !0, 'enable-openssl' => !0, 'enable-systemd' => !0, ); my %global; $global{'project_identifier'} = 'YASKKSERV'; $global{'version'} = '1.1.0'; # CompilerIsSupport($compiler_version, 3, 2, 1); sub CompilerIsSupport ($$$$) { my $compiler_version = $_[0]; my $major = $_[1]; my $minor = $_[2]; my $sub = $_[3]; if ($compiler_version >= $major * 1000000 + $minor * 1000 + $sub * 1) { return !0; } else { return 0; } } sub CompilerCheck ($$;$) { my $check_header = $_[0]; my $check_body = $_[1]; my $check_option = defined($_[2]) ? $_[2] : ''; # thanks! KURASHIKI-san and Debian my $temporary_filename_base = '/tmp/yaskkserv.configure.XXXXX'; my ($wfh_dummy, $temporary_filename_o) = File::Temp::mkstemps($temporary_filename_base, '.o'); my ($wfh, $temporary_filename_c) = File::Temp::mkstemps($temporary_filename_base, '.c'); print $wfh $check_header; print $wfh qq!int main(int argc, char *argv[])\n{\n!; print $wfh $check_body; print $wfh qq!return 0;\n}\n!; close($wfh); # thanks! KURASHIKI-san my $c = "$global{'compiler'} $check_option -c $temporary_filename_c -o $temporary_filename_o >/dev/null 2>&1"; system($c); my $result = $? ? 0 : !0; unlink($temporary_filename_o); unlink($temporary_filename_c); return $result; } sub LinkerCheckLibrary ($) { my $library_option = $_[0]; my $temporary_filename_base = '/tmp/yaskkserv.configure.XXXXX'; my ($wfh_dummy, $temporary_filename_execute) = File::Temp::mkstemps($temporary_filename_base, ''); my ($wfh, $temporary_filename_c) = File::Temp::mkstemps($temporary_filename_base, '.c'); print $wfh qq!int main(int argc, char *argv[])\n{\n!; print $wfh qq!return 0;\n}\n!; close($wfh); my $c = "$global{'compiler'} $temporary_filename_c -o $temporary_filename_execute $library_option >/dev/null 2>&1"; system($c); my $result = $? ? 0 : !0; unlink($temporary_filename_execute); unlink($temporary_filename_c); return $result; } sub isGcc () { if ($global{'compiler'} =~ /gcc/) { return !0; } 0; } sub isClang () { if ($global{'compiler'} =~ /clang/) { return !0; } 0; } sub getPkgConfig { my $command = $_[0]; my $args = $_[1]; my $result; if (defined($global{'pkg-config'})) { my $tmp = `pkg-config $command $args 2>&1`; if ($? == 0) { chomp($tmp); $result = $tmp; } } return $result; } $global{'data'} .= "# -*- Makefile -*-\n"; $global{'data'} .= "#\n"; $global{'data'} .= "# $0"; foreach (@ARGV) { $global{'data'} .= " $_"; } $global{'data'} .= "\n"; $global{'data'} .= "#\n"; $global{'data'} .= "# " . localtime() . "\n"; $global{'data'} .= "#\n"; $global{'data'} .= "# * DO NOT EDIT! *\n"; $global{'data'} .= "#\n"; GetOptions('gplusplus=s' => \$global_options{'gplusplus'}, 'compiler=s' => \$global_options{'compiler'}, 'help' => \$global_options{'help'}, 'enable-google-japanese-input' => \$global_options{'enable-google-japanese-input'}, 'disable-google-japanese-input' => \$global_options{'disable-google-japanese-input'}, 'enable-google-suggest' => \$global_options{'enable-google-suggest'}, 'disable-google-suggest' => \$global_options{'disable-google-suggest'}, 'enable-syslog' => \$global_options{'enable-syslog'}, 'disable-syslog' => \$global_options{'disable-syslog'}, 'enable-error-message' => \$global_options{'enable-error-message'}, 'disable-error-message' => \$global_options{'disable-error-message'}, 'enable-https' => \$global_options{'enable-https'}, 'disable-https' => \$global_options{'disable-https'}, 'enable-gnutls' => \$global_options{'enable-gnutls'}, 'disable-gnutls' => \$global_options{'disable-gnutls'}, 'enable-openssl' => \$global_options{'enable-openssl'}, 'disable-openssl' => \$global_options{'disable-openssl'}, 'enable-systemd' => \$global_options{'enable-systemd'}, 'disable-systemd' => \$global_options{'disable-systemd'}, 'precompile' => \$global_options{'precompile'}, 'prefix=s' => \$global_options{'prefix'}); if (defined($global_options{'help'})) { print "$0 usage\n"; print " --gplusplus=COMPILER *DEPRECATED* compiler [default g++]\n"; print " --compiler=COMPILER compiler (g++, clang++ or etc) [default g++]\n"; print " --help print this message\n"; print " --enable-google-japanese-input enable google japanese input (for yaskkserv_hairy) [default enable]\n"; print " --disable-google-japanese-input disable google japanese input (for yaskkserv_hairy) [default enable]\n"; print " --enable-google-suggest enable google suggest (for yaskkserv_hairy) [default disable]\n"; print " --disable-google-suggest disable google suggest (for yaskkserv_hairy) [default disable]\n"; print " --enable-syslog enable syslog [default]\n"; print " --disable-syslog disable syslog\n"; print " --enable-error-message enable error message [default]\n"; print " --disable-error-message disable error message\n"; print " --enable-https enable HTTPS [default]\n"; print " --disable-https disable HTTPS\n"; print " --enable-gnutls enable GnuTLS [default]\n"; print " --disable-gnutls disable GnuTLS\n"; print " --enable-openssl enable OpenSSL [default]\n"; print " --disable-openssl disable OpenSSL\n"; print " --enable-systemd enable systemd [default]\n"; print " --disable-systemd disable systemd\n"; print " --precompile use precompile (for G++ 4.0 or newer)\n"; print " --prefix=PREFIX install root directory [/usr/local]\n"; die; } { $_ = `pkg-config --version 2>&1`; if (defined($_)) { $global{'pkg-config'} = $_; print "pkg-config (found)\n"; } else { print "pkg-config (not found)\n"; } } { if (defined($global_options{'gplusplus'})) { $global{'compiler'} = $global_options{'gplusplus'}; print "*** Warning : --gplusplus is deprecated\n"; } elsif (defined($global_options{'compiler'})) { $global{'compiler'} = $global_options{'compiler'}; } else { my $tmp = 'g++'; $_ = `$tmp -v 2>&1`; if (defined($_)) { } else { $tmp = 'clang++'; $_ = `$tmp -v 2>&1`; unless (defined($_)) { print STDERR "*** Warning : compiler not found!\n"; } } $global{'compiler'} = $tmp; } $global{'data'} .= "export COMPILER = $global{'compiler'}\n"; } { my $tmp = 'make'; $_ = `$tmp -v 2>&1`; if (defined($_) and /gnu\s*make/im) { print "GNU Make ($tmp)\n"; } else { $tmp = 'gmake'; $_ = `$tmp -v 2>&1`; if (defined($_) and /gnu\s*make/im) { print "GNU Make ($tmp)\n"; } else { $tmp = 'gnumake'; $_ = `$tmp -v 2>&1`; if (defined($_) and /gnu\s*make/im) { print "GNU Make ($tmp)\n"; } else { print STDERR "*** Warning : GNU Make not found!\n"; } } } } { $global{'data'} .= "export MKDIR = mkdir\n"; } { $global{'data'} .= "export RM = rm\n"; } { $global{'data'} .= "export PERL = perl\n"; } { $global{'data'} .= "export INSTALL = install\n"; } { $global{'data'} .= "export PREFIX = $global_options{'prefix'}\n"; } { $global{'data'} .= "export PROJECT_IDENTIFIER = $global{'project_identifier'}\n"; $_ = $global{'project_identifier'}; tr/A-Z/a-z/; $global{'data'} .= "export PROJECT_IDENTIFIER_LOWER_CASE = $_\n"; } { $global{'data'} .= "export PROJECT_VERSION = $global{'version'}\n"; } { $_ = `pwd 2>&1`; chomp; $global{'project_root'} = $_; $global{'data'} .= "export PROJECT_ROOT = $global{'project_root'}\n"; } { my @compiler_version; foreach (split(/[\r\n]+/, `$global{'compiler'} -v 2>&1`)) { if (/\s*clang\s+version/ and m!\s+(\d+)\.(\d+)\.?(\d+)?!) { @compiler_version = ($1, $2, $3); last; } elsif (/^\s*gcc\s+version/ and m!\s+(\d+)\.(\d+)\.?(\d+)?!) { @compiler_version = ($1, $2, $3); last; } } if ($#compiler_version == -1) { $global{'compiler_version'} = 0; print STDERR "*** Warning : compiler version check failed.\n"; } else { my $pow = $#compiler_version; foreach (@compiler_version) { $_ = 0 unless defined($_); $global{'compiler_version'} += $_ * (1000 ** $pow); --$pow; } my $tmp; foreach (@compiler_version) { $tmp .= "$_."; } chop $tmp; print "compiler $global{'compiler'} ($tmp)\n"; } if (isGcc()) { unless (CompilerIsSupport($global{'compiler_version'}, 3, 3, 0)) { print STDERR "*** Warning : G++ is too old. need version 3.3 or newer.\n"; } } } if (defined($global_options{'precompile'})) { if (isClang()) { $global{'data'} .= "export USE_PRECOMPILE = t\n"; } elsif (isGcc()) { if (CompilerIsSupport($global{'compiler_version'}, 4, 0, 0)) { $global{'data'} .= "export USE_PRECOMPILE = t\n"; } else { print STDERR "*** Warning : G++ is too old. need version 4.0 or newer.\n"; } } } { $_ = pack('V', 1); if (unpack('C', $_) == 1) { $global{'data'} .= "export CXXFLAGS_BYTE_ORDER = -D $global{'project_identifier'}_ARCHITECTURE_BYTE_ORDER_VAX\n"; } else { $global{'data'} .= "export CXXFLAGS_BYTE_ORDER = -D $global{'project_identifier'}_ARCHITECTURE_BYTE_ORDER_NETWORK\n"; } $global{'data'} .= "export CXXFLAGS_CONFIG = \n"; unless (defined($global_options{'disable-syslog'})) { $global{'data'} .= "CXXFLAGS_CONFIG += -D $global{'project_identifier'}_CONFIG_ENABLE_SYSLOG\n"; } unless (defined($global_options{'disable-error-message'})) { $global{'data'} .= "CXXFLAGS_CONFIG += -D $global{'project_identifier'}_CONFIG_ENABLE_ERROR_MESSAGE\n"; } if (defined($global_options{'enable-google-japanese-input'}) and !defined($global_options{'disable-google-japanese-input'})) { { $_ = 'iconv.h'; my $found_flag; my $header_symbol = $_; $header_symbol =~ tr/a-z/A-Z/; $header_symbol =~ s![\./]!_!g; if (CompilerCheck("#include <$_>\n", '')) { my $const_char_code = <\n", $const_char_code)) { $found_flag = !0; print qq{$_ (argument "const char *" found)\n}; $global{'data'} .= "CXXFLAGS_CONFIG += -D $global{'project_identifier'}_CONFIG_ICONV_ARGUMENT_CONST_CHAR\n"; } elsif (CompilerCheck("#include <$_>\n", $char_code)) { $found_flag = !0; print qq{$_ (argument "char *" found)\n}; $global{'data'} .= "CXXFLAGS_CONFIG += -D $global{'project_identifier'}_CONFIG_ICONV_ARGUMENT_CHAR\n"; } else { print STDERR "*** Warning : iconv not found\n"; } if (defined($found_flag)) { $global{'data'} .= "CXXFLAGS_CONFIG += -D $global{'project_identifier'}_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT\n"; $global{'data'} .= "CXXFLAGS_CONFIG += -D $global{'project_identifier'}_CONFIG_HEADER_HAVE_$header_symbol\n"; if (defined($global_options{'enable-google-suggest'}) and !defined($global_options{'disable-google-suggest'})) { $global{'data'} .= "CXXFLAGS_CONFIG += -D $global{'project_identifier'}_CONFIG_ENABLE_GOOGLE_SUGGEST\n"; } } } unless (defined($found_flag)) { print "$_ (not found : DISABLE --enable-google-japanese-input)\n"; $global_options{'enable-google-japanese-input'} = undef; } } if (defined($global_options{'enable-https'}) and !defined($global_options{'disable-https'})) { if (defined($global_options{'enable-gnutls'}) and !defined($global_options{'disable-gnutls'})) { if (CompilerCheck("#include \n" . "#include \n" . "#include \n" , '')) { $global{'data'} .= "CXXFLAGS_CONFIG += -D $global{'project_identifier'}_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL\n"; $global{'HAVE_GNUTLS_OPENSSL'} = !0; print STDERR "SSL GnuTLS\n"; } if (defined($global{'HAVE_GNUTLS_OPENSSL'})) { if (CompilerCheck("#include \n" . "#include \n" . "#include \n" , 'RAND_poll();')) { $global{'data'} .= "CXXFLAGS_CONFIG += -D $global{'project_identifier'}_CONFIG_HEADER_HAVE_RAND_POLL\n"; print STDERR "SSL GnuTLS RAND_poll() (found)\n"; } else { print STDERR "SSL GnuTLS RAND_poll() (not found)\n"; } } } if (!defined($global{'HAVE_GNUTLS_OPENSSL'}) and defined($global_options{'enable-openssl'}) and !defined($global_options{'disable-openssl'})) { if (CompilerCheck("#include \n" . "#include \n" . "#include \n" . "#include \n" , '')) { $global{'data'} .= "CXXFLAGS_CONFIG += -D $global{'project_identifier'}_CONFIG_HEADER_HAVE_OPENSSL\n"; $global{'HAVE_OPENSSL'} = !0; print STDERR "SSL OpenSSL\n"; } if (defined($global{'HAVE_OPENSSL'})) { if (CompilerCheck("#include \n" . "#include \n" . "#include \n" . "#include \n" , 'RAND_poll();')) { $global{'data'} .= "CXXFLAGS_CONFIG += -D $global{'project_identifier'}_CONFIG_HEADER_HAVE_RAND_POLL\n"; print STDERR "SSL OpenSSL RAND_poll() (found)\n"; } else { print STDERR "SSL OpenSSL RAND_poll() (not found)\n"; } } } if (!defined($global{'HAVE_GNUTLS_OPENSSL'}) and !defined($global{'HAVE_OPENSSL'})) { if (!defined($global{'HAVE_GNUTLS_OPENSSL'})) { print STDERR "*** Warning : GnuTLS not found(or disable)\n"; } if (!defined($global{'HAVE_OPENSSL'})) { print STDERR "*** Warning : OpenSSL not found(or disable)\n"; } } } else { print STDERR "*** Warning : HTTPS disabled\n"; } } else { $global_options{'enable-google-japanese-input'} = undef; } if (defined($global_options{'enable-systemd'}) and !defined($global_options{'disable-systemd'})) { my $includes = "#include \n"; my $body = "int fd = SD_LISTEN_FDS_START;\n" . "int ret = sd_listen_fds(1);\n"; if (CompilerCheck($includes, $body)) { $global{'data'} .= "CXXFLAGS_CONFIG += -D $global{'project_identifier'}_CONFIG_HAVE_SYSTEMD\n"; $global{'HAVE_SYSTEMD'} = !0; print "SD_LISTEN_FDS_START and sd_listen_fds (found)\n"; } else { print STDERR "*** Warning : SD_LISTEN_FDS_START and sd_listen_fds are not found\n"; } } } { if (CompilerCheck("#include \n", "int tmp = MSG_NOSIGNAL;\n")) { $global{'data'} .= "CXXFLAGS_CONFIG += -D $global{'project_identifier'}_CONFIG_MACRO_HAVE_SYMBOL_MSG_NOSIGNAL\n"; print "MSG_NOSIGNAL (found)\n"; } else { print "MSG_NOSIGNAL (not found)\n"; } } { if (CompilerCheck("#include \n", "res_state r = &_res; int retrans = r->retrans; int retry = r->retry;\n")) { $global{'data'} .= "CXXFLAGS_CONFIG += -D $global{'project_identifier'}_CONFIG_MACRO_HAVE_SYMBOL_RESOLV_RETRANS_RETRY\n"; print "RESOLV_RETRANS_RETRY (found)\n"; } else { print "RESOLV_RETRANS_RETRY (not found)\n"; } } { if (CompilerCheck("#include \n" . "#include \n" , "timer_t timer_id;\n" . "timer_create(CLOCK_REALTIME, 0, &timer_id);\n")) { $global{'data'} .= "CXXFLAGS_CONFIG += -D $global{'project_identifier'}_CONFIG_FUNCTION_HAVE_TIMER_CREATE\n"; $global{'HAVE_TIMER_CREATE'} = !0; print "timer_create() (found)\n"; } else { print "timer_create() (not found)\n"; } } { if (CompilerCheck("#include \n" . "#include \n" , "sigset_t sigset;\n" . "pthread_sigmask(SIG_SETMASK, &sigset, NULL);\n")) { $global{'data'} .= "CXXFLAGS_CONFIG += -D $global{'project_identifier'}_CONFIG_HAVE_PTHREAD\n"; $global{'HAVE_PTHREAD'} = !0; print "pthread (found)\n"; } else { print "pthread (not found)\n"; } } { $_ = `uname 2>&1`; if (/(bsd)/i or /(darwin)/i or /(cygwin)/i or /(linux)/i) { $global{'OSNAME'} = $1; } else { print STDERR "*** Warning : unknown architecture ($_)\n"; $global{'OSNAME'} = 'linux'; } $global{'architecture'} = 'BSD_CYGWIN_LINUX_GCC'; $global{'CXXFLAGS_ARCHITECTURE'} = "-D $global{'project_identifier'}_ARCHITECTURE_BSD_CYGWIN_LINUX_GCC"; if (CompilerCheck('', '', '-std=c++11')) { $global{'CXXFLAGS_ARCHITECTURE'} .= ' -std=c++11 -D YASKKSERV_ARCHITECTURE_CXX11'; print STDERR "c++11 supported\n"; } $global{'LDFLAGS_ARCHITECTURE'} = ''; $global{'LDFLAGS_LIBRARY_SIMPLE'} = ''; $global{'LDFLAGS_LIBRARY_NORMAL'} = ''; $global{'LDFLAGS_LIBRARY_HAIRY'} = ''; if (LinkerCheckLibrary('-liconv')) { $global{'LDFLAGS_LIBRARY_HAIRY'} .= ' -liconv'; } $global{'LDFLAGS_LIBRARY_HAIRY'} .= ' -lrt' if defined($global{'HAVE_TIMER_CREATE'}); if (defined($global{'HAVE_GNUTLS_OPENSSL'})) { my $tmp = getPkgConfig('gnutls', '--libs'); my $libs; if (defined($tmp)) { $libs = ' ' . $tmp . ' -lgnutls-openssl'; unless (LinkerCheckLibrary($libs)) { $libs = undef; } } unless (defined($libs)) { if (LinkerCheckLibrary('-lgnutls-openssl')) { $libs = ' -lgnutls-openssl'; } } if (defined($libs)) { $global{'LDFLAGS_LIBRARY_HAIRY'} .= $libs; } else { print STDERR "*** Warning : GnuTLS library NOT FOUND\n"; } } if (defined($global{'HAVE_OPENSSL'})) { my $tmp = getPkgConfig('openssl', '--libs'); my $libs; if (defined($tmp)) { $libs = ' ' . $tmp; unless (LinkerCheckLibrary($libs)) { $libs = undef; } } unless (defined($libs)) { if (LinkerCheckLibrary('-lssl -lcrypto')) { $libs = ' -lssl -lcrypto'; } } if (defined($libs)) { $global{'LDFLAGS_LIBRARY_HAIRY'} .= $libs; } else { print STDERR "*** Warning : OpenSSL library NOT FOUND\n"; } } if (defined($global{'HAVE_PTHREAD'})) { if (LinkerCheckLibrary('-lpthread')) { $global{'LDFLAGS_LIBRARY_HAIRY'} .= ' -lpthread'; } } if (defined($global{'HAVE_SYSTEMD'})) { if (LinkerCheckLibrary('-lsystemd')) { $global{'LDFLAGS_LIBRARY_SIMPLE'} .= ' -lsystemd'; $global{'LDFLAGS_LIBRARY_NORMAL'} .= ' -lsystemd'; $global{'LDFLAGS_LIBRARY_HAIRY'} .= ' -lsystemd'; } } if (/cygwin/i) { $global{'EXECUTE_FILE_SUFFIX'} = '.exe'; } else { $global{'EXECUTE_FILE_SUFFIX'} = ''; } die "unknown architecture \"$_\"" unless defined($global{'architecture'}); $global{'data'} .= "export CXXFLAGS_ARCHITECTURE = $global{'CXXFLAGS_ARCHITECTURE'}\n"; $global{'data'} .= "export LDFLAGS_ARCHITECTURE = $global{'LDFLAGS_ARCHITECTURE'}\n"; $global{'data'} .= "export LDFLAGS_LIBRARY_SIMPLE = $global{'LDFLAGS_LIBRARY_SIMPLE'}\n"; $global{'data'} .= "export LDFLAGS_LIBRARY_NORMAL = $global{'LDFLAGS_LIBRARY_NORMAL'}\n"; $global{'data'} .= "export LDFLAGS_LIBRARY_HAIRY = $global{'LDFLAGS_LIBRARY_HAIRY'}\n"; $global{'data'} .= "export ARCHITECTURE = $global{'architecture'}\n"; $_ = $global{'architecture'}; tr/A-Z/a-z/; $global{'data'} .= "export ARCHITECTURE_LOWER_CASE = $_\n"; $global{'data'} .= "export EXECUTE_FILE_SUFFIX = $global{'EXECUTE_FILE_SUFFIX'}\n"; $global{'data'} .= "export OSNAME = $global{'OSNAME'}\n"; } { $_ = `ccache 2>&1`; if ($? >= 0) { $global{'data'} .= "export CCACHE = ccache\n"; print "ccache (found)\n"; } else { print "ccache (not found)\n"; } } { my $common = ''; if (CompilerCheck('', '', '-march=native')) { $common .= '-march=native'; } my $optimize = ''; if (isClang() or CompilerIsSupport($global{'compiler_version'}, 4, 0, 0)) { if (CompilerCheck("#include \n", '', '-Ofast')) { $optimize .= '-Ofast'; } elsif (CompilerCheck("#include \n", '', '-O3')) { $optimize .= '-O3'; print STDERR "*** Warning : -Ofast failed\n"; } else { $optimize .= '-Os'; print STDERR "*** Warning : -Ofast, -O3 failed\n"; } } else { # gcc3 Ϥʪ꤬ꥵʲ뤤ϵ路ʤС # ѥХ򤱤뤿˥ץƥޥ٥򲼤ޤ $_ = `cat /proc/meminfo 2>&1`; my $memory_size = 0 * 1024; if (/^MemTotal:\s+(\d+)\s+kB/) { $memory_size = $1; print "memory ($memory_size kB)\n"; } else { print "memory (unknown)\n"; } if ($memory_size < 320000) { $optimize .= '-Os'; print STDERR "*** Warning : optimize level changed (-O3 to -Os)\n"; } elsif (CompilerCheck("#include \n", '', '-O3')) { $optimize .= '-O3'; } else { $optimize .= '-Os'; print STDERR "*** Warning : -O3 failed\n"; } } { $global{'data'} .= 'export CXXFLAGS_OPTIMIZE_SERVER_SIMPLE = '; $global{'data'} .= "$common -Os\n"; } { $global{'data'} .= 'export CXXFLAGS_OPTIMIZE_SERVER_NORMAL = '; $global{'data'} .= "$common -Os\n"; } { $global{'data'} .= 'export CXXFLAGS_OPTIMIZE_SERVER_HAIRY = '; $global{'data'} .= "$common $optimize\n"; } { $global{'data'} .= 'export CXXFLAGS_OPTIMIZE_TOOL = '; $global{'data'} .= "$common $optimize\n"; } } { my $common = '-Wall -Wextra -W -Weffc++ -Wold-style-cast -Woverloaded-virtual -Wsign-promo -Wsynth -Wundef -Wshadow -Wlarger-than-16384 -Wpointer-arith -Wcast-qual -Wcast-align -Wconversion -Wsign-compare -Waggregate-return -Wmissing-noreturn -Wredundant-decls -Wnon-virtual-dtor -Wreorder -Wswitch-default -Wswitch-enum'; my $common_4_2_0 = '-Wabi -Wcomments -Wctor-dtor-privacy -Wdeprecated -Wendif-labels -Wfloat-equal -Wformat-extra-args -Wformat-nonliteral -Wformat-security -Wformat-y2k -Wimport -Winvalid-pch -Wmissing-include-dirs -Wmultichar -Wpragmas -Wredundant-decls -Wundef -Wunused-macros -Wvariadic-macros -Winvalid-offsetof -Wnon-template-friend -Wpmf-conversions -Wstrict-null-sentinel'; { $global{'data'} .= 'export CXXFLAGS_WARNING_SERVER_SIMPLE = '; $global{'data'} .= "$common_4_2_0 " if isClang() or CompilerIsSupport($global{'compiler_version'}, 4, 2, 0); $global{'data'} .= "$common\n"; } { $global{'data'} .= 'export CXXFLAGS_WARNING_SERVER_NORMAL = '; $global{'data'} .= "$common_4_2_0 " if isClang() or CompilerIsSupport($global{'compiler_version'}, 4, 2, 0); $global{'data'} .= "$common\n"; } { $global{'data'} .= 'export CXXFLAGS_WARNING_SERVER_HAIRY = '; $global{'data'} .= "$common_4_2_0 " if isClang() or CompilerIsSupport($global{'compiler_version'}, 4, 2, 0); $global{'data'} .= "$common\n"; } { $global{'data'} .= "export CXXFLAGS_WARNING_TOOL = "; $global{'data'} .= "$common_4_2_0 " if isClang() or CompilerIsSupport($global{'compiler_version'}, 4, 2, 0); $global{'data'} .= "$common\n"; } } if (defined($global_options{'enable-google-japanese-input'})) { print "************************************\n"; print "** enable google japanese input ! **\n"; print "** enable google suggest ! **\n" if defined $global_options{'enable-google-suggest'}; print "************************************\n"; } else { if (defined($global_options{'enable-google-suggest'})) { die "illegal options --enable-google-suggest"; } } { open(my $wfh, '>', 'Makefile.config') or die; print $wfh $global{'data'}; } yaskkserv-1.1.0/documentation/000077500000000000000000000000001262716711600164155ustar00rootroot00000000000000yaskkserv-1.1.0/documentation/TODO.txt000066400000000000000000000001161262716711600177210ustar00rootroot00000000000000- yaskkserv_make_dictionary ̃oCgI[_wΉB - hLgB yaskkserv-1.1.0/documentation/css/000077500000000000000000000000001262716711600172055ustar00rootroot00000000000000yaskkserv-1.1.0/documentation/css/default.css000066400000000000000000000021461262716711600213460ustar00rootroot00000000000000body { color: rgb(0, 0, 64); background-color: rgb(255, 248, 232); } address { text-align: right; } strong { background-color: rgb(0, 0, 0); } h1 { color: rgb(128, 64, 16); border-bottom: 3px solid rgb(128, 64, 16); } h1.space { margin-top: 2em; } h2 { color: rgb(128, 64, 16); border-bottom: 3px solid rgb(128, 64, 16); } pre.commandline { font-family: monospace; white-space: pre; border: none; padding: 4px; color: rgb(32, 32, 32); background-image: none; background-color: rgb(204, 192, 160); } pre.source { font-family: monospace; white-space: pre; border: none; padding: 4px; color: rgb(204, 204, 204); background-image: none; background-color: rgb(102, 102, 102); } pre.log { font-family: monospace; white-space: pre; border: none; padding: 4px; color: rgb(204, 204, 204); background-image: none; background-color: rgb(102, 102, 102); } div.center { text-align: center; } div.right { text-align: right; } div.title { font-family: Arial,sans-serif; font-weight: bold; text-align: center; font-size: large; margin-top: 2em; margin-bottom: 2em; } yaskkserv-1.1.0/documentation/index.html000066400000000000000000000017021262716711600204120ustar00rootroot00000000000000 hLggbvy[W / yaskkserv
yaskkserv ̃hLggbvy[W

hLg

ȉ̂悤ȃhLgpӂĂ܂B

yaskkserv-1.1.0/documentation/install.html000066400000000000000000000155531262716711600207620ustar00rootroot00000000000000 CXg[ / yaskkserv
CXg[ɂ‚

͂߂

̃pbP[WrhƁAȉ̃vOQ쐬܂B

yaskkserv_simple
ƂVvȃT[o
yaskkserv_normal
ʓIȃT[o
yaskkserv_hairy
ȂłT[oɂȂ\
yaskkserv_make_dictionary
yaskkserv pϊ[eBeB

CXg[

̊‹ŁA

$ ./configure
$ make

Ńrhł܂B configure Perl XNvgłB Perl Ȃꍇ͌q Makefile.noperl gp܂B

CXg[ PREFIX/bin Ƀc[A PREFIX/sbin ɃT[oCXg[܂B

CXg[oCiƂɉz^[QbgpӂĂ܂B

# make install
# make install_normal
(c[ƃT[oCXg[܂B yaskkserv_normal  yaskkserv ƂOŃCXg[܂B)

# make install_simple
(c[ƃT[oCXg[܂B yaskkserv_simple  yaskkserv ƂOŃCXg[܂B)

# make install_hairy
(c[ƃT[oCXg[܂B yaskkserv_hairy  yaskkserv ƂOŃCXg[܂B)

# make install_all
(c[ƃT[oCXg[܂B yaskkserv_simple, yaskkserv_normal  yaskkserv_hairy ͂̂܂܂̖OŃCXg[܂B)

Perl ꍇ Makefile.noperl ŕҏWāA

$ make -f Makefile.noperl

Ńrhł܂BCXg[ Perl ꍇƓlŁA

# make -f Makefile.noperl install_all
(c[ƃT[oCXg[܂B yaskkserv_simple, yaskkserv_normal  yaskkserv_hairy ͂̂܂܂̖OŃCXg[܂B)

̂悤Ɏs܂B

ӂKvȓ_

  • gcc-3.3 n + Ȃ@BŃrhɎs邱Ƃ
  • gcc 3.3 ȏオKv (߂ 4 n)
  • rhɂ Perl Kv

gcc-3.3 n + Ȃ@Bł̓RpC̃oO𓥂ŃrhɎs邱Ƃ܂B gcc-4 ngȂ@BŃrhKv܂B҂̊‹ł̓ 256M ̋@Bł̓rhɎsA 512M ̋@Bł͐܂B

configure IvV

--gplusplus=G++
g++ ̎st@Cw肵܂Bo[W g++ gꍇɕ֗łB
--help
gp@\܂B
--enable-google-japanese-input
yaskkserv_hairy google japanese input Lɂ܂B(ftHg)
--disable-google-japanese-input
yaskkserv_hairy google japanese input 𖳌ɂ܂B
--enable-google-suggest
yaskkserv_hairy google suggest Lɂ܂B
--disable-google-suggest
yaskkserv_hairy google suggest 𖳌ɂ܂B(ftHg)
--enable-syslog
syslog o͂Lɂ܂B (ftHg)
--disable-error-message
syslog o͂𖳌ɂ܂B
--enable-error-message
G[bZ[Wo͂Lɂ܂B (ftHg)
--disable-error-message
G[bZ[Wo͂𖳌ɂ܂BwvbZ[W\ȂȂ̂ŒӂKvłB
--precompile
vRpCwb_gp܂B
--prefix=PREFIX
CXg[fBNgw肵܂B

‚

܂ yaskkserv_make_dictionary Őp̎쐬Kv܂B

$ yaskkserv_make_dictionary SKK-JISYO.L SKK-JISYO.L.yaskkserv

ȏ̑ SKK-JISYO.L SKK-JISYO.L.yaskkserv ܂B

쐬w肵ăT[oN܂B

$ yaskkserv SKK-JISYO.L.yaskkserv

google japanese input ƂĎg

google japanese input Lɂ --google-japanese-input=dictionary IvVw肵ꍇA yaskkserv_hairy ł́AɁuhttps://www.google.comvwł܂B https ł͂Ȃuhttp://www.google.comvw肵ꍇ http ŃANZX܂B

$ yaskkserv --google-japanese-input=dictionary https://www.google.com

l google suggest LɂꍇAɁuhttps://suggest.google.comvwł܂B

$ yaskkserv --google-japanese-input=dictionary https://suggest.google.com

͕wł܂B

$ yaskkserv --google-japanese-input=dictionary LOCALDIC https://suggest.google.com https://www.google.com

google ւ̖₢킹 --google-cache IvVŃLbV邱Ƃ”\łAԂ̈Ⴂߋɕϊ𐄑鋰ꂪ܂B

[JɌtȂƂ̂ google ɃANZX

--google-japanese-input=notfound IvVw肷ƁAɌ₪tȂƂɂ google japanese input ܂Bȉ̂悤ȑgݍ킹”\łB

Ɍ₪tȂ google japanese input https ŃANZXB

$ yaskkserv --google-japanese-input=notfound LOCALDIC

Ɍ₪tȂ google suggest https ŃANZXB

$ yaskkserv --google-japanese-input=notfound --google-suggest LOCALDIC

Ɍ₪tȂ google suggest ̎ google japanese input https ŃANZXB

$ yaskkserv --google-japanese-input=notfound-suggest-input --google-suggest LOCALDIC

Ɍ₪tȂ google japanese input ̎ google suggest https ŃANZXB

$ yaskkserv --google-japanese-input=notfound-input-suggest --google-suggest LOCALDIC

--use-http IvVt邱Ƃ https ł͂Ȃ http ŃANZXł܂B

ڍׂzzTCgʼnĂ܂B


߂

yaskkserv-1.1.0/examples/000077500000000000000000000000001262716711600153625ustar00rootroot00000000000000yaskkserv-1.1.0/examples/yaskkserv.service000066400000000000000000000004201262716711600207620ustar00rootroot00000000000000[Unit] Description=Yet Another SKK server After=yaskkserv.socket Requires=yaskkserv.socket [Service] User=nobody ExecStart=/usr/bin/yaskkserv_hairy --no-daemonize --google-japanese-input=notfound /usr/share/skk/SKK-JISYO.L.yaskkserv [Install] WantedBy=multi-user.target yaskkserv-1.1.0/examples/yaskkserv.socket000066400000000000000000000001741262716711600206200ustar00rootroot00000000000000[Unit] Description=yaskkserv socket PartOf=yaskkserv.service [Socket] ListenStream=1178 [Install] WantedBy=sockets.target yaskkserv-1.1.0/skkserv.plist.in000066400000000000000000000006551262716711600167240ustar00rootroot00000000000000 Label org.umiushi.yaskkserv OnDemand ProgramArguments $(INSTALL_PATH)/$(INSTALL_PROGRAM) $(INSTALL_DICTIONARY) yaskkserv-1.1.0/source/000077500000000000000000000000001262716711600150445ustar00rootroot00000000000000yaskkserv-1.1.0/source/Makefile.bsd_cygwin_linux_gcc000066400000000000000000000035131262716711600226700ustar00rootroot00000000000000# -*- Makefile -*- .SUFFIXES : .PHONY : all clean run makerun break makebreak kill makekill debugger vlist vhist vreport test precompile depend cleandepend all : precompile $(MAKE) -f $(MAKEFILE) -C skk all $(MAKE) -f $(MAKEFILE) -C yaskkserv_simple all $(MAKE) -f $(MAKEFILE) -C yaskkserv_normal all $(MAKE) -f $(MAKEFILE) -C yaskkserv_hairy all $(MAKE) -f $(MAKEFILE) -C yaskkserv_make_dictionary all date echo '*** done.' clean : $(MAKE) -f $(MAKEFILE) -C skk clean $(MAKE) -f $(MAKEFILE) -C yaskkserv_simple clean $(MAKE) -f $(MAKEFILE) -C yaskkserv_normal clean $(MAKE) -f $(MAKEFILE) -C yaskkserv_hairy clean $(MAKE) -f $(MAKEFILE) -C yaskkserv_make_dictionary clean date echo '*** done.' run : $(MAKE) -f $(MAKEFILE) -C yaskkserv_hairy run date echo '*** done.' makerun : all run ifdef USE_PRECOMPILE precompile : $(VAR_PATH)/skk_gcc_precompile.h.gch $(VAR_PATH)/skk_gcc_precompile.h.gch : $(VAR_PATH)/skk_gcc_precompile.h cd $(VAR_PATH) && $(CXX) skk_gcc_precompile.h else # USE_PRECOMPILE precompile : $(VAR_PATH)/skk_gcc_precompile.h endif # USE_PRECOMPILE $(VAR_PATH)/skk_gcc_precompile.h : $(PROJECT_ROOT)/source/skk/architecture/$(ARCHITECTURE_LOWER_CASE)/skk_gcc_precompile.h.in cp -p $< $@ depend : precompile $(MAKE) -f $(MAKEFILE) -C skk depend $(MAKE) -f $(MAKEFILE) -C yaskkserv_simple depend $(MAKE) -f $(MAKEFILE) -C yaskkserv_normal depend $(MAKE) -f $(MAKEFILE) -C yaskkserv_hairy depend $(MAKE) -f $(MAKEFILE) -C yaskkserv_make_dictionary depend date echo '*** done.' cleandepend : $(MAKE) -f $(MAKEFILE) -C skk cleandepend $(MAKE) -f $(MAKEFILE) -C yaskkserv_simple cleandepend $(MAKE) -f $(MAKEFILE) -C yaskkserv_normal cleandepend $(MAKE) -f $(MAKEFILE) -C yaskkserv_hairy cleandepend $(MAKE) -f $(MAKEFILE) -C yaskkserv_make_dictionary cleandepend date echo '*** done.' yaskkserv-1.1.0/source/Makefile.bsd_cygwin_linux_gcc.common000066400000000000000000000022121262716711600241520ustar00rootroot00000000000000# -*- Makefile -*- ifdef DEBUG DEBUG_FLAGS = -g -rdynamic -D $(PROJECT_IDENTIFIER)_DEBUG OPTIMIZE_FLAGS = ifdef DEBUG_PARANOIA DEBUG_FLAGS += -D $(PROJECT_IDENTIFIER)_DEBUG_PARANOIA endif # DEBUG_PARANOIA else # DEBUG OPTIMIZE_FLAGS = $(CXXFLAGS_OPTIMIZE) # DEBUG_FLAGS = -pg endif # DEBUG INCLUDE_FLAGS = -I . -I $(VAR_PATH) -I $(PROJECT_ROOT)/source/skk -I $(PROJECT_ROOT)/source/skk/architecture -I $(PROJECT_ROOT)/source/skk/architecture/$(ARCHITECTURE_LOWER_CASE) LIBRARY_FLAGS = -L/usr/lib CPPFLAGS = $(DEBUG_FLAGS) $(CXXFLAGS_ARCHITECTURE) $(CXXFLAGS_BYTE_ORDER) $(CXXFLAGS_CONFIG) $(INCLUDE_FLAGS) $(CXXFLAGS_DEFINE) -D $(PROJECT_IDENTIFIER)_VERSION=\"$(PROJECT_VERSION)\" CXXFLAGS = $(DEBUG_FLAGS) $(CXXFLAGS_ARCHITECTURE) $(CXXFLAGS_BYTE_ORDER) $(CXXFLAGS_CONFIG) $(INCLUDE_FLAGS) $(OPTIMIZE_FLAGS) $(CXXFLAGS_WARNING) -fno-exceptions -fno-rtti -fmessage-length=0 -pipe -fPIC -D $(PROJECT_IDENTIFIER)_VERSION=\"$(PROJECT_VERSION)\" LDFLAGS = $(DEBUG_FLAGS) $(LDFLAGS_ARCHITECTURE) $(OPTIMIZE_FLAGS) -pipe $(LIBRARY_FLAGS) -fPIC CXX = $(CCACHE) $(COMPILER) LD = $(COMPILER) CPP = $(CXX) LD = $(CXX) STRIP = strip yaskkserv-1.1.0/source/skk/000077500000000000000000000000001262716711600156345ustar00rootroot00000000000000yaskkserv-1.1.0/source/skk/Makefile.bsd_cygwin_linux_gcc000066400000000000000000000017201262716711600234560ustar00rootroot00000000000000# -*- Makefile -*- include ../Makefile.$(ARCHITECTURE_LOWER_CASE).common SOURCES_MAIN = ${wildcard *.cpp} OBJECTS_MAIN = ${addprefix $(VAR_PATH)/skk/,$(SOURCES_MAIN:.cpp=.o)} SOURCES_ARCHITECTURE = ${wildcard architecture/$(ARCHITECTURE_LOWER_CASE)/*.cpp} OBJECTS_ARCHITECTURE = ${addprefix $(VAR_PATH)/skk/,$(SOURCES_ARCHITECTURE:.cpp=.o)} SOURCES = $(SOURCES_ARCHITECTURE) $(SOURCES_MAIN) OBJECTS = $(OBJECTS_ARCHITECTURE) $(OBJECTS_MAIN) DEPEND_FILE = $(VAR_PATH)/depend.skk .SUFFIXES : .PHONY : all clean run makerun break makebreak kill makekill debugger vlist vhist vreport test depend cleandepend all : $(OBJECTS) $(DEPEND_FILE) : $(MAKEDEPEND) $(VAR_PATH)/skk $(DEPEND_FILE) '$(CXX) $(CXXFLAGS)' '$(CPP) -E -MM $(CPPFLAGS) $(SOURCES)' depend : $(MAKEDEPEND) $(VAR_PATH)/skk $(DEPEND_FILE) '$(CXX) $(CXXFLAGS)' '$(CPP) -E -MM $(CPPFLAGS) $(SOURCES)' cleandepend : -$(RM) $(DEPEND_FILE) include $(DEPEND_FILE) clean : -$(RM) $(OBJECTS) yaskkserv-1.1.0/source/skk/architecture/000077500000000000000000000000001262716711600203165ustar00rootroot00000000000000yaskkserv-1.1.0/source/skk/architecture/bsd_cygwin_linux_gcc/000077500000000000000000000000001262716711600245015ustar00rootroot00000000000000yaskkserv-1.1.0/source/skk/architecture/bsd_cygwin_linux_gcc/skk_gcc.cpp000066400000000000000000000320731262716711600266160ustar00rootroot00000000000000/* Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012, 2013, 2014 Tadashi Watanabe This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "skk_gcc.hpp" namespace YaSkkServ { int global_sighup_flag = 0; int local_main(int argc, char *argv[]); namespace { void signal_dictionary_update_handler(int signum) { global_sighup_flag = 1; signum = 0; // KILLWARNING } } #ifdef YASKKSERV_DEBUG // skk_gcc.hpp Ƥޥ #undef new #undef delete void Debug::printf_core(const char *filename, int line, const char *p, ...) { char buffer[16 * 1024]; va_list ap; va_start(ap, p); vsnprintf(buffer, sizeof(buffer), p, ap); va_end(ap); FILE *file; time_t time_object; char tmp_buffer[1024]; file = fopen("/tmp/yaskkserv.debuglog.tmp", "a"); time_object = time(0); tmp_buffer[0] = '['; strcpy(&tmp_buffer[1], ctime(&time_object)); for (int i = 0; i != 1024 - 8; ++i) { if (tmp_buffer[i] == '\0') { break; } if (tmp_buffer[i] == '\n') { tmp_buffer[i + 0] = ']'; tmp_buffer[i + 1] = ':'; tmp_buffer[i + 2] = '\0'; fputs(tmp_buffer, file); break; } } fprintf(file, "%s:%d ", filename, line); fputs(buffer, file); fclose(file); } void Debug::print_core(const char *filename, int line, const char *p) { FILE *file; time_t time_object; char tmp_buffer[1024]; file = fopen("/tmp/yaskkserv.debuglog.tmp", "a"); time_object = time(0); tmp_buffer[0] = '['; strcpy(&tmp_buffer[1], ctime(&time_object)); for (int i = 0; i != 1024 - 8; ++i) { if (tmp_buffer[i] == '\0') { break; } if (tmp_buffer[i] == '\n') { tmp_buffer[i + 0] = ']'; tmp_buffer[i + 1] = ':'; tmp_buffer[i + 2] = '\0'; fputs(tmp_buffer, file); break; } } fprintf(file, "%s:%d ", filename, line); fputs(p, file); fclose(file); } #endif // YASKKSERV_DEBUG } #ifdef YASKKSERV_INTERNAL_DEBUG_NEW namespace { enum { YASKKSERV_INTERNAL_DEBUG_NEW_BUFFER_LENGTH = 16 * 1024 }; struct skk_debug_new_t { void *p; size_t size; char filename[128]; int line; }; // extern size_t skk_debug_new_total_size; bool skk_debug_new_first_flag = true; size_t skk_debug_new_total_size = 0; skk_debug_new_t skk_debug_new_buffer[YASKKSERV_INTERNAL_DEBUG_NEW_BUFFER_LENGTH]; // #pragma GCC diagnostic push // #pragma GCC diagnostic ignored "-Wlarger-than=" // extern skk_debug_new_t skk_debug_new_buffer[YASKKSERV_INTERNAL_DEBUG_NEW_BUFFER_LENGTH]; // #pragma GCC diagnostic pop void skk_debug_new_check_leak() { YaSkkServ::Debug::printf_core(__FILE__, __LINE__, "skk_debug_new_check_leak() skk_debug_new_total_size:%d\n", skk_debug_new_total_size); for (int i = 0; i != YASKKSERV_INTERNAL_DEBUG_NEW_BUFFER_LENGTH; ++i) { if (skk_debug_new_buffer[i].p) { YaSkkServ::Debug::printf_core(__FILE__, __LINE__, "leak:%p size:%d %s:%d\n", skk_debug_new_buffer[i].p, skk_debug_new_buffer[i].size, skk_debug_new_buffer[i].filename, skk_debug_new_buffer[i].line); } } } void skk_debug_new_initialize_first() { for (int i = 0; i != YASKKSERV_INTERNAL_DEBUG_NEW_BUFFER_LENGTH; ++i) { skk_debug_new_buffer[i].p = 0; skk_debug_new_buffer[i].size = 0; skk_debug_new_buffer[i].filename[0] = '\0'; skk_debug_new_buffer[i].line = 0; } skk_debug_new_first_flag = false; } } void *operator new(size_t size) { if (skk_debug_new_first_flag) { skk_debug_new_initialize_first(); } int i; for (i = 0; i != YASKKSERV_INTERNAL_DEBUG_NEW_BUFFER_LENGTH; ++i) { if (skk_debug_new_buffer[i].p == 0) { goto FOUND; } } #ifdef YASKKSERV_DEBUG_PARANOIA YaSkkServ::Debug::paranoia_assert_(__FILE__, __LINE__, 0); #endif // YASKKSERV_DEBUG_PARANOIA FOUND: skk_debug_new_total_size += size; void *p = malloc(size); skk_debug_new_buffer[i].p = p; skk_debug_new_buffer[i].size = size; strcpy(skk_debug_new_buffer[i].filename, "-"); skk_debug_new_buffer[i].line = 0; YaSkkServ::Debug::printf_core(__FILE__, __LINE__, "DEBUG new:%d total:%d p:%p id:%d\n", size, skk_debug_new_total_size, p, i); return p; } void *operator new(size_t size, const char *filename, int line) { if (skk_debug_new_first_flag) { skk_debug_new_initialize_first(); } YaSkkServ::Debug::printf_core(__FILE__, __LINE__, "filename:%s:%d\n", filename, line); int i; for (i = 0; i != YASKKSERV_INTERNAL_DEBUG_NEW_BUFFER_LENGTH; ++i) { if (skk_debug_new_buffer[i].p == 0) { goto FOUND; } } #ifdef YASKKSERV_DEBUG_PARANOIA YaSkkServ::Debug::paranoia_assert_(__FILE__, __LINE__, 0); #endif // YASKKSERV_DEBUG_PARANOIA FOUND: skk_debug_new_total_size += size; void *p = malloc(size); skk_debug_new_buffer[i].p = p; skk_debug_new_buffer[i].size = size; strcpy(skk_debug_new_buffer[i].filename, filename); skk_debug_new_buffer[i].line = line; YaSkkServ::Debug::printf_core(__FILE__, __LINE__, "DEBUG new:%d total:%d p:%p id:%d\n", size, skk_debug_new_total_size, p, i); return p; } void operator delete(void *p) { if (p == 0) { YaSkkServ::Debug::printf_core(__FILE__, __LINE__, "DEBUG delete null\n"); return; } int i; for (i = 0; i != YASKKSERV_INTERNAL_DEBUG_NEW_BUFFER_LENGTH; ++i) { if (skk_debug_new_buffer[i].p == p) { goto FOUND; } } #ifdef YASKKSERV_DEBUG_PARANOIA YaSkkServ::Debug::paranoia_assert_(__FILE__, __LINE__, 0); #endif // YASKKSERV_DEBUG_PARANOIA FOUND: size_t size = skk_debug_new_buffer[i].size; skk_debug_new_total_size -= size; YaSkkServ::Debug::printf_core(__FILE__, __LINE__, "DEBUG delete:%d total:%d p:%p id:%d filename:%s:%d\n", size, skk_debug_new_total_size, p, i, skk_debug_new_buffer[i].filename, skk_debug_new_buffer[i].line); skk_debug_new_buffer[i].p = 0; skk_debug_new_buffer[i].size = 0; skk_debug_new_buffer[i].filename[0] = '\0'; skk_debug_new_buffer[i].line = 0; free(p); } void *operator new[](size_t size) { if (skk_debug_new_first_flag) { skk_debug_new_initialize_first(); } int i; for (i = 0; i != YASKKSERV_INTERNAL_DEBUG_NEW_BUFFER_LENGTH; ++i) { if (skk_debug_new_buffer[i].p == 0) { goto FOUND; } } #ifdef YASKKSERV_DEBUG_PARANOIA YaSkkServ::Debug::paranoia_assert_(__FILE__, __LINE__, 0); #endif // YASKKSERV_DEBUG_PARANOIA FOUND: skk_debug_new_total_size += size; void *p = malloc(size); skk_debug_new_buffer[i].p = p; skk_debug_new_buffer[i].size = size; strcpy(skk_debug_new_buffer[i].filename, "-"); skk_debug_new_buffer[i].line = 0; YaSkkServ::Debug::printf_core(__FILE__, __LINE__, "DEBUG new[]:%d total:%d p:%p id:%d\n", size, skk_debug_new_total_size, p, i); return p; } void *operator new[](size_t size, const char *filename, int line) { if (skk_debug_new_first_flag) { skk_debug_new_initialize_first(); } YaSkkServ::Debug::printf_core(__FILE__, __LINE__, "filename:%s:%d\n", filename, line); int i; for (i = 0; i != YASKKSERV_INTERNAL_DEBUG_NEW_BUFFER_LENGTH; ++i) { if (skk_debug_new_buffer[i].p == 0) { goto FOUND; } } #ifdef YASKKSERV_DEBUG_PARANOIA YaSkkServ::Debug::paranoia_assert_(__FILE__, __LINE__, 0); #endif // YASKKSERV_DEBUG_PARANOIA FOUND: skk_debug_new_total_size += size; void *p = malloc(size); skk_debug_new_buffer[i].p = p; skk_debug_new_buffer[i].size = size; strcpy(skk_debug_new_buffer[i].filename, filename); skk_debug_new_buffer[i].line = line; YaSkkServ::Debug::printf_core(__FILE__, __LINE__, "DEBUG new[]:%d total:%d p:%p id:%d\n", size, skk_debug_new_total_size, p, i); return p; } void operator delete[](void *p) { if (p == 0) { YaSkkServ::Debug::printf_core(__FILE__, __LINE__, "DEBUG delete[] null\n"); return; } int i; for (i = 0; i != YASKKSERV_INTERNAL_DEBUG_NEW_BUFFER_LENGTH; ++i) { if (skk_debug_new_buffer[i].p == p) { goto FOUND; } } YaSkkServ::Debug::printf_core(__FILE__, __LINE__, "DEBUG delete[] %p not found\n", p); #ifdef YASKKSERV_DEBUG_PARANOIA YaSkkServ::Debug::paranoia_assert_(__FILE__, __LINE__, 0); #endif // YASKKSERV_DEBUG_PARANOIA FOUND: size_t size = skk_debug_new_buffer[i].size; skk_debug_new_total_size -= size; YaSkkServ::Debug::printf_core(__FILE__, __LINE__, "DEBUG delete:%d total:%d p:%p id:%d filename:%s:%d\n", size, skk_debug_new_total_size, p, i, skk_debug_new_buffer[i].filename, skk_debug_new_buffer[i].line); skk_debug_new_buffer[i].p = 0; skk_debug_new_buffer[i].size = 0; skk_debug_new_buffer[i].filename[0] = '\0'; skk_debug_new_buffer[i].line = 0; free(p); } #endif // YASKKSERV_INTERNAL_DEBUG_NEW int main(int argc, char *argv[]) { signal(SIGHUP, YaSkkServ::signal_dictionary_update_handler); int result = YaSkkServ::local_main(argc, argv); #ifdef YASKKSERV_INTERNAL_DEBUG_NEW skk_debug_new_check_leak(); #endif // YASKKSERV_INTERNAL_DEBUG_NEW return result; } yaskkserv-1.1.0/source/skk/architecture/bsd_cygwin_linux_gcc/skk_gcc.hpp000066400000000000000000000156471262716711600266330ustar00rootroot00000000000000/* Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012, 2013, 2014 Tadashi Watanabe This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef SKK_GCC_HPP #define SKK_GCC_HPP #include "skk_gcc_precompile.h" namespace YaSkkServ { extern int global_sighup_flag; /// ǥХå˴Ϣ֤̾Ǥ /** * \attention * DEBUG_PRINTF ϥޥ YASKKSERV_DEBUG ƤȤ * DEBUG_ASSERT ϥޥ YASKKSERV_DEBUG_PARANOIA ƤȤ * ͭˤʤޤ */ namespace Debug { template struct CompileTimeError; template<> struct CompileTimeError {}; template class TypeTraits { typedef char Size1; struct Size2 { char dummy[2]; }; struct Test { Test(const volatile void*); }; static inline Size1 get(Test); static inline Size2 get(...); static inline T& makeType(); enum { TYPE_SIZE = sizeof(get(makeType())) }; template static inline bool is_pointer() { return (type_size == sizeof(Size1)) ? true : false; } public: static inline bool isPointer() { return is_pointer(); } static inline void isPointerCompileTimeError() { CompileTimeError(); } }; template<> class TypeTraits { public: static inline bool isPointer() { return false; } }; #ifdef YASKKSERV_DEBUG void printf_core(const char *filename, int line, const char *p, ...); void print_core(const char *filename, int line, const char *p); #ifdef YASKKSERV_ARCHITECTURE_CXX11 #define DEBUG_PRINTF(...) Debug::printf_core(__FILE__, __LINE__, __VA_ARGS__) #else // YASKKSERV_ARCHITECTURE_CXX11 #define DEBUG_PRINTF(p, args...) Debug::printf_core(__FILE__, __LINE__, p, ## args) #endif // YASKKSERV_ARCHITECTURE_CXX11 #define DEBUG_PRINT(p) Debug::print_core(__FILE__, __LINE__, p) #else // YASKKSERV_DEBUG #ifdef YASKKSERV_ARCHITECTURE_CXX11 #define DEBUG_PRINTF(...) #else // YASKKSERV_ARCHITECTURE_CXX11 #define DEBUG_PRINTF(p, args...) #endif // YASKKSERV_ARCHITECTURE_CXX11 #define DEBUG_PRINT(p) #endif // YASKKSERV_DEBUG #ifdef YASKKSERV_DEBUG_PARANOIA inline void paranoia_assert_(const char *filename, int line, bool flag) { if (flag == false) { DEBUG_PRINTF("%s:%d ASSERT()\n", filename, line); } assert(flag); } template inline void paranoia_assert_range_(const char *filename, int line, T scalar, T minimum, T maximum) { if ((scalar < minimum) || (scalar > maximum)) { DEBUG_PRINTF("%s:%d ASSERT_RANGE()\n" " scalar = %d\n" "minimum = %d\n" "maximum = %d\n" , filename, line, scalar, minimum, maximum); assert(0); } } template inline void paranoia_assert_pointer_(const char *filename, int line, T p) { TypeTraits::isPointerCompileTimeError(); if (p == 0) { DEBUG_PRINTF("%s:%d ASSERT_POINTER()\n" " p = %p\n" , filename, line, p); assert(0); } } template inline void paranoia_assert_pointer_align_(const char *filename, int line, T p, int align) { TypeTraits::isPointerCompileTimeError(); if (p == 0) { DEBUG_PRINTF("%s:%d ASSERT_POINTER_ALIGN()\n" " p = %p\n" , filename, line, p); assert(0); } intptr_t tmp = reinterpret_cast(p); if ((tmp % align) != 0) { DEBUG_PRINTF("%s:%d ASSERT_POINTER_ALIGN()\n" " p = %p align = %d\n" , filename, line, p, (tmp % align)); assert(0); } } #define DEBUG_ASSERT(expr) Debug::paranoia_assert_(__FILE__, __LINE__, expr) #define DEBUG_ASSERT_RANGE(scalar, minimum, maximum) Debug::paranoia_assert_range_(__FILE__, __LINE__, scalar, minimum, maximum) #define DEBUG_ASSERT_POINTER(p) Debug::paranoia_assert_pointer_(__FILE__, __LINE__, p) #define DEBUG_ASSERT_POINTER_ALIGN(p, align) Debug::paranoia_assert_pointer_align_(__FILE__, __LINE__, p, align) #else // YASKKSERV_DEBUG_PARANOIA template inline void paranoia_assert_pointer_(T p) { TypeTraits::isPointerCompileTimeError(); (void)p; // AVOIDWARNING } template inline void paranoia_assert_pointer_align_(T p, int align) { TypeTraits::isPointerCompileTimeError(); (void)p; // AVOIDWARNING (void)align; // AVOIDWARNING } #define DEBUG_ASSERT(expr) #define DEBUG_ASSERT_RANGE(scalar, minimum, maximum) #define DEBUG_ASSERT_POINTER(p) Debug::paranoia_assert_pointer_(p) #define DEBUG_ASSERT_POINTER_ALIGN(p, align) Debug::paranoia_assert_pointer_align_(p, align) #endif // YASKKSERV_DEBUG_PARANOIA } } // // ʲ new/delete ޤǥХåѥɤǤ // #ifdef YASKKSERV_DEBUG #define YASKKSERV_INTERNAL_DEBUG_NEW #endif // YASKKSERV_DEBUG #ifdef YASKKSERV_INTERNAL_DEBUG_NEW #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wredundant-decls" void *operator new(size_t size); void *operator new(size_t size, const char *filename, int line); void operator delete(void *p); void *operator new[](size_t size); void *operator new[](size_t size, const char *filename, int line); void operator delete[](void *p); #pragma GCC diagnostic pop #define new new(__FILE__, __LINE__) #define delete DEBUG_PRINTF("delete:%s:%d\n", __FILE__, __LINE__), delete #endif // YASKKSERV_INTERNAL_DEBUG_NEW #endif // SKK_GCC_HPP yaskkserv-1.1.0/source/skk/architecture/bsd_cygwin_linux_gcc/skk_gcc_precompile.h.in000066400000000000000000000043141262716711600311040ustar00rootroot00000000000000/* Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012, 2013, 2014 Tadashi Watanabe This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef SKK_GCC_PRECOMPILE_H #define SKK_GCC_PRECOMPILE_H // C++ // C #include #include #include #include #include #include #include #include #include #include // BSD / Cygwin / Linux #include #include #include #include #include #include #include #include #include #include #include #include #include // pthread #ifdef YASKKSERV_CONFIG_HAVE_PTHREAD #include #endif // YASKKSERV_CONFIG_HAVE_PTHREAD // Socket #include #include #include #include #ifdef YASKKSERV_CONFIG_HEADER_HAVE_ICONV_H #include #endif // YASKKSERV_CONFIG_HEADER_HAVE_ICONV_H #ifdef YASKKSERV_CONFIG_MACRO_HAVE_SYMBOL_RESOLV_RETRANS_RETRY #include #endif // YASKKSERV_CONFIG_MACRO_HAVE_SYMBOL_RESOLV_RETRANS_RETRY #ifdef YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL #include #include #endif // YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL #ifdef YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL #include #include #include #include #include #endif // YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL #endif // SKK_GCC_PRECOMPILE_H yaskkserv-1.1.0/source/skk/architecture/bsd_cygwin_linux_gcc/skk_mmap.hpp000066400000000000000000000074451262716711600270260ustar00rootroot00000000000000/* Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012, 2013, 2014 Tadashi Watanabe This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef SKK_MMAP_HPP #define SKK_MMAP_HPP #include "skk_gcc.hpp" namespace YaSkkServ { class SkkMmap { SkkMmap(SkkMmap &source); SkkMmap& operator=(SkkMmap &source); public: virtual ~SkkMmap() { if (buffer_) { int result = munmap(buffer_, static_cast(filesize_)); if (result < 0) { DEBUG_PRINTF("munmap failed\n"); } } if (file_descriptor_ >= 0) { close(file_descriptor_); } } SkkMmap() : file_descriptor_(-1), filesize_(0), buffer_(0) { } #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" /// եΰ˥ޥåפޤϥΰؤΥݥ󥿤򡢼Ԥ 0 ֤ޤоݤ̾ΥեξΤޤ void *map(const char *filename) { file_descriptor_ = open(filename, O_RDONLY); if (file_descriptor_ < 0) { DEBUG_PRINTF("file \"%s\" open failed.\n", filename); } else { struct stat stat_buffer; fstat(file_descriptor_, &stat_buffer); if (!S_ISREG(stat_buffer.st_mode)) { DEBUG_PRINTF("S_ISREG() failed.\n"); } else { filesize_ = static_cast(stat_buffer.st_size); buffer_ = mmap(0, static_cast(filesize_), PROT_READ, MAP_PRIVATE, file_descriptor_, 0); if (buffer_ == MAP_FAILED) { DEBUG_PRINTF("mmap failed.\n"); buffer_ = 0; } } } return buffer_; } #pragma GCC diagnostic pop /// ޥåפΰؤΥݥ󥿤֤ޤޥåפ˼Ԥ map() ¹ԤƤʤä 0 ֤ޤΤȤǥХåӥɤʤХȤޤ void *getBuffer() { DEBUG_ASSERT(file_descriptor_ != -1); DEBUG_ASSERT_POINTER(buffer_); return buffer_; } /// ޥåפեΥ֤ޤޥåפ˼Ԥ map() ¹ԤƤʤä 0 ֤ޤΤȤǥХåӥɤʤХȤޤ int getFilesize() { DEBUG_ASSERT(file_descriptor_ != -1); DEBUG_ASSERT_POINTER(buffer_); return filesize_; } private: int file_descriptor_; int filesize_; void *buffer_; }; } #endif // SKK_MMAP_HPP yaskkserv-1.1.0/source/skk/architecture/bsd_cygwin_linux_gcc/skk_socket.cpp000066400000000000000000000016021262716711600273440ustar00rootroot00000000000000/* Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012, 2013, 2014 Tadashi Watanabe This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "skk_socket.hpp" namespace YaSkkServ { sigjmp_buf SkkSocket::jump_buffer_; } yaskkserv-1.1.0/source/skk/architecture/bsd_cygwin_linux_gcc/skk_socket.hpp000066400000000000000000000610231262716711600273540ustar00rootroot00000000000000/* Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012, 2013, 2014 Tadashi Watanabe This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef SKK_SOCKET_HPP #define SKK_SOCKET_HPP #include "skk_gcc.hpp" namespace YaSkkServ { class SkkSocket { SkkSocket(SkkSocket &source); SkkSocket& operator=(SkkSocket &source); public: virtual ~SkkSocket() { #if defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) shutdownASyncSocketSsl(); if (ssl_ctx_) { SSL_CTX_free(ssl_ctx_); } #endif // defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) } SkkSocket() : #if defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) ssl_ctx_(0), ssl_(0), #endif // defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) getaddrinfo_result_(EAI_SYSTEM), internal_addrinfo_(0) { #if defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) #ifdef YASKKSERV_DEBUG SSL_load_error_strings(); #endif // YASKKSERV_DEBUG SSL_library_init(); ssl_ctx_ = SSL_CTX_new(SSLv23_client_method()); if (ssl_ctx_ == 0) { #ifdef YASKKSERV_DEBUG char error_buffer[1024]; fprintf(stderr, "%s\n", ERR_error_string(ERR_get_error(), error_buffer)); #endif // YASKKSERV_DEBUG DEBUG_ASSERT(0); exit(1); } #endif // defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) } static int send(int fd, const void *buffer, int size) { #ifdef YASKKSERV_CONFIG_MACRO_HAVE_SYMBOL_MSG_NOSIGNAL return static_cast(::send(fd, buffer, static_cast(size), MSG_NOSIGNAL)); #else // YASKKSERV_CONFIG_MACRO_HAVE_SYMBOL_MSG_NOSIGNAL return static_cast(::send(fd, buffer, size, 0)); #endif // YASKKSERV_CONFIG_MACRO_HAVE_SYMBOL_MSG_NOSIGNAL } static int receive(int fd, void *buffer, int size) { return static_cast(recv(fd, buffer, static_cast(size), 0)); } #if defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) int writeSsl(const void *buffer, int size) { DEBUG_ASSERT_POINTER(ssl_ctx_); DEBUG_ASSERT_POINTER(ssl_); return static_cast(SSL_write(ssl_, buffer, size)); } int readSsl(void *buffer, int size) { DEBUG_ASSERT_POINTER(ssl_ctx_); DEBUG_ASSERT_POINTER(ssl_); return static_cast(SSL_read(ssl_, buffer, size)); } void shutdownASyncSocketSsl() { DEBUG_ASSERT_POINTER(ssl_ctx_); DEBUG_ASSERT_POINTER(ssl_); if (ssl_) { for (;;) { int shutdown_result = SSL_shutdown(ssl_); if (shutdown_result == 1) { break; } else { int ssl_error = SSL_get_error(ssl_, shutdown_result); if (ssl_error == SSL_ERROR_SYSCALL) { DEBUG_PRINTF("SSL_ERROR_SYSCALL\n"); break; } else if ((ssl_error == SSL_ERROR_WANT_READ) || (ssl_error == SSL_ERROR_WANT_WRITE)) { DEBUG_PRINTF(" shutdown ssl_error=%d\n", ssl_error); } else { DEBUG_PRINTF("SSL_shutdown() failed\n"); DEBUG_ASSERT(0); break; } } usleep(10 * 1000); } SSL_free(ssl_); ssl_ = 0; } } bool isBusySsl(int send_receive_result) { DEBUG_ASSERT_POINTER(ssl_ctx_); DEBUG_ASSERT_POINTER(ssl_); if (ssl_) { int ssl_error = SSL_get_error(ssl_, send_receive_result); DEBUG_PRINTF("send_receive_result=%d ssl_error=%d\n", send_receive_result, ssl_error); if ((ssl_error == SSL_ERROR_WANT_READ) || (ssl_error == SSL_ERROR_WANT_WRITE) || (ssl_error == SSL_ERROR_ZERO_RETURN)) { return true; } } return false; } #endif // defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) // socket file descriptor ֤ޤԤʤ -1 ֤ޤ timeout äǥॢȤޤ int prepareASyncSocket(const char *server, const char *service, float timeout, bool is_ipv6) { DEBUG_PRINTF("prepareASyncSocket(%s, %s, %6.2f)\n", server, service, timeout); struct addrinfo *addrinfo = prepareASyncSocketGetAddrinfo(server, service, timeout, is_ipv6); if (addrinfo == 0) { return -1; } int socket_fd = prepareASyncSocketGetSocketFd(addrinfo, timeout); freeInternalAddrinfo(); return socket_fd; } #if defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) int prepareASyncSocketSsl(const char *server, const char *service, float timeout, bool is_ipv6) { DEBUG_ASSERT_POINTER(ssl_ctx_); DEBUG_PRINTF("prepareASyncSocketSsl(%s, %s, %6.2f)\n", server, service, timeout); struct addrinfo *addrinfo = prepareASyncSocketGetAddrinfo(server, service, timeout, is_ipv6); if (addrinfo == 0) { return -1; } int socket_fd = prepareASyncSocketGetSocketFd(addrinfo, timeout); freeInternalAddrinfo(); if (socket_fd < 0) { return -1; } ssl_ = SSL_new(ssl_ctx_); if (ssl_ == 0) { #ifdef YASKKSERV_DEBUG char error_buffer[1024]; fprintf(stderr, "%s\n", ERR_error_string(ERR_get_error(), error_buffer)); #endif // YASKKSERV_DEBUG close(socket_fd); return -1; } if (SSL_set_fd(ssl_, socket_fd) == 0) { #ifdef YASKKSERV_DEBUG char error_buffer[1024]; fprintf(stderr, "%s\n", ERR_error_string(ERR_get_error(), error_buffer)); #endif // YASKKSERV_DEBUG // SSL_shutdown(ssl_); // ssl_ = 0; shutdownASyncSocketSsl(); close(socket_fd); return -1; } #ifdef YASKKSERV_CONFIG_HEADER_HAVE_RAND_POLL RAND_poll(); #endif // YASKKSERV_CONFIG_HEADER_HAVE_RAND_POLL // if (RAND_status() == 0) // FIXME! // { // SSL_shutdown(ssl_); // ssl_ = 0; // close(socket_fd); // return -1; // } for (;;) { int ssl_connect_result = SSL_connect(ssl_); if (ssl_connect_result == 1) { break; } else { int ssl_error = SSL_get_error(ssl_, ssl_connect_result); if ((ssl_error == SSL_ERROR_WANT_READ) || (ssl_error == SSL_ERROR_WANT_WRITE) || (ssl_error == SSL_ERROR_ZERO_RETURN)) // if (isBusySsl(ssl_connect_result)) { usleep(10 * 1000); } else { shutdownASyncSocketSsl(); close(socket_fd); return -1; } } } return socket_fd; } #endif // defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) private: static void sighandler(int signum) __attribute__ ((noreturn)) { (void)signum; DEBUG_PRINTF("sighandler(%d)\n", signum); siglongjmp(jump_buffer_, -1); } #ifdef YASKKSERV_CONFIG_MACRO_HAVE_SYMBOL_RESOLV_RETRANS_RETRY struct addrinfo *prepareASyncSocketGetAddrinfo(const char *server, const char *service, float timeout, bool is_ipv6) { DEBUG_ASSERT_POINTER(server); DEBUG_PRINTF(" try getaddrinfo\n"); res_state res = &_res; int int_timeout = static_cast(timeout); if (int_timeout < 1) { int_timeout = 1; } res->retrans = int_timeout; res->retry = 1; DEBUG_PRINTF(" res->retrans=%d res->retry=%d\n", res->retrans, res->retry); struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_flags = 0; if (is_ipv6) { hints.ai_family = AF_UNSPEC; // IPv4 or IPv6 } else { hints.ai_family = AF_INET; } hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = 0; hints.ai_addr = 0; hints.ai_canonname = 0; hints.ai_next = 0; getaddrinfo_result_ = EAI_SYSTEM; internal_addrinfo_ = 0; getaddrinfo_result_ = getaddrinfo(server, service, &hints, &internal_addrinfo_); DEBUG_PRINTF(" done getaddrinfo getaddrinfo_result_=%d internal_addrinfo_=%p\n", getaddrinfo_result_, internal_addrinfo_); if (getaddrinfo_result_ == 0) { DEBUG_PRINTF(" getaddrinfo() success internal_addrinfo_=%p\n", internal_addrinfo_); } else { internal_addrinfo_ = 0; } return internal_addrinfo_; } #else // YASKKSERV_CONFIG_MACRO_HAVE_SYMBOL_RESOLV_RETRANS_RETRY // ॢդ addrinfo ֤ޤ addrinfo 0 ʳξɬ freeaddrinfo() Dzɬפ뤳ȤդɬפǤԤʤ 0 ֤ޤ #ifdef YASKKSERV_CONFIG_FUNCTION_HAVE_TIMER_CREATE struct addrinfo *prepareASyncSocketGetAddrinfo(const char *server, const char *service, float timeout, bool is_ipv6) { DEBUG_ASSERT_POINTER(server); signal(SIGALRM, sighandler); static timer_t timer_id; struct itimerspec timer_clear_value; timer_clear_value.it_interval.tv_sec = 0; timer_clear_value.it_interval.tv_nsec = 0; timer_clear_value.it_value.tv_sec = 0; timer_clear_value.it_value.tv_nsec = 0; if (sigsetjmp(jump_buffer_, 1) == 0) { struct itimerspec set_value; { int64_t tmp = static_cast(timeout) * 1000 * 1000 * 1000; time_t second = static_cast(tmp / 1000 / 1000 / 1000); long nsecond = static_cast(tmp - second * 1000 * 1000 * 1000); set_value.it_interval.tv_sec = 0; set_value.it_interval.tv_nsec = 0; set_value.it_value.tv_sec = second; set_value.it_value.tv_nsec = nsecond; } if (timer_create(CLOCK_REALTIME, 0, &timer_id) == -1) { DEBUG_PRINTF(" timer_create() failed\n"); return 0; } DEBUG_PRINTF(" timer_id=%d\n", timer_id); if (timer_settime(timer_id, 0, &set_value, 0) == -1) { DEBUG_PRINTF(" timer_settime() failed timer_id=%d\n", timer_id); timer_delete(timer_id); return 0; } DEBUG_PRINTF(" try getaddrinfo\n"); struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_flags = 0; if (is_ipv6) { hints.ai_family = AF_UNSPEC; // IPv4 or IPv6 } else { hints.ai_family = AF_INET; } hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = 0; hints.ai_addr = 0; hints.ai_canonname = 0; hints.ai_next = 0; getaddrinfo_result_ = EAI_SYSTEM; internal_addrinfo_ = 0; getaddrinfo_result_ = getaddrinfo(server, service, &hints, &internal_addrinfo_); int clear_timer_settime_result = timer_settime(timer_id, 0, &timer_clear_value, 0); DEBUG_PRINTF(" done getaddrinfo getaddrinfo_result_=%d internal_addrinfo_=%p\n", getaddrinfo_result_, internal_addrinfo_); if (getaddrinfo_result_ == 0) { DEBUG_PRINTF(" getaddrinfo() success internal_addrinfo_=%p\n", internal_addrinfo_); } else { internal_addrinfo_ = 0; } if (clear_timer_settime_result == -1) { DEBUG_PRINTF(" timer_settime() clear failed timer_id=%d\n", timer_id); freeInternalAddrinfo(); } if (timer_delete(timer_id) == -1) { DEBUG_PRINTF(" timer_delete() failed timer_id=%d\n", timer_id); freeInternalAddrinfo(); } } else { if (internal_addrinfo_) { DEBUG_PRINTF(" BAD TIMING freeaddrinfo() getaddrinfo_result_=%d internal_addrinfo_=%p\n", getaddrinfo_result_, internal_addrinfo_); freeInternalAddrinfo(); } timer_settime(timer_id, 0, &timer_clear_value, 0); timer_delete(timer_id); DEBUG_PRINTF("signal jmp\n"); } return internal_addrinfo_; } #else // YASKKSERV_CONFIG_FUNCTION_HAVE_TIMER_CREATE struct addrinfo *prepareASyncSocketGetAddrinfo(const char *server, const char *service, float timeout, bool is_ipv6) { DEBUG_ASSERT_POINTER(server); signal(SIGALRM, sighandler); if (sigsetjmp(jump_buffer_, 1) == 0) { { struct itimerval new_value; { int64_t tmp = static_cast(timeout) * 1000 * 1000; time_t second = tmp / 1000 / 1000; long usecond = tmp - second * 1000 * 1000; new_value.it_interval.tv_sec = 0; new_value.it_interval.tv_usec = 0; new_value.it_value.tv_sec = second; new_value.it_value.tv_usec = usecond; } if (setitimer(ITIMER_REAL, &new_value, 0) == -1) { DEBUG_PRINTF(" setitimer() failed\n"); return 0; } } DEBUG_PRINTF(" try getaddrinfo\n"); struct addrinfo hints; memset(&hints, 0, sizeof(hints)); if (is_ipv6) { hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG; hints.ai_family = AF_UNSPEC; // IPv4 or IPv6 } else { hints.ai_flags = AI_V4MAPPED; hints.ai_family = AF_INET; } hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = 0; hints.ai_addr = 0; hints.ai_canonname = 0; hints.ai_next = 0; getaddrinfo_result_ = EAI_SYSTEM; internal_addrinfo_ = 0; struct itimerval cancel_value; cancel_value.it_interval.tv_sec = 0; cancel_value.it_interval.tv_usec = 0; cancel_value.it_value.tv_sec = 0; cancel_value.it_value.tv_usec = 0; getaddrinfo_result_ = getaddrinfo(server, service, &hints, &internal_addrinfo_); int clear_timer_result = setitimer(ITIMER_REAL, &cancel_value, 0); DEBUG_PRINTF(" done getaddrinfo getaddrinfo_result_=%d internal_addrinfo_=%p\n", getaddrinfo_result_, internal_addrinfo_); if (getaddrinfo_result_ == 0) { DEBUG_PRINTF(" getaddrinfo() success internal_addrinfo_=%p\n", internal_addrinfo_); } else { internal_addrinfo_ = 0; } if (clear_timer_result == -1) { DEBUG_PRINTF(" clear timer failed\n"); freeInternalAddrinfo(); } } else { if (internal_addrinfo_) { DEBUG_PRINTF(" BAD TIMING freeaddrinfo() getaddrinfo_result_=%d internal_addrinfo_=%p\n", getaddrinfo_result_, internal_addrinfo_); freeInternalAddrinfo(); } DEBUG_PRINTF("signal jmp\n"); } return internal_addrinfo_; } #endif // YASKKSERV_CONFIG_FUNCTION_HAVE_TIMER_CREATE #endif // YASKKSERV_CONFIG_MACRO_HAVE_SYMBOL_RESOLV_RETRANS_RETRY #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" // Ԥʤ -1 ֤ޤ static int prepareASyncSocketGetSocketFd(struct addrinfo *addrinfo, float timeout) { DEBUG_ASSERT_POINTER(addrinfo); int socket_fd = socket(AF_INET, SOCK_STREAM, 0); if (socket_fd < 0) { return -1; } fcntl(socket_fd, F_SETFL, O_NONBLOCK); bool socket_fd_fail_close_flag = true; int connect_result = connect(socket_fd, addrinfo->ai_addr, addrinfo->ai_addrlen); DEBUG_PRINTF("connect_result=%d errno=%d\n", connect_result); if ((connect_result == -1) && (errno == EINPROGRESS)) { fd_set fds; struct timeval tv; int sec = static_cast(timeout); int usec = static_cast((timeout - static_cast(sec))) * 1000 * 1000; tv.tv_sec = sec; tv.tv_usec = usec; FD_ZERO(&fds); FD_SET(socket_fd, &fds); DEBUG_PRINTF("try select\n"); int select_result = select(socket_fd + 1, 0, &fds, 0, &tv); if (select_result == 0) { // timeout DEBUG_PRINTF("select timeout\n"); } else if (select_result != -1) { DEBUG_PRINTF("select success\n"); int optval; socklen_t optlen = sizeof(optval); if (getsockopt(socket_fd, SOL_SOCKET, SO_ERROR, &optval, &optlen) == 0) { DEBUG_PRINTF("optval=%d optlen=%d\n", optval, optlen); if (optval == 0) { socket_fd_fail_close_flag = false; } } } } if (socket_fd_fail_close_flag) { close(socket_fd); return -1; } return socket_fd; } #pragma GCC diagnostic pop void freeInternalAddrinfo() { if (internal_addrinfo_) { DEBUG_PRINTF("freeInternalAddrinfo() %p\n", internal_addrinfo_); freeaddrinfo(internal_addrinfo_); internal_addrinfo_ = 0; } } private: static sigjmp_buf jump_buffer_; #if defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) SSL_CTX *ssl_ctx_; SSL *ssl_; #endif // defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) int getaddrinfo_result_; struct addrinfo *internal_addrinfo_; }; } #endif // SKK_SOCKET_HPP yaskkserv-1.1.0/source/skk/architecture/bsd_cygwin_linux_gcc/skk_syslog.cpp000066400000000000000000000024711262716711600274010ustar00rootroot00000000000000/* Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012, 2013, 2014 Tadashi Watanabe This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "skk_syslog.hpp" namespace YaSkkServ { #ifdef YASKKSERV_CONFIG_ENABLE_SYSLOG void SkkSyslog::printf(int log_level, Level level, const char *p, ...) { if (log_level <= log_level_) { va_list ap; va_start(ap, p); vsyslog(static_cast(level), p, ap); va_end(ap); } } #else // YASKKSERV_CONFIG_ENABLE_SYSLOG void SkkSyslog::printf(int log_level, Level level, const char *p, ...) { } #endif // YASKKSERV_CONFIG_ENABLE_SYSLOG } yaskkserv-1.1.0/source/skk/architecture/bsd_cygwin_linux_gcc/skk_syslog.hpp000066400000000000000000000046071262716711600274110ustar00rootroot00000000000000/* Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012, 2013, 2014 Tadashi Watanabe This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef SKK_SYSLOG_HPP #define SKK_SYSLOG_HPP #include "skk_gcc.hpp" namespace YaSkkServ { /* int log_level --log-level ˤɽѡ enum Level syslog(3) Υ٥Ǥ뤳ȤդɬפǤ */ class SkkSyslog { SkkSyslog(SkkSyslog &source); SkkSyslog& operator=(SkkSyslog &source); public: enum Level { LEVEL_EMERG = LOG_EMERG, // LEVEL_ALART = LOG_ALART, LEVEL_CRIT = LOG_CRIT, LEVEL_ERR = LOG_ERR, LEVEL_WARNING = LOG_WARNING, LEVEL_NOTICE = LOG_NOTICE, LEVEL_INFO = LOG_INFO, LEVEL_DEBUG = LOG_DEBUG }; virtual ~SkkSyslog() { #ifdef YASKKSERV_CONFIG_ENABLE_SYSLOG closelog(); #endif // YASKKSERV_CONFIG_ENABLE_SYSLOG } #ifdef YASKKSERV_CONFIG_ENABLE_SYSLOG SkkSyslog(const char *identifier, int log_level) : log_level_(log_level) { openlog(identifier, LOG_PID, LOG_DAEMON); } #else // YASKKSERV_CONFIG_ENABLE_SYSLOG SkkSyslog(const char *identifier, int log_level) { } #endif // YASKKSERV_CONFIG_ENABLE_SYSLOG void setLogLevel(int log_level) { #ifdef YASKKSERV_CONFIG_ENABLE_SYSLOG log_level_ = log_level; #endif // YASKKSERV_CONFIG_ENABLE_SYSLOG } void printf(int log_level, Level level, const char *p, ...); private: #ifdef YASKKSERV_CONFIG_ENABLE_SYSLOG int log_level_; #endif // YASKKSERV_CONFIG_ENABLE_SYSLOG }; } #endif // SKK_SYSLOG_HPP yaskkserv-1.1.0/source/skk/architecture/bsd_cygwin_linux_gcc/skk_utility_architecture.cpp000066400000000000000000000024141262716711600323230ustar00rootroot00000000000000/* Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012, 2013, 2014 Tadashi Watanabe This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "skk_utility_architecture.hpp" namespace YaSkkServ { namespace SkkUtility { #ifdef YASKKSERV_CONFIG_ENABLE_ERROR_MESSAGE void printf(const char *p, ...) { va_list ap; va_start(ap, p); vfprintf(stderr, p, ap); va_end(ap); } #else // YASKKSERV_CONFIG_ENABLE_ERROR_MESSAGE void printf(const char *p, ...) { } #endif // YASKKSERV_CONFIG_ENABLE_ERROR_MESSAGE } } yaskkserv-1.1.0/source/skk/architecture/bsd_cygwin_linux_gcc/skk_utility_architecture.hpp000066400000000000000000000100461262716711600323300ustar00rootroot00000000000000/* Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012, 2013, 2014 Tadashi Watanabe This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef SKK_UTILITY_ARCHITECTURE_HPP #define SKK_UTILITY_ARCHITECTURE_HPP #include "skk_gcc.hpp" namespace YaSkkServ { namespace SkkUtility { void printf(const char *p, ...); inline int chmod(const char *path, mode_t mode) { return ::chmod(path, mode); } inline void sleep(int second) { ::sleep(static_cast(second)); } class DictionaryPermission { public: DictionaryPermission(const char *filename) : filename_(filename), stat_(), stat_result_(stat(filename_, &stat_)), euid_(geteuid()) { } bool isExist() const { if (stat_result_ == -1) { return false; } return true; } // 真ならば正しいパーミッションです。偽ならばメッセージも表示します。 bool checkAndPrintPermission() const { DEBUG_ASSERT(isExist()); if ((stat_.st_uid == 0) || (stat_.st_uid == euid_)) { if (stat_.st_mode & 0022) { SkkUtility::printf("illegal permission 0%o \"%s\"\n" "Try chmod go-w %s\n" , stat_.st_mode & 0777, filename_, filename_); return false; } } else { SkkUtility::printf("illegal owner \"%s\"\n" "file owner must be root or same euid\n" , filename_); return false; } return true; } private: const char *filename_; struct stat stat_; int stat_result_; uid_t euid_; }; class WaitAndCheckForGoogleJapaneseInput { public: WaitAndCheckForGoogleJapaneseInput() : time_start_() { gettimeofday(&time_start_, 0); } // 偽ならばタイムアウトです。 bool waitAndCheckLoopHead(float timeout) { // send の直後なので、ちょっと待つ。 usleep(10 * 1000); // 余計な仕事もこのあたりで。 struct timeval time_current; gettimeofday(&time_current, 0); unsigned long long usec_start = static_cast(time_start_.tv_sec * 1000 * 1000 + time_start_.tv_usec); unsigned long long usec_current = static_cast(time_current.tv_sec * 1000 * 1000 + time_current.tv_usec); if (usec_current - usec_start >= static_cast(timeout * 1000.0f * 1000.0f)) { return false; } return true; } private: struct timeval time_start_; }; } } #endif // SKK_UTILITY_ARCHITECTURE_HPP yaskkserv-1.1.0/source/skk/architecture/skk_architecture.hpp000066400000000000000000000020061262716711600243570ustar00rootroot00000000000000/* Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012, 2013, 2014 Tadashi Watanabe This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef SKK_ARCHITECTURE_HPP #define SKK_ARCHITECTURE_HPP #ifdef YASKKSERV_ARCHITECTURE_BSD_CYGWIN_LINUX_GCC #include "skk_gcc.hpp" #endif // YASKKSERV_ARCHITECTURE_BSD_CYGWIN_LINUX_GCC #endif // SKK_ARCHITECTURE_HPP yaskkserv-1.1.0/source/skk/skk_command_line.hpp000066400000000000000000000550341262716711600216510ustar00rootroot00000000000000/* Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012, 2013, 2014 Tadashi Watanabe This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef SKK_COMMAND_LINE_HPP #define SKK_COMMAND_LINE_HPP #include "skk_architecture.hpp" namespace YaSkkServ { // /** * * դ * * "option argument" ϥץΰ * * "argument" ϥץʳΰ(˥ե̾) * * * ʲΤ褦ʷбƤޤ * * ./a.out [options] [argument] * * ./a.out -a optarg --alpha=optarg argument * * ./a.out -- -a b --alpha=beta gamma (-- ʹߤ argument) */ class SkkCommandLine { SkkCommandLine(SkkCommandLine &source); SkkCommandLine& operator=(SkkCommandLine &source); public: enum OptionArgument { OPTION_ARGUMENT_TERMINATOR, OPTION_ARGUMENT_NONE, OPTION_ARGUMENT_INTEGER, OPTION_ARGUMENT_FLOAT, OPTION_ARGUMENT_STRING }; struct Option { const char *option_short; const char *option_long; OptionArgument option_argument; }; virtual ~SkkCommandLine() { delete[] option_result_; } SkkCommandLine() : argv_(0), option_table_(0), option_result_(0), error_string_("no error."), option_table_length_(0), argc_(0), argument_index_(0), argument_length_(0), parse_flag_(false) { } bool parse(int argc, const char * const argv[], const Option *option_table) { argc_ = argc; argv_ = argv; option_table_ = option_table; for (int i = 0;; ++i) { if ((option_table + i)->option_argument == OPTION_ARGUMENT_TERMINATOR) { option_table_length_ = i; break; } } if (option_table_length_ > 0) { if (option_result_) { delete[] option_result_; } option_result_ = new OptionResult[option_table_length_]; int option_check_length = argc_; // check "--" (force argument) for (int i = 1; i != argc_; ++i) { const char *p = *(argv_ + i); if ((*(p + 0) == '-') && (*(p + 1) == '-') && (*(p + 2) == '\0')) { argument_index_ = i + 1; argument_length_ = argc_ - argument_index_; DEBUG_PRINTF("argument_index_=%d argument_length_=%d\n", argument_index_, argument_length_); option_check_length = i; break; } } if (!parse_loop(option_check_length)) { return false; } else { if (argument_index_ != 0) { for (int i = 0; i != argument_length_; ++i) { DEBUG_PRINTF("argument? %d/%d %s\n", i, argument_length_, *(argv_ + argument_index_ + i)); } } return true; } } else { error_string_ = "internal error."; return false; } } int getArgumentArgvIndex() const { return argument_index_; } int getArgumentLength() const { return argument_length_; } bool isArgumentDefined(int n) const { if (n >= argument_length_) { DEBUG_ASSERT(0); return false; } else { return true; } } const char *getArgumentPointer(int n) const { if (n >= argument_length_) { DEBUG_ASSERT(0); return 0; } else { return *(argv_ + argument_index_ + n); } } bool isOptionDefined(int n) const { if (n >= option_table_length_) { DEBUG_ASSERT(0); return false; } else { return (option_result_ + n)->enable_flag; } } const char *getOptionArgumentPointer(int n) const { if (n >= option_table_length_) { DEBUG_ASSERT(0); return 0; } else { return (option_result_ + n)->argument; } } const char *getOptionArgumentString(int n) const { const char *p = getOptionArgumentPointer(n); if (p) { if ((option_table_ + n)->option_argument != OPTION_ARGUMENT_STRING) { DEBUG_ASSERT(0); return 0; } } return p; } int getOptionArgumentInteger(int n) const { const char *p = getOptionArgumentPointer(n); if (p) { if ((option_table_ + n)->option_argument != OPTION_ARGUMENT_INTEGER) { DEBUG_ASSERT(0); return 0; } } int result; if (!SkkUtility::getInteger(p, result)) { DEBUG_ASSERT(0); } return result; } float getOptionArgumentFloat(int n) const { const char *p = getOptionArgumentPointer(n); if (p) { if ((option_table_ + n)->option_argument != OPTION_ARGUMENT_FLOAT) { DEBUG_ASSERT(0); return 0; } } float result; if (!SkkUtility::getFloat(p, result)) { DEBUG_ASSERT(0); } return result; } const char *getErrorString() const { return error_string_; } private: static bool is_option(const char *p) { if (*(p + 0) == '-') { return true; } else { return false; } } static bool is_long_option(const char *p) { if ((*(p + 0) == '-') && (*(p + 1) == '-')) { return true; } else { return false; } } static const char *get_equal_pointer(const char *p) { for (;;) { char c = *p; if (c == '\0') { return 0; } if (c == '=') { return p; } ++p; } } static bool is_integer(const char *p) { int dummy_result; return SkkUtility::getInteger(p, dummy_result); } static bool is_float(const char *p) { float dummy_result; return SkkUtility::getFloat(p, dummy_result); } /// '=' or '\0' ǽüʸӤƱʤп֤ޤ static bool compare_option_string(const char *a, const char *b) { for (int i = 0; ;++i) { if ((*(a + i) == '\0') || (*(a + i) == '=')) { if ((*(b + i) == '\0') || (*(b + i) == '=')) { return true; } else { return false; } } if (*(a + i) != *(b + i)) { return false; } } } /// option option_table_ ˴ޤޤ뤫Ĵ١ޤޤƤп֤ξꤷޤ bool search_option_table(const char *option, int &result_option_table_index, bool &result_long_flag) const { if (is_option(option)) { bool long_flag = is_long_option(option); const char *p; if (long_flag) { p = option + 2; // skip "--" } else { p = option + 1; // skip "-" } if (long_flag) { for (int i = 0; (option_table_ + i)->option_argument != OPTION_ARGUMENT_TERMINATOR; ++i) { if ((option_table_ + i)->option_long && compare_option_string(p, (option_table_ + i)->option_long)) { result_option_table_index = i; result_long_flag = long_flag; return true; } } } else { for (int i = 0; (option_table_ + i)->option_argument != OPTION_ARGUMENT_TERMINATOR; ++i) { if ((option_table_ + i)->option_short && compare_option_string(p, (option_table_ + i)->option_short)) { result_option_table_index = i; result_long_flag = long_flag; return true; } } } } return false; } bool parse_loop(int option_check_length) { enum State { STATE_OPTION, STATE_OPTION_ARGUMENT }; State state = STATE_OPTION; int option_table_index = -1; error_string_ = "no error."; for (int i = 1; i != option_check_length; ++i) { DEBUG_PRINTF("option? %d/%d %s\n", i, option_check_length, *(argv_ + i)); switch (state) { default: DEBUG_ASSERT(0); error_string_ = "internal error."; return false; case STATE_OPTION: DEBUG_PRINTF(" state_option\n"); { bool long_flag; if (search_option_table(*(argv_ + i), option_table_index, long_flag)) { DEBUG_PRINTF(" search_option_table() found.\n"); switch ((option_table_ + option_table_index)->option_argument) { case OPTION_ARGUMENT_TERMINATOR: // FALLTHROUGH default: DEBUG_ASSERT(0); error_string_ = "internal error."; return false; case OPTION_ARGUMENT_NONE: { const char *p = get_equal_pointer(*(argv_ + i)); if (p) { error_string_ = p; return false; } } (option_result_ + option_table_index)->enable_flag = true; break; case OPTION_ARGUMENT_INTEGER: case OPTION_ARGUMENT_FLOAT: case OPTION_ARGUMENT_STRING: { const char *p = get_equal_pointer(*(argv_ + i)); if (p) { // --foo=ARGUMENT // || // p __/ \__ p + 1 if (*(p + 1) == '\0') { error_string_ = p; return false; } if ((option_table_ + option_table_index)->option_argument == OPTION_ARGUMENT_INTEGER) { if (!is_integer(p + 1)) { error_string_ = p; return false; } } if ((option_table_ + option_table_index)->option_argument == OPTION_ARGUMENT_FLOAT) { if (!is_float(p + 1)) { error_string_ = p; return false; } } (option_result_ + option_table_index)->argument = p + 1; (option_result_ + option_table_index)->long_flag = long_flag; (option_result_ + option_table_index)->enable_flag = true; } else { (option_result_ + option_table_index)->long_flag = long_flag; state = STATE_OPTION_ARGUMENT; } } break; } } else { DEBUG_PRINTF(" search_option_table() NOT FOUND.\n"); if (is_option(*(argv_ + i))) { error_string_ = *(argv_ + i); return false; } else { argument_index_ = i; argument_length_ = argc_ - argument_index_; return true; } } } break; case STATE_OPTION_ARGUMENT: DEBUG_PRINTF(" state_option_argument\n"); if (option_table_index < 0) { error_string_ = "internal error."; return false; } if ((option_table_ + option_table_index)->option_argument == OPTION_ARGUMENT_INTEGER) { if (!is_integer(*(argv_ + i))) { error_string_ = *(argv_ + i); return false; } } if ((option_table_ + option_table_index)->option_argument == OPTION_ARGUMENT_FLOAT) { if (!is_float(*(argv_ + i))) { error_string_ = *(argv_ + i); return false; } } (option_result_ + option_table_index)->argument = *(argv_ + i); (option_result_ + option_table_index)->enable_flag = true; state = STATE_OPTION; break; } } return true; } private: struct OptionResult { OptionResult(OptionResult &source); OptionResult& operator=(OptionResult &source); OptionResult () : argument(0), enable_flag(false), long_flag(false) { } const char *argument; bool enable_flag; bool long_flag; }; const char * const *argv_; const Option *option_table_; OptionResult *option_result_; const char *error_string_; int option_table_length_; int argc_; int argument_index_; int argument_length_; bool parse_flag_; }; } #endif // SKK_COMMAND_LINE_HPP yaskkserv-1.1.0/source/skk/skk_dictionary.hpp000066400000000000000000000636601262716711600213750ustar00rootroot00000000000000/* Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012, 2013, 2014 Tadashi Watanabe This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef SKK_DICTIONARY_H #define SKK_DICTIONARY_H #include "skk_jisyo.hpp" namespace YaSkkServ { /// yaskkserv Ѽ񥯥饹Ǥ /** * */ class SkkDictionary { SkkDictionary(SkkDictionary &source); SkkDictionary& operator=(SkkDictionary &source); public: virtual ~SkkDictionary() { close(); } SkkDictionary() : mtime_(), // ʲΥФ close() ǤɬפʤȤդɬפǤ read_buffer_(0), index_(0), fixed_array_(0), block_(0), block_short_(0), string_(0), midasi_(0), henkanmojiretsu_(0), file_descriptor_(-1), before_read_offset_(-1), index_size_(0), normal_block_length_(0), special_block_length_(0), normal_string_size_(0), special_entry_offset_(0), midasi_size_(0), henkanmojiretsu_size_(0), block_size_(0), last_read_offset_start_(0), last_read_index_(0), last_start_block_(0), last_block_length_(0), last_block_index_(0), last_search_result_(false) { } bool open(const char *filename) { return open_system_call(filename); } bool close() { return close_system_call(); } /// п֤ޤ񤬹Ƥ update_flag ˿֤ޤ˼Ԥ update_flag ˿ޤ /** * åץǡȥåˤϡ * * ּե˼¹Ԥ줿þ * * Ȥ礭꤬뤳ȤդɬפǤ */ bool isUpdateDictionary(bool &update_flag, const char *filename) { bool result; struct stat stat_work; if (stat(filename, &stat_work) == -1) { result = false; } else { result = true; if (mtime_ != stat_work.st_mtime) { mtime_ = stat_work.st_mtime; update_flag = true; } else { update_flag = false; } } return result; } /// midasi ǻꤷȥõޤդп֤ޤ bool search(const char *midasi) { last_search_result_ = search_system_call(midasi); return last_search_result_; } /// midasi ǻꤷʸ 1 ʸܤбǽΥȥõޤդп֤ޤ bool searchForFirstCharacter(const char *midasi) { last_search_result_ = search_system_call(midasi); return last_search_result_; } /// Υȥõޤդп֤ޤ bool searchNextEntry() { last_search_result_ = search_next_entry_system_call(); return last_search_result_; } /// search() ޤ searchNextEntry() Ƥ뤫ɤ֤ޤƤп֤ޤ bool isSuccess() const { return last_search_result_; } /// search() ޤ searchNextEntry() ǺǸȯָФפΥ֤ޤ˲ʸϴޤߤޤ int getMidasiSize() const { return midasi_size_; } /// search() ޤ searchNextEntry() ǺǸȯָФפΥݥ󥿤֤ޤ const char *getMidasiPointer() const { return midasi_; } /// search() ޤ searchNextEntry() ǺǸȯѴʸפΥ֤ޤ˲ʸϴޤߤޤ int getHenkanmojiretsuSize() const { return henkanmojiretsu_size_; } /// search() ޤ searchNextEntry() ǺǸȯѴʸפΥݥ󥿤֤ޤ const char *getHenkanmojiretsuPointer() const { return henkanmojiretsu_; } private: template bool search_system_call(const char *midasi) { DEBUG_ASSERT_POINTER(midasi); const int margin = 8; char encoded_midasi[SkkUtility::ENCODED_MIDASI_BUFFER_SIZE]; int encoded_size = SkkUtility::encodeHiragana(midasi, encoded_midasi, sizeof(encoded_midasi) - margin); if (encoded_size == 0) { encoded_midasi[0] = '\1'; int i; for (i = 0; sizeof(encoded_midasi) - margin; ++i) { if ((*(midasi + i) == ' ') || (*(midasi + i) == '\0')) { goto FOUND_TERMINATOR; } encoded_midasi[i + 1] = *(midasi + i); } return false; FOUND_TERMINATOR: encoded_midasi[i + 1] = '\0'; } else { encoded_midasi[encoded_size] = '\0'; } int fixed_array_index = SkkUtility::getFixedArrayIndex(encoded_midasi); DEBUG_ASSERT_RANGE(fixed_array_index, -1, 0xff); int start_block; int block_length; int read_offset_start; const char *string; if (fixed_array_index == -1) { // special start_block = normal_block_length_; block_length = special_block_length_; read_offset_start = special_entry_offset_; string = string_ + normal_string_size_; } else { // normal start_block = (fixed_array_ + fixed_array_index)->start_block; block_length = (fixed_array_ + fixed_array_index)->block_length; read_offset_start = 0; string = string_ + (fixed_array_ + fixed_array_index)->string_data_offset; } for (int i = 0; i != block_length; ++i) { int cmp = SkkUtility::compareMidasi(string, 0, 510, encoded_midasi); if (cmp >= 0) { int read_size; int read_offset; if (block_) { read_size = (block_ + start_block + i)->getDataSize(); read_offset = read_offset_start + (block_ + start_block + i)->getOffset(); } else { read_size = (block_short_ + start_block + i)->getDataSize(); read_offset = (start_block + i) * block_size_; } if (before_read_offset_ == read_offset) { // cached } else { if (lseek(file_descriptor_, read_offset, SEEK_SET) == -1) { DEBUG_PRINTF("#### FAILED lseek() ERROR!!\n"); return false; } int read_result = static_cast(read(file_descriptor_, read_buffer_, static_cast(read_size))); if (read_result != read_size) { DEBUG_PRINTF("#### FAILED read() ERROR!! read_size = %d read_result = %d\n", read_size, read_result); return false; } before_read_offset_ = read_offset; last_read_index_ = 0; } if (is_first) { int index = 0; midasi_ = read_buffer_ + index; midasi_size_ = SkkUtility::getMidasiSize(read_buffer_, index, read_size); henkanmojiretsu_ = SkkUtility::getHenkanmojiretsuPointer(read_buffer_, index, read_size); henkanmojiretsu_size_ = SkkUtility::getHenkanmojiretsuSize(read_buffer_, index, read_size); last_read_offset_start_ = read_offset_start; last_read_index_ = index; last_start_block_ = start_block; last_block_length_ = block_length; last_block_index_ = i; return true; } else { int index; if (SkkUtility::searchBinary(read_buffer_, read_size, encoded_midasi, index)) { DEBUG_ASSERT(index >= 0); midasi_ = read_buffer_ + index; midasi_size_ = SkkUtility::getMidasiSize(read_buffer_, index, read_size); henkanmojiretsu_ = SkkUtility::getHenkanmojiretsuPointer(read_buffer_, index, read_size); henkanmojiretsu_size_ = SkkUtility::getHenkanmojiretsuSize(read_buffer_, index, read_size); last_read_offset_start_ = read_offset_start; last_read_index_ = index; last_start_block_ = start_block; last_block_length_ = block_length; last_block_index_ = i; return true; } if (SkkUtility::searchLinear(read_buffer_, read_size, encoded_midasi, index)) { DEBUG_ASSERT(index >= 0); midasi_ = read_buffer_ + index; midasi_size_ = SkkUtility::getMidasiSize(read_buffer_, index, read_size); henkanmojiretsu_ = SkkUtility::getHenkanmojiretsuPointer(read_buffer_, index, read_size); henkanmojiretsu_size_ = SkkUtility::getHenkanmojiretsuSize(read_buffer_, index, read_size); last_read_offset_start_ = read_offset_start; last_read_index_ = index; last_start_block_ = start_block; last_block_length_ = block_length; last_block_index_ = i; return true; } return false; } } string = skip_space(string); } return false; } bool search_next_entry_system_call() { if ((!last_search_result_) || (last_block_index_ >= last_block_length_)) { return false; } int read_size; int read_offset; if (block_) { read_size = (block_ + last_start_block_ + last_block_index_)->getDataSize(); read_offset = last_read_offset_start_ + (block_ + last_start_block_ + last_block_index_)->getOffset(); } else { read_size = (block_short_ + last_start_block_ + last_block_index_)->getDataSize(); read_offset = (last_start_block_ + last_block_index_) * block_size_; } last_read_index_ = SkkUtility::getNextLineIndex(read_buffer_, last_read_index_, read_size); if (last_read_index_ < 0) { ++last_block_index_; if (last_block_index_ >= last_block_length_) { return false; } if (block_) { read_size = (block_ + last_start_block_ + last_block_index_)->getDataSize(); read_offset = last_read_offset_start_ + (block_ + last_start_block_ + last_block_index_)->getOffset(); } else { read_size = (block_short_ + last_start_block_ + last_block_index_)->getDataSize(); read_offset = (last_start_block_ + last_block_index_) * block_size_; } if (lseek(file_descriptor_, read_offset, SEEK_SET) == -1) { DEBUG_PRINTF("#### FAILED lseek() ERROR!!\n"); return false; } int read_result = static_cast(read(file_descriptor_, read_buffer_, static_cast(read_size))); if (read_result != read_size) { DEBUG_PRINTF("#### FAILED read() ERROR!! read_size = %d read_result = %d\n", read_size, read_result); return false; } before_read_offset_ = read_offset; last_read_index_ = 0; } midasi_ = read_buffer_ + last_read_index_; midasi_size_ = SkkUtility::getMidasiSize(read_buffer_, last_read_index_, read_size); henkanmojiretsu_ = SkkUtility::getHenkanmojiretsuPointer(read_buffer_, last_read_index_, read_size); henkanmojiretsu_size_ = SkkUtility::getHenkanmojiretsuSize(read_buffer_, last_read_index_, read_size); return true; } bool open_system_call(const char *filename) { bool result; file_descriptor_ = ::open(filename, O_RDONLY); if (file_descriptor_ == -1) { result = false; } else { SkkJisyo::Information information; struct stat stat; if (fstat(file_descriptor_, &stat) == -1) { result = false; } else { result = true; mtime_ = stat.st_mtime; } { off_t lseek_offset = sizeof(information); if (result && (lseek(file_descriptor_, -lseek_offset, SEEK_END) == -1)) { result = false; } else { result = true; } } if (result && (read(file_descriptor_, &information, sizeof(information)) == -1)) { result = false; } if (result) { if (information.get(SkkJisyo::Information::ID_IDENTIFIER) != SkkJisyo::IDENTIFIER) { result = false; } } if (result) { const int size_limit_minimum = 1 * 1024; const int size_limit_maximum = 256 * 1024; int index_data_offset = information.get(SkkJisyo::Information::ID_INDEX_DATA_OFFSET); int index_data_size = information.get(SkkJisyo::Information::ID_INDEX_DATA_SIZE); if ((index_data_offset <= 0) || (index_data_size <= size_limit_minimum) || (index_data_size >= size_limit_maximum)) { result = false; } if (result) { if (lseek(file_descriptor_, index_data_offset, SEEK_SET) == -1) { result = false; } } if (result) { index_ = new char[index_data_size]; if (read(file_descriptor_, index_, static_cast(index_data_size)) != index_data_size) { result = false; } else { SkkJisyo::IndexDataHeader index_data_header; index_data_header.initialize(index_); index_size_ = index_data_size; const int block_size_limit_minimum = 32; const int block_size_limit_maximum = 256 * 1024; block_size_ = index_data_header.get(SkkJisyo::IndexDataHeader::ID_BLOCK_SIZE); if ((block_size_ < block_size_limit_minimum) || (block_size_ > block_size_limit_maximum)) { result = false; } else { const int margin = 32; read_buffer_ = new char[block_size_ + margin]; normal_block_length_ = index_data_header.get(SkkJisyo::IndexDataHeader::ID_NORMAL_BLOCK_LENGTH); special_block_length_ = index_data_header.get(SkkJisyo::IndexDataHeader::ID_SPECIAL_BLOCK_LENGTH); normal_string_size_ = index_data_header.get(SkkJisyo::IndexDataHeader::ID_NORMAL_STRING_SIZE); special_entry_offset_ = index_data_header.get(SkkJisyo::IndexDataHeader::ID_SPECIAL_ENTRY_OFFSET); int index_data_string_offset = 0; index_data_string_offset += normal_block_length_; index_data_string_offset += special_block_length_; fixed_array_ = reinterpret_cast(index_ + SkkJisyo::IndexDataHeader::getSize()); if (index_data_header.get(SkkJisyo::IndexDataHeader::ID_BIT_FLAG) & SkkJisyo::IndexDataHeader::BIT_FLAG_BLOCK_SHORT) { block_ = 0; block_short_ = reinterpret_cast(index_ + SkkJisyo::IndexDataHeader::getSize() + sizeof(SkkJisyo::FixedArray) * 256); index_data_string_offset *= static_cast(sizeof(SkkJisyo::BlockShort)); } else { block_ = reinterpret_cast(index_ + SkkJisyo::IndexDataHeader::getSize() + sizeof(SkkJisyo::FixedArray) * 256); block_short_ = 0; index_data_string_offset *= static_cast(sizeof(SkkJisyo::Block)); } string_ = index_ + SkkJisyo::IndexDataHeader::getSize() + sizeof(SkkJisyo::FixedArray) * 256 + index_data_string_offset; } } } } } return result; } bool close_system_call() { delete[] read_buffer_; if (file_descriptor_ >= 0) { ::close(file_descriptor_); } delete[] index_; read_buffer_ = 0; index_ = 0; fixed_array_ = 0; block_ = 0; block_short_ = 0; string_ = 0; midasi_ = 0; henkanmojiretsu_ = 0; file_descriptor_ = -1; before_read_offset_ = -1; index_size_ = 0; normal_block_length_ = 0; special_block_length_ = 0; normal_string_size_ = 0; special_entry_offset_ = 0; midasi_size_ = 0; henkanmojiretsu_size_ = 0; block_size_ = 0; last_read_offset_start_ = 0; last_read_index_ = 0; last_start_block_ = 0; last_block_length_ = 0; last_block_index_ = 0; last_search_result_ = false; return true; } /// 1 ԸιƬؤΥݥ󥿤֤ޤ static const char *get_next_line(const char *p) { return SkkUtility::getNextPointer<'\n'>(p); } static const char *skip_space(const char *p) { return SkkUtility::getNextPointer<' '>(p); } private: time_t mtime_; char *read_buffer_; char *index_; SkkJisyo::FixedArray *fixed_array_; SkkJisyo::Block *block_; SkkJisyo::BlockShort *block_short_; char *string_; const char *midasi_; const char *henkanmojiretsu_; int file_descriptor_; int before_read_offset_; int index_size_; int normal_block_length_; int special_block_length_; int normal_string_size_; int special_entry_offset_; int midasi_size_; int henkanmojiretsu_size_; int block_size_; int last_read_offset_start_; int last_read_index_; int last_start_block_; int last_block_length_; int last_block_index_; bool last_search_result_; }; } #endif // SKK_DICTIONARY_H yaskkserv-1.1.0/source/skk/skk_jisyo.hpp000066400000000000000000004053761262716711600203710ustar00rootroot00000000000000/* Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012, 2013, 2014 Tadashi Watanabe This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef SKK_JISYO_H #define SKK_JISYO_H #include "skk_architecture.hpp" #include "skk_utility.hpp" #include "skk_mmap.hpp" namespace YaSkkServ { /// SKK 򰷤饹Ǥ /** * * \section memo * * ᥽åɤǤϥХåե󥰤ˤ®Ԥ뤿 I/O * cstdio ѤޤФФ륨ȥ Search() ᥽ * ɤǤϥХåե󥰤ɬפʤΤ mmap Ѥޤ * * ʾΤ褦ˡܥ饹ǤϽʥ꥽׵ᤷޤ * * * \section aboutdictionary ˤĤ * * yaskkserv Ǥϼ SKK μ񤫤ѷѴƻѤޤ * Ū 2 ʳޤ̤˥桼 1 ʳܤμ˿ * ȤϤޤ * * 1 ʳ * * \li class SkkJisyo * * \li createDictionaryForClassSkkJisyo() Ѥ * * 2 ʳ * * \li class SkkDictionary * * \li createDictionaryForClassSkkDictionary() Ѥ * * * ѴƤϰʲ̤Ǥ * * \li ȤƼ * * \li ָФפϡ֤Ҥ餬ʥ󥳡ɡפ * * \li ̾泌ȥפȡü쥨ȥפʬ * * \li 줾ꤢפȡʤפ򺮤֤Ǿ祽Ȥ * * \li 2 ʳܤǤϥǥåǡղä * * \li ˼󤬥Хʥղä * * \subsection special ü쥨ȥ * * Ƭʸ֤Ҥ餬(0xa4)פޤϡASCII(0x21-0x7e)פǤʤʸ * ü쥨ȥȤưޤ * * * \seciton structure ι¤ * * \verbatim +---------------+------------------------------------+ <-- SEEK_TOP (STATE_NORMAL) | | normal | | | ̾泌ȥ | | | (祽ȡ¸ߤʤ⤢) | <-- SEEK_BOTTOM (STATE_NORMAL) | dictionary +------------------------------------+ <-- SEEK_TOP (STATE_SPECIAL) | | special | | | ü쥨ȥ | | | (祽ȡ¸ߤʤ⤢) | <-- SEEK_BOTTOM (STATE_SPECIAL) +---------------+------------------------------------+ | | terminator and alignment | | index data | 1 - 4 ХȤ 0 ߥ͡ΰ | | +------------------------------------+ <-- ǥåǡեå | (1 ʳܤǤ | struct IndexDataHeader | | ¸ߤʤ) | + | | | index data ǥåǡ | +---------------+------------------------------------+ | | terminator and alignment | | | 1 - 4 ХȤ 0 ߥ͡ΰ | | information +------------------------------------+ <--- ե륵 - sizeof(Information) | | | | | struct Information | | | | +---------------+------------------------------------+ \endverbatim * * \subsection information * * \verbatim struct Information object[0] : ӥåȥե饰 object[1] : ꥶ object[2] : ꥶ object[3] : ꥶ object[4] : ꥶ object[5] : ꥶ object[6] : ǥåǡؤΥեå object[7] : ǥåǡ object[8] : special Կ object[9] : special object[10] : normal Կ object[11] : normal object[12] : ֥å饤ȥ object[13] : С object[14] : object object[15] : identifier \endverbatim * * \section aboutdictionaryindex ǥåǡˤĤ * * ǥåǡϰʲǤ鹽ޤ(Ϳͤ 2005ǯ10 * 12 () SKK-JISYO.total+zipcode ͤǤ) * * \li struct FixedArray θĹ (256 ) * * \li struct Block/BlockShort βĹ (block_size/length : 4k/3564, 8k/1840, 16k/971) * * \li ʸǼΰ (block_size/length : 4k/28k, 8k/14k, 16k/8k) * * Block/BlockShort βĹʸǼΰϡ̾泌ȥü * ȥǶѤޤü쥨ȥΤΤ̾泌ȥθɲä * ޤ FixedArray ̾泌ȥѤޤ * * \verbatim +----------------------------------------------------+ | | | struct IndexDataHeader | | | | header[0] : ӥåȥե饰 | | header[1] : header | | header[2] : ֥å | | header[3] : normal_block_length | | header[4] : special_block_length | | header[5] : normal_string_length | | header[6] : special_string_length | | header[7] : ü쥨ȥؤΥեå | | | +----------------------------------------------------+ | | | FixedArray fixed_array[256] | | | | ̾泌ȥõҥȾǤ | | | +----------------------------------------------------+ | | | Block block[block_length] | | BlockShort block[block_length] | | | | ֥åݻޤ | | 饤Ȥ줿Ǥ BlockShort | | Ѥ뤳Ȥǥ 1/4 ˤ뤳Ȥ | | Ǥޤ | | | +----------------------------------------------------+ | | | char string[string_length] | | | | ĹʸǤüɤȤƥڡ | | ѤޤĤޤ "AA BBB CCCC DDDDD " | | äʸˤʤޤ | | | | ʸ block Ʊ(block_length ) | | ¸ߤޤ | | | | ʸб֥åκǸθФ | | Ǥˤ֥åõʸ | | ¸ߤ뤫ɤĴ٤ޤ | | | +----------------------------------------------------+ \endverbatim * */ class SkkJisyo { SkkJisyo(SkkJisyo &source); SkkJisyo& operator=(SkkJisyo &source); public: enum State { STATE_NORMAL, STATE_SPECIAL, STATE_LENGTH }; enum JisyoType { JISYO_TYPE_UNKNOWN, JISYO_TYPE_SKK_RAW, JISYO_TYPE_CLASS_SKK_JISYO, JISYO_TYPE_CLASS_SKK_DICTIONARY }; enum SeekPosition { SEEK_POSITION_TOP, SEEK_POSITION_BOTTOM, SEEK_POSITION_NEXT, SEEK_POSITION_PREVIOUS, SEEK_POSITION_BEGINNING_OF_LINE }; enum { IDENTIFIER = 0x7fedc000 }; /// array[0] Ͼ˥ӥåȥե饰򼨤ȤդɬפǤ template struct ArrayInt32 { enum { BIT_FLAG_BYTE_ORDER_VAX = 0x1 << 0, }; static int getSize() { return sizeof(int32_t) * N; } ArrayInt32(int bit_flag = BIT_FLAG_BYTE_ORDER_VAX) { array[0] = bit_flag; for (int i = 1; i != N; ++i) { array[i] = 0; } } bool initialize(const void *p) { DEBUG_ASSERT_POINTER(p); DEBUG_ASSERT_POINTER_ALIGN(p, 4); const int32_t *tmp = reinterpret_cast(p); for (int i = 0; i != N; ++i) { array[i] = *tmp++; } return true; } int32_t getSwap(int index) const { return static_cast((static_cast(array[index] << 24) & 0xff000000UL) | (static_cast(array[index] << 8) & 0x00ff0000UL) | (static_cast(array[index] >> 8) & 0x0000ff00UL) | (static_cast(array[index] >> 24) & 0x000000ffUL)); } int32_t get(int index) const { #ifdef YASKKSERV_ARCHITECTURE_BYTE_ORDER_NETWORK if (array[0] & BIT_FLAG_BYTE_ORDER_VAX) { return getSwap(index); } else { return array[index]; } #endif // YASKKSERV_ARCHITECTURE_BYTE_ORDER_NETWORK #ifdef YASKKSERV_ARCHITECTURE_BYTE_ORDER_VAX if (array[0] & BIT_FLAG_BYTE_ORDER_VAX) { return array[index]; } else { return getSwap(index); } #endif // YASKKSERV_ARCHITECTURE_BYTE_ORDER_VAX } void set(int index, int32_t scalar) { #ifdef YASKKSERV_ARCHITECTURE_BYTE_ORDER_NETWORK if (array[0] & BIT_FLAG_BYTE_ORDER_VAX) { array[index] = getSwap(index); } else { array[index] = scalar; } #endif // YASKKSERV_ARCHITECTURE_BYTE_ORDER_NETWORK #ifdef YASKKSERV_ARCHITECTURE_BYTE_ORDER_VAX if (array[0] & BIT_FLAG_BYTE_ORDER_VAX) { array[index] = scalar; } else { array[index] = getSwap(index); } #endif // YASKKSERV_ARCHITECTURE_BYTE_ORDER_VAX } int32_t array[N]; }; struct Information { enum Id { ID_BIT_FLAG, ID_RESERVE_1, ID_RESERVE_2, ID_RESERVE_3, ID_RESERVE_4, ID_RESERVE_5, ID_INDEX_DATA_OFFSET, ID_INDEX_DATA_SIZE, ID_SPECIAL_LINES, ID_SPECIAL_SIZE, ID_NORMAL_LINES, ID_NORMAL_SIZE, ID_BLOCK_ALIGNMENT_SIZE, ID_VERSION, ID_SIZE, ID_IDENTIFIER, ID_LENGTH, }; static int getSize() { return sizeof(int32_t) * ID_LENGTH; } Information(int bit_flag = ArrayInt32::BIT_FLAG_BYTE_ORDER_VAX) : object(bit_flag) { set(ID_IDENTIFIER, SkkJisyo::IDENTIFIER); set(ID_SIZE, getSize()); set(ID_VERSION, (0 * 100000) + (0 * 10000) + (0 * 1000) + (0 * 100) + (0 * 10) + (1 * 1)); } bool initialize(const void *p) { return object.initialize(p); } int32_t get(Id id) { return object.get(id); } void set(Id id, int32_t scalar) { return object.set(id, scalar); } ArrayInt32 object; }; struct IndexDataHeader { enum Id { ID_BIT_FLAG, ID_SIZE, ID_BLOCK_SIZE, ID_NORMAL_BLOCK_LENGTH, ID_SPECIAL_BLOCK_LENGTH, ID_NORMAL_STRING_SIZE, ID_SPECIAL_STRING_SIZE, ID_SPECIAL_ENTRY_OFFSET, ID_LENGTH }; enum { BIT_FLAG_BLOCK_SHORT = 0x1 << 31 }; static int getSize() { return sizeof(int32_t) * ID_LENGTH; } IndexDataHeader(int bit_flag = ArrayInt32::BIT_FLAG_BYTE_ORDER_VAX) : object(bit_flag) { set(ID_SIZE, getSize()); } bool initialize(const void *p) { return object.initialize(p); } int32_t get(Id id) { return object.get(id); } void set(Id id, int32_t scalar) { return object.set(id, scalar); } ArrayInt32 object; }; struct FixedArray { FixedArray () : start_block(0), block_length(0), string_data_offset(0) { } int16_t start_block; int16_t block_length; int32_t string_data_offset; }; struct Block { Block () : offset(0), line_length_and_data_size(0) { } int getOffset() { return offset; } void setOffset(int scalar) { offset = scalar; } int getDataSize() { return line_length_and_data_size & 0xfffff; } void setLineLengthAndDataSize(int line_length, int data_size) { line_length_and_data_size = (line_length << 20) | data_size; } int32_t offset; int32_t line_length_and_data_size; }; struct BlockShort { BlockShort () : data_size(0) { } int getDataSize() { return data_size; } void setDataSize(int size) { data_size = static_cast(size); } int16_t data_size; }; private: /// okuri_ari_index okuri_nasi_index ޤԤϵ֤ޤ static bool get_index(const char *buffer, int filesize, int &okuri_ari_index, int &okuri_nasi_index) { DEBUG_ASSERT_POINTER(buffer); for (;;) { // // okuri_ari_index okuri_nasi_index ʲΤ褦ήǵޤ // // ================ SKK ι¤ȥǥå ================== // ;; okuri-ari entries. // u /.../ // i /.../ // a /.../ ιƬ okuri_ari_index // ;; okuri-nasi entries. // /.../ ιƬ okuri_nasi_index // /.../ // /.../ // ================================================================ // // 1. ޤ ";; okuri-nasi entries.\n" 򸡺 // // 2. դä顢 1 Ծ夬ꤢꥨȥƬס // 1 ԲʤȥƬ // (SKK Ǥꤢꥨȥϵ˥ȤƤ뤳Ȥ) // // 3. 줾ƬǶԤȥȤ򥹥åפƬ // if ((*(buffer + okuri_nasi_index) == ';') && ((filesize + 1 - okuri_nasi_index) >= SkkUtility::getStringOkuriNasiLength()) && SkkUtility::isStringOkuriNasi(buffer + okuri_nasi_index)) { // get candidate index okuri_ari_index = SkkUtility::getPreviousLineIndex(buffer, okuri_nasi_index, filesize); okuri_nasi_index = SkkUtility::getNextLineIndex(buffer, okuri_nasi_index, filesize); // skip empty/comment line while (okuri_ari_index > 0) { if (*(buffer + okuri_ari_index) == '\n') { --okuri_ari_index; okuri_ari_index = SkkUtility::getBeginningOfLineIndex(buffer, okuri_ari_index, filesize); } else if (*(buffer + okuri_ari_index) == ';') { okuri_ari_index = SkkUtility::getPreviousLineIndex(buffer, okuri_ari_index, filesize); } else { break; } } while (okuri_nasi_index >= 0) { if (*(buffer + okuri_nasi_index) == '\n') { ++okuri_nasi_index; if (okuri_nasi_index >= filesize) { okuri_nasi_index = -1; } } else if (*(buffer + okuri_nasi_index) == ';') { okuri_nasi_index = SkkUtility::getNextLineIndex(buffer, okuri_nasi_index, filesize); } else { break; } } break; } okuri_nasi_index = SkkUtility::getNextLineIndex(buffer, okuri_nasi_index, filesize); if (okuri_nasi_index < 0) { return false; } } return true; } static bool append_terminator(FILE *file) { DEBUG_ASSERT_POINTER(file); // ߥ͡󥢥饤ΰ(4 bytes·) char tmp[4]; for (int i = 0; i != 4; ++i) { tmp[i] = 0; } // 1 or 2 or 3 or 4 ХȤ 0 (Ǥ 4 Хȥ饤ʤ 4 Х) long current = ftell(file); if (fwrite(tmp, 4 - (current % 4), 1, file) < 1) { return false; } return true; } static bool append_information(FILE *file, int block_alignment_size, int normal_size, int normal_lines, int special_size, int special_lines, int index_data_size, int index_data_offset) { DEBUG_ASSERT_POINTER(file); Information information; information.set(Information::ID_BLOCK_ALIGNMENT_SIZE, block_alignment_size); information.set(Information::ID_NORMAL_SIZE, normal_size); information.set(Information::ID_NORMAL_LINES, normal_lines); information.set(Information::ID_SPECIAL_SIZE, special_size); information.set(Information::ID_SPECIAL_LINES, special_lines); information.set(Information::ID_INDEX_DATA_SIZE, index_data_size); information.set(Information::ID_INDEX_DATA_OFFSET, index_data_offset); append_terminator(file); if (fwrite(&information, sizeof(information), 1, file) < 1) { return false; } return true; } static bool create_dictionary_for_class_skk_jisyo_write_temporary_raw(FILE *file, const char *buffer, int index, int line_size) { DEBUG_ASSERT_POINTER(file); DEBUG_ASSERT_POINTER(buffer); DEBUG_ASSERT(index >= 0); DEBUG_ASSERT(line_size > 0); const int cr_size = 1; if (fwrite("\1", 1, 1, file) < 1) { return false; } if (fwrite(buffer + index, static_cast(line_size + cr_size), 1, file) < 1) { return false; } return true; } static bool create_dictionary_for_class_skk_jisyo_write_temporary_encoded(FILE *file, const char *buffer, int index, int filesize, const char *line_buffer, int encoded_size) { DEBUG_ASSERT_POINTER(file); DEBUG_ASSERT_POINTER(buffer); DEBUG_ASSERT(index >= 0); DEBUG_ASSERT(filesize > 0); DEBUG_ASSERT_POINTER(line_buffer); DEBUG_ASSERT(encoded_size > 0); const int cr_size = 1; if (fwrite(line_buffer, static_cast(encoded_size), 1, file) < 1) { return false; } if (fwrite(" ", 1, 1, file) < 1) { return false; } const char *tmp = SkkUtility::getHenkanmojiretsuPointer(buffer, index, filesize); const int tmp_size = SkkUtility::getHenkanmojiretsuSize(buffer, index, filesize); if ((tmp == 0) || (tmp_size <= 0)) { return false; } if (fwrite(tmp, static_cast(tmp_size + cr_size), 1, file) < 1) { return false; } return true; } static bool create_dictionary_for_class_skk_jisyo_write_temporary(const char *buffer, int filesize, int normal_fd, int special_fd, int okuri_ari_index, int okuri_nasi_index, int &okuri_ari_lines, int &okuri_nasi_lines, int &special_okuri_nasi_lines) { DEBUG_ASSERT_POINTER(buffer); DEBUG_ASSERT(filesize > 0); DEBUG_ASSERT(normal_fd > 0); DEBUG_ASSERT(special_fd > 0); DEBUG_ASSERT(okuri_ari_index >= 0); DEBUG_ASSERT(okuri_nasi_index >= 0); DEBUG_ASSERT(okuri_ari_lines == 0); DEBUG_ASSERT(okuri_nasi_lines == 0); DEBUG_ASSERT(special_okuri_nasi_lines == 0); bool result; FILE *file_normal = fdopen(normal_fd, "wb"); FILE *file_special = fdopen(special_fd, "wb"); if ((file_normal == 0) || (file_special == 0)) { result = false; } else { result = true; const int cr_size = 1; const int line_buffer_margin = 16; // line_buffer_size ϾQŪ˹ͤΤʤͤǤ줳ͤ // Ǥ⡢ encodeHiragana() ǥå򤷤Ƥ뤿 // const int line_buffer_size = 64 * 1024; char *line_buffer = new char[line_buffer_size]; for (;;) { bool copy_okuri_ari = false; bool copy_okuri_nasi = false; if ((okuri_ari_index > 0) && (okuri_nasi_index >= 0)) { int tmp = SkkUtility::compareMidasi(buffer, okuri_ari_index, filesize, buffer + okuri_nasi_index); if (tmp == 0) { // ʤ ari/nasi ƱФ (ä餪) result = false; break; } else if (tmp > 0) { // ari -> nasi copy_okuri_nasi = true; } else { // nasi -> ari copy_okuri_ari = true; } } else if (okuri_ari_index > 0) { copy_okuri_ari = true; } else if (okuri_nasi_index >= 0) { copy_okuri_nasi = true; } else { break; } if (copy_okuri_ari) { int line_size = SkkUtility::getLineSize(buffer, okuri_ari_index, filesize); if (line_size == 0) { SkkUtility::printf("warning: found empty line\n"); --okuri_ari_index; if (okuri_ari_index <= 0) { okuri_ari_index = 0; } } else { int encoded_size = SkkUtility::encodeHiragana(buffer + okuri_ari_index, line_buffer, line_buffer_size - line_buffer_margin); if (encoded_size == 0) { result = create_dictionary_for_class_skk_jisyo_write_temporary_raw(file_normal, buffer, okuri_ari_index, line_size); if (result == false) { break; } } else { result = create_dictionary_for_class_skk_jisyo_write_temporary_encoded(file_normal, buffer, okuri_ari_index, filesize, line_buffer, encoded_size); if (result == false) { break; } } ++okuri_ari_lines; okuri_ari_index = SkkUtility::getPreviousLineIndex(buffer, okuri_ari_index, filesize); } } if (copy_okuri_nasi) { int line_size = SkkUtility::getLineSize(buffer, okuri_nasi_index, filesize); if (line_size == 0) { SkkUtility::printf("warning: found empty line\n"); ++okuri_nasi_index; if (okuri_nasi_index >= filesize) { okuri_nasi_index = -1; } } else { int c = *(buffer + okuri_nasi_index) & 0xff; if ((c == 0xa4) || ((c >= 0x21) && (c <= 0x7e))) { int encoded_size = SkkUtility::encodeHiragana(buffer + okuri_nasi_index, line_buffer, line_buffer_size - line_buffer_margin); if (encoded_size == 0) { result = create_dictionary_for_class_skk_jisyo_write_temporary_raw(file_normal, buffer, okuri_nasi_index, line_size); if (result == false) { break; } } else { result = create_dictionary_for_class_skk_jisyo_write_temporary_encoded(file_normal, buffer, okuri_nasi_index, filesize, line_buffer, encoded_size); if (result == false) { break; } } ++okuri_nasi_lines; } else { if (fwrite("\1", 1, 1, file_special) < 1) { result = false; break; } if (fwrite(buffer + okuri_nasi_index, static_cast(line_size + cr_size), 1, file_special) < 1) { result = false; break; } ++special_okuri_nasi_lines; } okuri_nasi_index = SkkUtility::getNextLineIndex(buffer, okuri_nasi_index, filesize); } } // skip comment while ((okuri_ari_index > 0) && (*(buffer + okuri_ari_index) == ';')) { okuri_ari_index = SkkUtility::getPreviousLineIndex(buffer, okuri_ari_index, filesize); } while ((okuri_nasi_index >= 0) && (*(buffer + okuri_nasi_index) == ';')) { okuri_nasi_index = SkkUtility::getNextLineIndex(buffer, okuri_nasi_index, filesize); } } delete[] line_buffer; } if (file_normal) { fclose(file_normal); } if (file_special) { fclose(file_special); } return result; } static bool create_dictionary_for_class_skk_jisyo_sort_core(FILE *file, char *buffer, int filesize, int lines) { DEBUG_ASSERT_POINTER(file); DEBUG_ASSERT_POINTER(buffer); DEBUG_ASSERT(filesize > 0); DEBUG_ASSERT(lines > 0); const int cr_size = 1; SkkUtility::SortKey *sort_key = new SkkUtility::SortKey[lines]; bool result = true; int index = 0; for (int i = 0; i != lines; ++i) { (sort_key + i)->index = index; (sort_key + i)->i = i; index = SkkUtility::getNextLineIndex(buffer, index, filesize); } SkkUtility::sortMidasi(buffer, filesize, sort_key, lines); for (int i = 0; i != lines; ++i) { int line_size = SkkUtility::getLineSize(buffer, (sort_key + i)->index, filesize); if (fwrite(buffer + (sort_key + i)->index, static_cast(line_size + cr_size), 1, file) < 1) { result = false; break; } } delete[] sort_key; return result; } static bool create_dictionary_for_class_skk_jisyo_sort_and_write(const char *filename_destination, const char *filename_normal, const char *filename_special, int okuri_ari_lines, int okuri_nasi_lines, int special_okuri_nasi_lines) { DEBUG_ASSERT_POINTER(filename_destination); DEBUG_ASSERT_POINTER(filename_normal); DEBUG_ASSERT_POINTER(filename_special); DEBUG_ASSERT(okuri_ari_lines >= 0); DEBUG_ASSERT(okuri_nasi_lines >= 0); DEBUG_ASSERT(special_okuri_nasi_lines >= 0); DEBUG_ASSERT((okuri_ari_lines + okuri_nasi_lines + special_okuri_nasi_lines) > 0); bool result = true; FILE *file = fopen(filename_destination, "wb"); if (file == 0) { result = false; } else { int normal_size = 0; int special_size = 0; if (result && ((okuri_ari_lines + okuri_nasi_lines) > 0)) { SkkMmap mmap; char *buffer = static_cast(mmap.map(filename_normal)); if (buffer == 0) { result = false; } else { normal_size = mmap.getFilesize(); result = create_dictionary_for_class_skk_jisyo_sort_core(file, buffer, normal_size, okuri_ari_lines + okuri_nasi_lines); } } if (result && (special_okuri_nasi_lines > 0)) { SkkMmap mmap; char *buffer = static_cast(mmap.map(filename_special)); if (buffer == 0) { result = false; } else { special_size = mmap.getFilesize(); result = create_dictionary_for_class_skk_jisyo_sort_core(file, buffer, special_size, special_okuri_nasi_lines); } } if (result) { result = append_information(file, 0, normal_size, okuri_ari_lines + okuri_nasi_lines, special_size, special_okuri_nasi_lines, 0, 0); if (!result) { DEBUG_PRINTF("append_information() failed.\n"); } } fclose(file); } return result; } // ޤԤϵ֤ޤ /** * Ȥꤢפȡʤפ򺮤ƥȺѤߤξ֤ * ϤޤâʤפΡ֤Ҥ餬(0xa4)פȡASCII(0x21 - * 0x7e)װʳʸ special_okuri_nasi_buffer سǼǸ˽Ϥ * ޤ * * ;; okuri-ari entries. /.../ * a /.../ a /.../ * ˤۤؤa /.../ ˤۤؤ /.../ * ;; okuri-nasi entries. ˤۤؤa /.../ * /.../ special_okuri_nasi_buffer * ˤۤؤ /.../ ۤ /ˡ/ * ۤ /ˡ/ // * // */ static bool create_dictionary_for_class_skk_jisyo(const char *filename_destination, const char *buffer, int filesize, int okuri_ari_index, int okuri_nasi_index) { DEBUG_ASSERT_POINTER(filename_destination); DEBUG_ASSERT_POINTER(buffer); DEBUG_ASSERT(filesize > 0); DEBUG_ASSERT(okuri_ari_index >= 0); DEBUG_ASSERT(okuri_nasi_index >= 0); char tmp_filename_normal[] = "/tmp/skkjisyo_normal.XXXXXX"; char tmp_filename_special[] = "/tmp/skkjisyo_special.XXXXXX"; int normal_fd = mkstemp(tmp_filename_normal); if (normal_fd == -1) { return false; } int special_fd = mkstemp(tmp_filename_special); if (special_fd == -1) { return false; } bool result; int okuri_ari_lines = 0; int okuri_nasi_lines = 0; int special_okuri_nasi_lines = 0; result = create_dictionary_for_class_skk_jisyo_write_temporary(buffer, filesize, normal_fd, special_fd, okuri_ari_index, okuri_nasi_index, okuri_ari_lines, okuri_nasi_lines, special_okuri_nasi_lines); if (result) { result = create_dictionary_for_class_skk_jisyo_sort_and_write(filename_destination, tmp_filename_normal, tmp_filename_special, okuri_ari_lines, okuri_nasi_lines, special_okuri_nasi_lines); } if (unlink(tmp_filename_normal) == -1) { result = false; } if (unlink(tmp_filename_special) == -1) { result = false; } return result; } static bool create_dictionary_index_and_dictionary_for_class_skk_jisyo_special_core(SkkJisyo &object, FILE *aligned_block_dictionary, Block *block, BlockShort *block_short, char *string, int &string_size, int block_size_maximum, bool alignment_flag, int line, int top_line, int index, int top_offset, int block_length, int top_file_offset) { if (block && block_short) { // ξΥݥ󥿤ꤵƤƤϤʤޤ DEBUG_PRINTF("ILLEGAL argument\n"); DEBUG_ASSERT(0); return false; } // Υ֥åκǽԤξޤ int backup_index = object.getIndex(); if (!object.seek(SkkJisyo::SEEK_POSITION_PREVIOUS)) { // SEEK_POSITION_PREVIOUS ԤʤɤϤꤨʤΤʷȤޤ DEBUG_PRINTF("ILLEGAL dictionary\n"); DEBUG_ASSERT(0); object.setIndex(backup_index); return false; } if (block) { if (aligned_block_dictionary && alignment_flag) { (block + block_length)->setOffset(static_cast(ftell(aligned_block_dictionary)) - top_file_offset); } else { (block + block_length)->setOffset(top_offset); } (block + block_length)->setLineLengthAndDataSize(line - top_line, index - top_offset); } else if (block_short) { (block_short + block_length)->setDataSize(index - top_offset); } { const int terminator_size = 1; int length = object.getMidasiSize() + terminator_size; if (string) { char *p = object.getMidasiPointer(); int i; for (i = 0; i != length - terminator_size; ++i) { *(string + string_size + i) = *(p + i); } *(string + string_size + i) = ' '; } string_size += length; } if (aligned_block_dictionary) { int size = index - top_offset; if (fwrite(object.getBuffer() + top_offset, static_cast(size), 1, aligned_block_dictionary) < 1) { object.setIndex(backup_index); return false; } if (alignment_flag && (size < block_size_maximum)) { fseek(aligned_block_dictionary, block_size_maximum - (size % block_size_maximum), SEEK_CUR); } } object.setIndex(backup_index); return true; } static bool create_dictionary_index_and_dictionary_for_class_skk_jisyo_special(SkkJisyo &object, FILE *aligned_block_dictionary, Block *block, BlockShort *block_short, char *string, int &block_length, int &string_size, int block_size_maximum, bool alignment_flag) { if (block && block_short) { // ξΥݥ󥿤ꤵƤƤϤʤޤ DEBUG_PRINTF("ILLEGAL argument\n"); DEBUG_ASSERT(0); return false; } { SkkJisyo::Information information; object.getInformation(information); if (information.get(SkkJisyo::Information::ID_SPECIAL_LINES) == 0) { // special ¸ߤʤĹ 0 ェλ block_length = 0; string_size = 0; return true; } } int backup_index = object.getIndex(); int top_offset = 0; int line = 1; int top_line = 1; int top_file_offset = 0; if (aligned_block_dictionary) { top_file_offset = static_cast(ftell(aligned_block_dictionary)); } block_length = 0; string_size = 0; object.seek(SkkJisyo::SEEK_POSITION_TOP); while (object.seek(SkkJisyo::SEEK_POSITION_NEXT)) { ++line; int index = object.getIndex(); if (index - top_offset > block_size_maximum) { // ֥åۤΤ 1 ᤷޤ object.seek(SkkJisyo::SEEK_POSITION_PREVIOUS); --line; index = object.getIndex(); if (index <= top_offset) { // ᤷˤ⤫餺ƱȤȤ 1 Ǥ // block_size_maximum 礭ȤȤʤꡢȤǤޤ DEBUG_PRINTF("ILLEGAL dictionary\n"); DEBUG_ASSERT(0); object.setIndex(backup_index); return false; } if (!create_dictionary_index_and_dictionary_for_class_skk_jisyo_special_core(object, aligned_block_dictionary, block, block_short, string, string_size, block_size_maximum, alignment_flag, line, top_line, index, top_offset, block_length, top_file_offset)) { // FIXME! } top_line = line; top_offset = index; ++block_length; } } // üնνǤ { object.seek(SkkJisyo::SEEK_POSITION_BOTTOM); int index = object.getIndex() + 1; if (index - top_offset > block_size_maximum) { // ֥åۤΤ 1 ᤷޤ object.seek(SkkJisyo::SEEK_POSITION_PREVIOUS); --line; index = object.getIndex(); if (index <= top_offset) { // ᤷˤ⤫餺ƱȤȤ 1 Ǥ // block_size_maximum 礭ȤȤʤꡢȤǤޤ DEBUG_PRINTF("ILLEGAL dictionary\n"); DEBUG_ASSERT(0); object.setIndex(backup_index); return false; } create_dictionary_index_and_dictionary_for_class_skk_jisyo_special_core(object, aligned_block_dictionary, block, block_short, string, string_size, block_size_maximum, alignment_flag, line, top_line, index, top_offset, block_length, top_file_offset); top_line = line; top_offset = index; ++block_length; ++line; } object.seek(SkkJisyo::SEEK_POSITION_BOTTOM); index = object.getIndex() + 1; { create_dictionary_index_and_dictionary_for_class_skk_jisyo_special_core(object, aligned_block_dictionary, block, block_short, string, string_size, block_size_maximum, alignment_flag, line, top_line, index, top_offset, block_length, top_file_offset); top_offset = index; ++block_length; } } object.setIndex(backup_index); return true; } static bool create_dictionary_index_and_dictionary_for_class_skk_jisyo_normal_core(SkkJisyo &object, FILE *aligned_block_dictionary, FixedArray *fixed_array, Block *block, BlockShort *block_short, char *string, int *count_work, int &string_size, int block_size_maximum, bool alignment_flag, int line, int top_line, int index, int top_offset, int top_fixed_array, int block_length) { if (block && block_short) { // ξΥݥ󥿤ꤵƤƤϤʤޤ DEBUG_PRINTF("ILLEGAL argument\n"); DEBUG_ASSERT(0); return false; } // Υ֥åκǽԤξޤ int backup_index = object.getIndex(); if (!object.seek(SkkJisyo::SEEK_POSITION_PREVIOUS)) { // SEEK_POSITION_PREVIOUS ԤʤɤϤꤨʤΤʷȤޤ DEBUG_PRINTF("ILLEGAL dictionary\n"); DEBUG_ASSERT(0); object.setIndex(backup_index); return false; } if (fixed_array) { if (*(count_work + top_fixed_array) == 0) { (fixed_array + top_fixed_array)->start_block = static_cast(block_length); (fixed_array + top_fixed_array)->string_data_offset = string_size; } (fixed_array + top_fixed_array)->block_length = static_cast(block_length - (fixed_array + top_fixed_array)->start_block + 1); } if (block) { if (aligned_block_dictionary && alignment_flag) { (block + block_length)->setOffset(static_cast(ftell(aligned_block_dictionary))); } else { (block + block_length)->setOffset(top_offset); } (block + block_length)->setLineLengthAndDataSize(line - top_line, index - top_offset); } else if (block_short) { (block_short + block_length)->setDataSize(index - top_offset); } { const int terminator_size = 1; int length = object.getMidasiSize() + terminator_size; if (string) { char *p = object.getMidasiPointer(); int i; for (i = 0; i != length - terminator_size; ++i) { *(string + string_size + i) = *(p + i); } *(string + string_size + i) = ' '; } string_size += length; } if (aligned_block_dictionary) { int size = index - top_offset; if (fwrite(object.getBuffer() + top_offset, static_cast(size), 1, aligned_block_dictionary) < 1) { object.setIndex(backup_index); return false; } if (alignment_flag && (size < block_size_maximum)) { fseek(aligned_block_dictionary, block_size_maximum - (size % block_size_maximum), SEEK_CUR); } } ++*(count_work + top_fixed_array); object.setIndex(backup_index); return true; } /// 񥤥ǥåޤƱ˥饤Ȥ줿Ǥޤ˼Ԥϵ֤ޤΤȤ DEBUG_ASSERT ͭʤХȤޤ /** * block_length string_size block string dzݤ٤ * ֤ޤblock string 0 ϤȡΥХåեˤϿ * ΤǡŵŪʸƤӽФȤưʲΤ褦 * create_block_and_aligned_block_dictionary() 2 ٸƤӽФȤä * ˡޤ * * \verbatim create_dictionary_index_and_dictionary_for_class_skk_jisyo_normal(object, 0, fixed_array, 0, // block 0, // string block_length, string_size, block_size_maximum, alignment_flag); block = new Block[block_length]; string = new char[string_size]; create_dictionary_index_and_dictionary_for_class_skk_jisyo_normal(object, 0, fixed_array, block, string block_length, string_size, block_size_maximum, alignment_flag); \endverbatim * * block string ˽ʬʥͿ뤫block_length * string_size Τʤ 1 ٤θƤӽФǤޤޤ * * aligned_block_dictionary ˽񤭹߲ǽʥեݥ󥿤Ϳ * Ϥޤ 0 ʤв⤷ޤ * * alignment_flag ʤгƥ֥å block_size_maximum ǥ饤 * Ȥ줿ˤʤޤ */ static bool create_dictionary_index_and_dictionary_for_class_skk_jisyo_normal(SkkJisyo &object, FILE *aligned_block_dictionary, FixedArray *fixed_array, Block *block, BlockShort *block_short, char *string, int &block_length, int &string_size, int block_size_maximum, bool alignment_flag) { if (block && block_short) { // ξΥݥ󥿤ꤵƤƤϤʤޤ DEBUG_PRINTF("ILLEGAL argument\n"); DEBUG_ASSERT(0); return false; } { SkkJisyo::Information information; object.getInformation(information); if (information.get(SkkJisyo::Information::ID_NORMAL_LINES) == 0) { // normal ¸ߤʤĹ 0 ェλ block_length = 0; string_size = 0; return true; } } int backup_index = object.getIndex(); int top_offset = 0; int count_work_table[256]; int top_fixed_array; int line = 1; int top_line = 1; block_length = 0; string_size = 0; for (int i = 0; i != 256; ++i) { count_work_table[i] = 0; } object.seek(SkkJisyo::SEEK_POSITION_TOP); top_fixed_array = object.getFixedArrayIndex(); if (top_fixed_array < 0) { DEBUG_ASSERT(0); object.setIndex(backup_index); return false; } while (object.seek(SkkJisyo::SEEK_POSITION_NEXT)) { ++line; int next_fixed_array = object.getFixedArrayIndex(); if (next_fixed_array < 0) { DEBUG_PRINTF("ILLEGAL FIXED_ARRAY\n"); DEBUG_ASSERT(0); object.setIndex(backup_index); return false; } int index = object.getIndex(); if ((top_fixed_array != next_fixed_array) || (index - top_offset > block_size_maximum)) { if (index - top_offset > block_size_maximum) { // ֥åۤΤ 1 ᤷޤ object.seek(SkkJisyo::SEEK_POSITION_PREVIOUS); --line; index = object.getIndex(); if (index <= top_offset) { // ᤷˤ⤫餺ƱȤȤ 1 Ǥ // block_size_maximum 礭ȤȤʤꡢȤǤޤ SkkUtility::printf("block size error. (block size = %d line size = %d)\n", block_size_maximum, object.getLineSize()); DEBUG_PRINTF("ILLEGAL dictionary\n"); DEBUG_ASSERT(0); object.setIndex(backup_index); return false; } // ɤľΤǺ fixed_array ꤷޤ next_fixed_array = object.getFixedArrayIndex(); if (next_fixed_array < 0) { DEBUG_PRINTF("ILLEGAL FIXED_ARRAY\n"); DEBUG_ASSERT(0); object.setIndex(backup_index); return false; } } if (!create_dictionary_index_and_dictionary_for_class_skk_jisyo_normal_core(object, aligned_block_dictionary, fixed_array, block, block_short, string, count_work_table, string_size, block_size_maximum, alignment_flag, line, top_line, index, top_offset, top_fixed_array, block_length)) { // FIXME! } top_line = line; top_offset = index; top_fixed_array = next_fixed_array; ++block_length; } } // üնνǤ { object.seek(SkkJisyo::SEEK_POSITION_BOTTOM); int index = object.getIndex() + 1; if (index - top_offset > block_size_maximum) { // ֥åۤΤ 1 ᤷޤ object.seek(SkkJisyo::SEEK_POSITION_PREVIOUS); --line; index = object.getIndex(); if (index <= top_offset) { // ᤷˤ⤫餺ƱȤȤ 1 Ǥ // block_size_maximum 礭ȤȤʤꡢȤǤޤ DEBUG_PRINTF("ILLEGAL dictionary\n"); DEBUG_ASSERT(0); object.setIndex(backup_index); return false; } create_dictionary_index_and_dictionary_for_class_skk_jisyo_normal_core(object, aligned_block_dictionary, fixed_array, block, block_short, string, count_work_table, string_size, block_size_maximum, alignment_flag, line, top_line, index, top_offset, top_fixed_array, block_length); top_line = line; top_offset = index; ++block_length; ++line; } object.seek(SkkJisyo::SEEK_POSITION_BOTTOM); index = object.getIndex() + 1; { create_dictionary_index_and_dictionary_for_class_skk_jisyo_normal_core(object, aligned_block_dictionary, fixed_array, block, block_short, string, count_work_table, string_size, block_size_maximum, alignment_flag, line, top_line, index, top_offset, top_fixed_array, block_length); top_offset = index; ++block_length; } } object.setIndex(backup_index); return true; } public: static bool getJisyoType(const char *filename, JisyoType &type) { DEBUG_ASSERT_POINTER(filename); bool result; FILE *file = fopen(filename, "rb"); if (file == 0) { type = JISYO_TYPE_UNKNOWN; result = false; } else { result = true; char tmp[1024]; if (fread(tmp, 1024, 1, file) < 1) { type = JISYO_TYPE_UNKNOWN; result = false; } else { if (tmp[0] == ';') { // 1 ʸܤ ; ʤйΨ SKK ʤΤǡʤꤤǤ // SKK ȤƤޤޤ type = JISYO_TYPE_SKK_RAW; } else { if (fseek(file, -static_cast(sizeof(Information)), SEEK_END) == -1) { type = JISYO_TYPE_UNKNOWN; result = false; } else { if (ftell(file) & 0x3) { // Information ٤֤ 4 ܿǤʤΤʤǤ type = JISYO_TYPE_UNKNOWN; } else { Information tmp_information; if (fread(&tmp_information, sizeof(tmp_information), 1, file) < 1) { type = JISYO_TYPE_UNKNOWN; result = false; } else { if (tmp_information.get(Information::ID_IDENTIFIER) != IDENTIFIER) { // IDENTIFIER פʤΤΤʤǤ type = JISYO_TYPE_UNKNOWN; } else { if (tmp_information.get(Information::ID_INDEX_DATA_SIZE) == 0) { // ǥåǡ¸ߤʤΤ class SkkJisyo ѤǤ type = JISYO_TYPE_CLASS_SKK_JISYO; } else { type = JISYO_TYPE_CLASS_SKK_DICTIONARY; } } } } } } } fclose(file); } return result; } /// SKK class SkkJisyo μѴޤѴ˼Ԥϵ֤ޤ /** * class SkkJisyo ǰμˤϥǥåǡ¸ߤޤ */ static bool createDictionaryForClassSkkJisyo(const char *filename_source, const char *filename_destination) { DEBUG_ASSERT_POINTER(filename_source); DEBUG_ASSERT_POINTER(filename_destination); bool result = true; SkkMmap mmap; char *buffer = static_cast(mmap.map(filename_source)); if (buffer == 0) { result = false; } else { int filesize = mmap.getFilesize(); if (filesize < SkkUtility::getStringOkuriAriLength() + SkkUtility::getStringOkuriNasiLength()) { result = false; } else { int okuri_ari_index = 0; int okuri_nasi_index = 0; // ޤ okuri_ari_index okuri_nasi_index ޤ if (!get_index(buffer, filesize, okuri_ari_index, okuri_nasi_index)) { result = false; } else { result = create_dictionary_for_class_skk_jisyo(filename_destination, buffer, filesize, okuri_ari_index, okuri_nasi_index); } } } return result; } /// SKK block_size class SkkDictionary μѴޤѴ˼Ԥϵ֤ޤ static bool createDictionaryForClassSkkDictionary(const char *filename_source, const char *filename_destination, int block_size, bool alignment_flag = false, bool block_short_flag = false) { DEBUG_ASSERT_POINTER(filename_source); DEBUG_ASSERT_POINTER(filename_destination); bool result; SkkJisyo object; FixedArray *fixed_array = 0; Block *block = 0; BlockShort *block_short = 0; char *string = 0; int normal_block_length = 0; int normal_string_size = 0; int special_block_length = 0; int special_string_size = 0; if (alignment_flag) { char tmp_filename[] = "/tmp/skkjisyo.XXXXXX"; // ʤΤˡǤƥݥե̾뤿 // mkstemp() ѤƤޤ̩ˤϤλȤǤϥƥݥե // ̾ˡǤ뤳ȤݾڤʤȤդɬפǤ int tmp_fd = mkstemp(tmp_filename); if (tmp_fd == -1) { return false; } else { ::close(tmp_fd); result = createDictionaryForClassSkkJisyo(filename_source, tmp_filename); if (result) { result = object.open(tmp_filename); if (result) { result = object.createDictionaryIndex(block_size, alignment_flag, block_short_flag); if (result) { result = object.getDictionaryIndexInformation(fixed_array, block, block_short, string, normal_block_length, normal_string_size, special_block_length, special_string_size); } if (result) { if (unlink(tmp_filename) == -1) { result = false; } else { result = object.createDictionaryIndexAndDictionaryForClassSkkJisyo(block_size, filename_destination, alignment_flag, block_short_flag); } } } } } } else { result = createDictionaryForClassSkkJisyo(filename_source, filename_destination); if (result) { result = object.open(filename_destination); if (result) { result = object.createDictionaryIndex(block_size); if (result) { result = object.getDictionaryIndexInformation(fixed_array, block, block_short, string, normal_block_length, normal_string_size, special_block_length, special_string_size); } } } } if (!result) { unlink(filename_destination); } else { FILE *file = fopen(filename_destination, "r+b"); if (file == 0) { result = false; } else { if (fseek(file, -static_cast(sizeof(Information)), SEEK_END) == -1) { result = false; } Information tmp_information; if (result && (fread(&tmp_information, sizeof(tmp_information), 1, file) < 1)) { result = false; } if (result) { if (fseek(file, -static_cast(sizeof(Information)), SEEK_END) == -1) { result = false; } IndexDataHeader index_data_header; { int32_t tmp = index_data_header.get(IndexDataHeader::ID_BIT_FLAG); tmp |= block_short_flag ? IndexDataHeader::BIT_FLAG_BLOCK_SHORT : 0; index_data_header.set(IndexDataHeader::ID_BIT_FLAG, tmp); } index_data_header.set(IndexDataHeader::ID_BLOCK_SIZE, block_size); index_data_header.set(IndexDataHeader::ID_NORMAL_BLOCK_LENGTH, normal_block_length); index_data_header.set(IndexDataHeader::ID_SPECIAL_BLOCK_LENGTH, special_block_length); index_data_header.set(IndexDataHeader::ID_NORMAL_STRING_SIZE, normal_string_size); index_data_header.set(IndexDataHeader::ID_SPECIAL_STRING_SIZE, special_string_size); index_data_header.set(IndexDataHeader::ID_SPECIAL_ENTRY_OFFSET, tmp_information.get(Information::ID_NORMAL_SIZE)); if (result) { int index_data_offset = static_cast(ftell(file)); if (result) { const size_t size_of_block = block ? sizeof(Block) : sizeof(BlockShort); struct { const void *p; size_t size; } table[] = { { &index_data_header, sizeof(index_data_header), }, { fixed_array, sizeof(FixedArray) * 256, }, { block, sizeof(Block) * static_cast(normal_block_length + special_block_length), }, { block_short, sizeof(BlockShort) * static_cast(normal_block_length + special_block_length), }, { string, static_cast(normal_string_size + special_string_size), }, { 0, 0, }, }; for (int i = 0;; ++i) { if ((table[i].p == 0) && (table[i].size == 0)) { break; } if (table[i].p) { if (fwrite(table[i].p, table[i].size, 1, file) < 1) { result = false; break; } } } if (result) { result = append_terminator(file); } if (result) { int index_data_size = static_cast(sizeof(index_data_header) + sizeof(FixedArray) * 256 + static_cast(size_of_block * static_cast(normal_block_length + special_block_length)) + static_cast(normal_string_size + special_string_size)); tmp_information.set(Information::ID_INDEX_DATA_SIZE, index_data_size); tmp_information.set(Information::ID_INDEX_DATA_OFFSET, index_data_offset); if (fwrite(&tmp_information, sizeof(tmp_information), 1, file) < 1) { result = false; } } } } } fclose(file); SkkUtility::chmod(filename_destination, 0644); } } return result; } /// ꤷե뤫 Information ޤ˼Ԥϵ֤ޤ static bool getInformation(const char *filename, Information &information) { DEBUG_ASSERT_POINTER(filename); JisyoType type; bool result = getJisyoType(filename, type); if ((type == JISYO_TYPE_CLASS_SKK_JISYO) || (type == JISYO_TYPE_CLASS_SKK_DICTIONARY)) { FILE *file = fopen(filename, "rb"); if (file == 0) { result = false; } else { result = true; if (fseek(file, -static_cast(sizeof(Information)), SEEK_END) == -1) { result = false; } if (result && (fread(&information, sizeof(information), 1, file) < 1)) { result = false; } fclose(file); } } else { result = false; } return result; } /// ꤷե뤫 IndexDataHeader ޤ˼Ԥϵ֤ޤ static bool getIndexDataHeader(const char *filename, IndexDataHeader &index_data_header) { DEBUG_ASSERT_POINTER(filename); JisyoType type; bool result = getJisyoType(filename, type); if (type == JISYO_TYPE_CLASS_SKK_DICTIONARY) { FILE *file = fopen(filename, "rb"); if (file == 0) { result = false; } else { result = true; if (fseek(file, -static_cast(sizeof(Information)), SEEK_END) == -1) { result = false; } Information tmp_information; if (result && (fread(&tmp_information, sizeof(tmp_information), 1, file) < 1)) { result = false; } int index_data_offset = tmp_information.get(Information::ID_INDEX_DATA_OFFSET); if (result && (fseek(file, index_data_offset, SEEK_SET) == -1)) { result = false; } if (result && (fread(&index_data_header, sizeof(index_data_header), 1, file) < 1)) { result = false; } fclose(file); } } else { result = false; } return result; } virtual ~SkkJisyo() { close(); } SkkJisyo() : mmap_(0), filename_buffer_(0), state_(STATE_NORMAL), information_(), fixed_array_(0), block_(0), block_short_(0), string_(0), normal_block_length_(0), normal_string_size_(0), special_block_length_(0), special_string_size_(0), open_failure_flag_(false) { for (int i = 0; i != STATE_LENGTH; ++i) { buffer_table_[i] = 0; index_table_[i] = 0; size_table_[i] = 0; } } /// 񥤥ǥå򥪥֥ filename_destination ꤵƤ class SkkJisyo μ񤭽ФޤѴ˼Ԥϵ֤ޤ /** * block_size ǥ饤Ȥޤ * * 񥤥ǥå filename_destination 0 ꤷޤ * createDictionaryIndex() ϡޤˤΤ褦ʼˤʤäƤޤ */ bool createDictionaryIndexAndDictionaryForClassSkkJisyo(int block_size, const char *filename_destination, bool alignment_flag = false, bool block_short_flag = false) { int normal_block_length; int normal_string_size; int special_block_length = 0; int special_string_size = 0; FILE *file; if (filename_destination) { file = fopen(filename_destination, "wb"); if (file == 0) { return false; } } else { file = 0; } if (fixed_array_ == 0) { fixed_array_ = new FixedArray[256]; } bool result; if (normal_block_length_ == 0) { setState(SkkJisyo::STATE_NORMAL); result = create_dictionary_index_and_dictionary_for_class_skk_jisyo_normal(*this, 0, fixed_array_, 0, 0, 0, normal_block_length, normal_string_size, block_size, alignment_flag); setState(SkkJisyo::STATE_SPECIAL); if (result) { result = create_dictionary_index_and_dictionary_for_class_skk_jisyo_special(*this, 0, 0, 0, 0, special_block_length, special_string_size, block_size, alignment_flag); normal_block_length_ = normal_block_length; normal_string_size_ = normal_string_size; special_block_length_ = special_block_length; special_string_size_ = special_string_size; } setState(SkkJisyo::STATE_NORMAL); } else { result = true; } if (result) { if (string_ == 0) { string_ = new char[normal_string_size_ + special_string_size_]; SkkUtility::clearMemory(string_, normal_string_size_ + special_string_size_); } else { // ˳ݤƤ롣 } // block_ block_short_ ƱꤷƤϤʤʤᡢ˳ݤ // ϡ⤦ 0 ꤷޤ if (block_short_flag) { if (block_short_ == 0) { delete[] block_; block_ = 0; block_short_ = new BlockShort[normal_block_length_ + special_block_length_]; } else { // ˳ݤƤޤ } } else { if (block_ == 0) { delete[] block_short_; block_short_ = 0; block_ = new Block[normal_block_length_ + special_block_length_]; } else { // ˳ݤƤޤ } } if (result) { setState(SkkJisyo::STATE_NORMAL); result = create_dictionary_index_and_dictionary_for_class_skk_jisyo_normal(*this, file, fixed_array_, block_, block_short_, string_, normal_block_length, normal_string_size, block_size, alignment_flag); int normal_size; if (file) { normal_size = static_cast(ftell(file)); } else { normal_size = 0; } if (result) { setState(SkkJisyo::STATE_SPECIAL); Block *tmp_block = 0; BlockShort *tmp_block_short = 0; if (block_) { tmp_block = block_ + normal_block_length; } if (block_short_) { tmp_block_short = block_short_ + normal_block_length; } result = create_dictionary_index_and_dictionary_for_class_skk_jisyo_special(*this, file, tmp_block, tmp_block_short, string_ + normal_string_size, special_block_length, special_string_size, block_size, alignment_flag); setState(SkkJisyo::STATE_NORMAL); } if (result && file) { int special_size = static_cast(ftell(file)) - normal_size; append_information(file, block_size, normal_size, information_.get(Information::ID_NORMAL_LINES), special_size, information_.get(Information::ID_SPECIAL_LINES), 0, 0); } } } if (file) { fclose(file); } return result; } /// 񥤥ǥå򥪥֥ޤ˼Ԥϵ֤ޤ bool createDictionaryIndex(int block_size, bool alignment_flag = false, bool block_short_flag = false) { return createDictionaryIndexAndDictionaryForClassSkkJisyo(block_size, 0, alignment_flag, block_short_flag); } /// 񥤥ǥåξޤ˼Ԥϵ֤ DEBUG_ASSERT ͭʤХȤޤ bool getDictionaryIndexInformation(FixedArray *&fixed_array, Block *&block, BlockShort *&block_short, char *&string, int &normal_block_length, int &normal_string_size, int &special_block_length, int &special_string_size) { if ((fixed_array_ == 0) || ((block_ == 0) && (block_short_ == 0)) || (string_ == 0)) { DEBUG_ASSERT(0); return false; } else { fixed_array = fixed_array_; block = block_; block_short = block_short_; string = string_; normal_block_length = normal_block_length_; normal_string_size = normal_string_size_; special_block_length = special_block_length_; special_string_size = special_string_size_; return true; } } bool close() { delete[] string_; delete[] block_; delete[] fixed_array_; delete mmap_; delete[] filename_buffer_; mmap_ = 0; filename_buffer_ = 0; state_ = STATE_NORMAL; // information_; fixed_array_ = 0; block_ = 0; string_ = 0; normal_block_length_ = 0; normal_string_size_ = 0; special_block_length_ = 0; special_string_size_ = 0; open_failure_flag_ = false; for (int i = 0; i != STATE_LENGTH; ++i) { buffer_table_[i] = 0; index_table_[i] = 0; size_table_[i] = 0; } return true; } /// 򥪡ץ󤷤ޤ˥ץǤп֤ޤԤϵ֤ DEBUG_ASSERT ͭʤХȤޤ /** * class SkkJisyo ǻѤǤ뼭 * createDictionaryForClassSkkJisyo()פޤ * createDictionaryIndexAndDictionaryForClassSkkJisyo() 饤 * Ȥʤפ줿ΤǤ * * ̾ SKK-JISYO 䥢饤Ȥ줿 class SkkJisyo Ǥϻ * ѤǤʤᡢץ˼Ԥޤ */ bool open(const char *filename) { DEBUG_ASSERT_POINTER(filename); int length = 0; const int limit = 4096; const int margin = 16; while (*(filename + length) != '\0') { ++length; } if ((length == 0) || (length > limit - margin)) { DEBUG_ASSERT(0); open_failure_flag_ = true; return false; } else { filename_buffer_ = new char[length + margin]; int i = 0; for (i = 0; *(filename + i) != '\0'; ++i) { *(filename_buffer_ + i) = *(filename + i); } *(filename_buffer_ + i) = '\0'; mmap_ = new SkkMmap(); buffer_table_[STATE_NORMAL] = static_cast(mmap_->map(filename_buffer_)); if (buffer_table_[STATE_NORMAL] == 0) { DEBUG_ASSERT(0); open_failure_flag_ = true; return false; } if (*buffer_table_[STATE_NORMAL] == ';') { // Ƭ 1 ХȤ ';' ʥǡ̾ SKK-JISYO βǽ⤤ // (ʤȤ class SkkJisyo ǤʷʤΤ) Ԥޤ DEBUG_ASSERT(0); open_failure_flag_ = true; return false; } information_.initialize(buffer_table_[STATE_NORMAL] + mmap_->getFilesize() - Information::getSize()); if ((information_.get(Information::ID_IDENTIFIER) != IDENTIFIER) || (information_.get(Information::ID_BLOCK_ALIGNMENT_SIZE) != 0)) { // IDENTIFIER ޤϥ饤Ȥ줿ʤмԤޤ open_failure_flag_ = true; return false; } size_table_[STATE_NORMAL] = information_.get(Information::ID_NORMAL_SIZE); size_table_[STATE_SPECIAL] = information_.get(Information::ID_SPECIAL_SIZE); buffer_table_[STATE_SPECIAL] = buffer_table_[STATE_NORMAL] + size_table_[STATE_NORMAL]; if (buffer_table_[STATE_NORMAL]) { seek(SEEK_POSITION_TOP); } } return true; } void getInformation(Information &information) { information = information_; } State getState() { return state_; } void setState(State state) { state_ = state; } char *getBuffer() { return buffer_table_[state_]; } int getIndex() { return index_table_[state_]; } void setIndex(int index) { index_table_[state_] = index; } /// ֤˥ޤХåե򥢥褦Ȥ˵֤ޤ /** * * ֤ϰʲ̤ * * \li ǥå -1 ĤޤХåեü˺ݤä * * \li Хåեü(ǥå 0 )ιԤإ褦Ȥ * * ʤü˺ݤäǤϥǥå 0 ˤʤǡ * ֤ʤȤդɬפǤ (ǥå 0 ξ֤ǹ˥ * ƽƵ֤) * */ bool seek(SeekPosition position) { if (open_failure_flag_) { return false; } bool result = true; switch (position) { default: DEBUG_ASSERT(0); break; case SEEK_POSITION_TOP: index_table_[state_] = 0; break; case SEEK_POSITION_BOTTOM: index_table_[state_] = size_table_[state_] - 1; break; case SEEK_POSITION_NEXT: index_table_[state_] = SkkUtility::getNextLineIndex(buffer_table_[state_], index_table_[state_], size_table_[state_]); break; case SEEK_POSITION_PREVIOUS: if (index_table_[state_] == 0) { result = false; } else { index_table_[state_] = SkkUtility::getPreviousLineIndex(buffer_table_[state_], index_table_[state_], size_table_[state_]); } break; case SEEK_POSITION_BEGINNING_OF_LINE: index_table_[state_] = SkkUtility::getBeginningOfLineIndex(buffer_table_[state_], index_table_[state_], size_table_[state_]); break; } if (index_table_[state_] < 0) { result = false; } return result; } /// ʸõޤܥ᥽åɤǥơȤѹ뤳ȤդɬפǤָФפϥڡǥߥ͡Ȥޤդʤе֤ޤ bool search(const char *midasi) { DEBUG_ASSERT_POINTER(midasi); if (open_failure_flag_) { return false; } const int margin = 8; char encoded_midasi[SkkUtility::ENCODED_MIDASI_BUFFER_SIZE]; int encoded_size = SkkUtility::encodeHiragana(midasi, encoded_midasi, sizeof(encoded_midasi) - margin); if (encoded_size == 0) { encoded_midasi[0] = '\1'; int i; for (i = 0; sizeof(encoded_midasi) - margin; ++i) { if ((*(midasi + i) == ' ') || (*(midasi + i) == '\0')) { goto FOUND_TERMINATOR; } encoded_midasi[i + 1] = *(midasi + i); } return false; FOUND_TERMINATOR: encoded_midasi[i + 1] = '\0'; } else { encoded_midasi[encoded_size] = '\0'; } // ޤХʥꥵõդʤϥХʥꥵνϤ // Ѥõޤ if (SkkUtility::getFixedArrayIndex(encoded_midasi) == -1) { state_ = STATE_SPECIAL; int index; if (SkkUtility::searchBinary(buffer_table_[state_], size_table_[state_], encoded_midasi, index)) { setIndex(index); return true; } else { if (SkkUtility::searchLinear(buffer_table_[state_], size_table_[state_], encoded_midasi, index)) { setIndex(index); return true; } } } else { state_ = STATE_NORMAL; int index; if (SkkUtility::searchBinary(buffer_table_[state_], size_table_[state_], encoded_midasi, index)) { setIndex(index); return true; } else { if (SkkUtility::searchLinear(buffer_table_[state_], size_table_[state_], encoded_midasi, index)) { setIndex(index); return true; } } } return false; } int getMidasiSize() { return SkkUtility::getMidasiSize(buffer_table_[state_], getIndex(), size_table_[state_]); } char *getMidasiPointer() { return buffer_table_[state_] + getIndex(); } /// index Ƭ֤ˤȤơѴʸפΥ֤ޤ˲ʸϴޤߤޤ int getHenkanmojiretsuSize() { return SkkUtility::getHenkanmojiretsuSize(buffer_table_[state_], getIndex(), size_table_[state_]); } /// index Ƭ֤ˤȤơѴʸפΥݥ󥿤֤ޤ const char *getHenkanmojiretsuPointer() { return SkkUtility::getHenkanmojiretsuPointer(buffer_table_[state_], getIndex(), size_table_[state_]); } /// index Ƭ֤ˤȤơ 1 ԤΥ֤ޤ˲ʸϴޤߤޤ int getLineSize() { return SkkUtility::getLineSize(buffer_table_[state_], getIndex(), size_table_[state_]); } int getFixedArrayIndex() { return SkkUtility::getFixedArrayIndex(buffer_table_[state_] + getIndex()); } private: SkkMmap *mmap_; char *filename_buffer_; State state_; Information information_; FixedArray *fixed_array_; Block *block_; BlockShort *block_short_; char *string_; int normal_block_length_; int normal_string_size_; int special_block_length_; int special_string_size_; bool open_failure_flag_; char *buffer_table_[STATE_LENGTH]; int index_table_[STATE_LENGTH]; int size_table_[STATE_LENGTH]; }; } #endif // SKK_JISYO_H yaskkserv-1.1.0/source/skk/skk_server.hpp000066400000000000000000000730571262716711600205370ustar00rootroot00000000000000/* Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012, 2013, 2014 Tadashi Watanabe This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef SKK_SERVER_H #define SKK_SERVER_H #ifdef YASKKSERV_CONFIG_HAVE_SYSTEMD #include #endif #include "skk_architecture.hpp" #include "skk_socket.hpp" #include "skk_utility.hpp" #include "skk_dictionary.hpp" #include "skk_syslog.hpp" namespace YaSkkServ { #ifdef YASKKSERV_DEBUG #define SKK_MEMORY_DEBUG #endif // YASKKSERV_DEBUG #ifdef SKK_MEMORY_DEBUG // // SKK_MEMORY_DEBUG Ƥ硢Хåե // SKK_MEMORY_DEBUG_MARGIN_SIZE * 2 ¿ݤޤ // // SKK_MEMORY_DEBUG_MARGIN_SIZE 礭ΰϥХåեղä // ޤޡ memory_debug_set() ǽꤵ졢 // memory_debug_check() ǥåޤ // // SKK_MEMORY_DEBUG ʤΥХåե // +----------+ // | Хåե | // +----------+ // // SKK_MEMORY_DEBUG ΥХåե // +----------+----------+----------+ // | ޡ | Хåե | ޡ | // +----------+----------+----------+ // #define SKK_MEMORY_DEBUG_MARGIN_SIZE 4 inline void skk_memory_debug_set_(char *p) { *(p + 0) = static_cast(0xde); *(p + 1) = static_cast(0xad); *(p + 2) = static_cast(0xbe); *(p + 3) = static_cast(0xef); DEBUG_PRINTF("skk_memory_debug_set_() %p\n" , p); } inline void skk_memory_debug_check_(const char *p) { if (((*(p + 0) & 0xff) != 0xde) || ((*(p + 1) & 0xff) != 0xad) || ((*(p + 2) & 0xff) != 0xbe) || ((*(p + 3) & 0xff) != 0xef)) { DEBUG_PRINTF("skk_memory_debug_check_() %p failed\n" "0x %02x,%02x,%02x,%02x\n" , p, *(p + 0) & 0xff, *(p + 1) & 0xff, *(p + 2) & 0xff, *(p + 3) & 0xff); DEBUG_ASSERT(0); } } #endif // SKK_MEMORY_DEBUG /// SKK ФǤ class SkkServer { SkkServer(SkkServer &source); SkkServer& operator=(SkkServer &source); public: virtual ~SkkServer() { for (int i = 0; i != max_connection_; ++i) { #ifdef SKK_MEMORY_DEBUG delete[] ((work_ + i)->read_buffer - SKK_MEMORY_DEBUG_MARGIN_SIZE); #else // SKK_MEMORY_DEBUG delete[] (work_ + i)->read_buffer; #endif // SKK_MEMORY_DEBUG } delete[] work_; syslog_.printf(1, SkkSyslog::LEVEL_INFO, "terminated"); } SkkServer(const char *identifier, int port, int log_level, const char *address) : syslog_(identifier, log_level), work_(0), port_(port), address_(address), max_connection_(0), listen_queue_(0), file_descriptor_(0) { } void printFirstSyslog() { syslog_.printf(1, SkkSyslog::LEVEL_INFO, "version " YASKKSERV_VERSION " (port=%d)", port_); } virtual bool mainLoop() = 0; protected: /// send() п֤ޤ֤ Work::closeAndReset() ٤Ǥ bool send(int file_descriptor, const void *data, int data_size) { bool result = false; int send_size = 0; for (;;) { int send_result = SkkSocket::send(file_descriptor, data, data_size); if (send_result == -1) { break; } else { send_size += send_result; if (send_size == data_size) { result = true; break; } } } return result; } #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" /// MainLoop() Υ˥饤Ǥ bool main_loop_initialize(int max_connection, int listen_queue) { max_connection_ = max_connection; listen_queue_ = listen_queue; // delete[] ϥǥȥ饯ǡ work_ = new Work[max_connection_]; for (int i = 0; i != max_connection_; ++i) { #ifdef SKK_MEMORY_DEBUG (work_ + i)->read_buffer = new char[SKK_MEMORY_DEBUG_MARGIN_SIZE + READ_BUFFER_SIZE + SKK_MEMORY_DEBUG_MARGIN_SIZE]; (work_ + i)->read_buffer += SKK_MEMORY_DEBUG_MARGIN_SIZE; skk_memory_debug_set_((work_ + i)->read_buffer - SKK_MEMORY_DEBUG_MARGIN_SIZE); skk_memory_debug_set_((work_ + i)->read_buffer - SKK_MEMORY_DEBUG_MARGIN_SIZE + SKK_MEMORY_DEBUG_MARGIN_SIZE + READ_BUFFER_SIZE); #else // SKK_MEMORY_DEBUG (work_ + i)->read_buffer = new char[READ_BUFFER_SIZE]; #endif // SKK_MEMORY_DEBUG *((work_ + i)->read_buffer + 0) = '\0'; } #ifdef YASKKSERV_CONFIG_HAVE_SYSTEMD int number_of_fds = sd_listen_fds(1); if (number_of_fds == 1) { file_descriptor_ = SD_LISTEN_FDS_START; syslog_.printf(1, SkkSyslog::LEVEL_INFO, "Use fd=%d from systemd socket activation", file_descriptor_); return true; } #endif file_descriptor_ = socket(AF_INET, SOCK_STREAM, 0); if (file_descriptor_ == -1) { return false; } fcntl(file_descriptor_, F_SETFL, O_NONBLOCK); { int optval = 1; setsockopt(file_descriptor_, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); } struct sockaddr_in socket_connect; SkkUtility::clearMemory(&socket_connect, sizeof(socket_connect)); socket_connect.sin_family = AF_INET; if (! inet_aton(address_, &socket_connect.sin_addr)) { SkkUtility::printf("invalid address\n"); return false; } socket_connect.sin_port = htons(static_cast(port_)); int retry = 3; while (bind(file_descriptor_, reinterpret_cast(&socket_connect), sizeof(socket_connect)) == -1) { if (--retry <= 0) { close(file_descriptor_); SkkUtility::printf("socket bind failed\n"); return false; } SkkUtility::sleep(1); } if ((listen(file_descriptor_, listen_queue_)) == -1) { close(file_descriptor_); return false; } return true; } #pragma GCC diagnostic pop /// ָФפõΤȤ "1" ղäߤΥХåեΡѴʸפ send() ޤ void main_loop_send_found(int work_index, SkkDictionary *skk_dictionary) { // // mmap Ȥʤ硢ꥳԡ򤱤뤿֥å꡼ɥХåե // 񤭴 send() ᤷƤޤ츫ʤäǤ '1' // 񤭹 p - 1 RAM Ǥ뤳Ȥݾڤ졢ɬ¸ߤޤ // Ūˤϥ֥åХåեΰʲΰ֤ˤޤ // // mmap Ȥ硢ޤ ROM Υǡ򰷤ˤ send() ʣ // Ƥ֤ʤɤνɬפˤʤ뤳ȤդɬפǤ // // p - 1 // | // v // ߤ /Ѵʸ0/Ѵʸ1/ // ^ // | // p == getHenkanmojiretsuPointer() // char *p = const_cast(skk_dictionary->getHenkanmojiretsuPointer()); const int protocol_size = 1; const int cr_size = 1; char backup = *(p - 1); *(p - 1) = '1'; if (!send((work_ + work_index)->file_descriptor, p - 1, protocol_size + skk_dictionary->getHenkanmojiretsuSize() + cr_size)) { (work_ + work_index)->closeAndReset(); } *(p - 1) = backup; } /// ָФפõ˼ԤΤȤ "4" ղäߤΥХåեΡָФפ send() ޤ /** * ߤΥХåե \\n Ǥʤ \\n ɲä send() ޤ */ void main_loop_send_not_found(int work_index, int recv_result) { // 2 ʬ send() ľˤʤޤ򤤤ޤ路 // 1 send() ˤ®ʤᡢʲΤ褦ʥɤˤʤäƤޤ DEBUG_ASSERT(recv_result > 1); // read_buffer recv() 륵礭ܤ˳ݤƤΤ + // recv_result ˥Ƥꤢޤ char backup_2 = *((work_ + work_index)->read_buffer + recv_result); int send_size; if (*((work_ + work_index)->read_buffer + recv_result - 1) != '\n') { // ü '\n' Ǥʤ '\n' ɲäޤ *((work_ + work_index)->read_buffer + recv_result) = '\n'; send_size = recv_result + 1; } else { send_size = recv_result; } char backup = *((work_ + work_index)->read_buffer); *((work_ + work_index)->read_buffer) = '4'; if (!send((work_ + work_index)->file_descriptor, (work_ + work_index)->read_buffer, send_size)) { (work_ + work_index)->closeAndReset(); } *((work_ + work_index)->read_buffer) = backup; *((work_ + work_index)->read_buffer + recv_result) = backup_2; } /// mainLoop() select() ޤ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" int main_loop_select(fd_set &fd_set_read) { int file_descriptor_maximum = file_descriptor_; FD_ZERO(&fd_set_read); FD_SET(file_descriptor_, &fd_set_read); for (int i = 0; i != max_connection_; ++i) { if ((work_ + i)->flag) { FD_SET((work_ + i)->file_descriptor, &fd_set_read); if ((work_ + i)->file_descriptor > file_descriptor_maximum) { file_descriptor_maximum = (work_ + i)->file_descriptor; } } #ifdef SKK_MEMORY_DEBUG skk_memory_debug_check_((work_ + i)->read_buffer - SKK_MEMORY_DEBUG_MARGIN_SIZE); skk_memory_debug_check_((work_ + i)->read_buffer - SKK_MEMORY_DEBUG_MARGIN_SIZE + SKK_MEMORY_DEBUG_MARGIN_SIZE + READ_BUFFER_SIZE); #endif // SKK_MEMORY_DEBUG } int n = select(file_descriptor_maximum + 1, &fd_set_read, 0, 0, 0); if ((n == -1) && (errno == EINTR)) { syslog_.printf(1, SkkSyslog::LEVEL_INFO, "caught signal"); } return n; } int main_loop_select_polling(fd_set &fd_set_read) { int file_descriptor_maximum = file_descriptor_; FD_ZERO(&fd_set_read); FD_SET(file_descriptor_, &fd_set_read); for (int i = 0; i != max_connection_; ++i) { if ((work_ + i)->flag) { FD_SET((work_ + i)->file_descriptor, &fd_set_read); if ((work_ + i)->file_descriptor > file_descriptor_maximum) { file_descriptor_maximum = (work_ + i)->file_descriptor; } } #ifdef SKK_MEMORY_DEBUG skk_memory_debug_check_((work_ + i)->read_buffer - SKK_MEMORY_DEBUG_MARGIN_SIZE); skk_memory_debug_check_((work_ + i)->read_buffer - SKK_MEMORY_DEBUG_MARGIN_SIZE + SKK_MEMORY_DEBUG_MARGIN_SIZE + READ_BUFFER_SIZE); #endif // SKK_MEMORY_DEBUG } struct timeval timeout; timeout.tv_sec = 3; timeout.tv_usec = 0; int n = select(file_descriptor_maximum + 1, &fd_set_read, 0, 0, &timeout); if ((n == -1) && (errno == EINTR)) { syslog_.printf(1, SkkSyslog::LEVEL_INFO, "caught signal"); } return n; } #pragma GCC diagnostic pop /// mainLoop() Ǽιå򤷤ޤ int main_loop_check_reload_dictionary(SkkDictionary *skk_dictionary, int skk_dictionary_length, const char * const *dictionary_filename_table, bool dictionary_check_update_flag) { int result = 0; if (dictionary_check_update_flag && dictionary_filename_table) { int total_read_size = 0; for (int i = 0; i != max_connection_; ++i) { if ((work_ + i)->flag) { total_read_size += (work_ + i)->read_process_index; } } if (total_read_size == 0) { for (int i = 0; i != skk_dictionary_length; ++i) { if (*(dictionary_filename_table + i)) { bool update_flag; if ((skk_dictionary + i)->isUpdateDictionary(update_flag, *(dictionary_filename_table + i))) { if (update_flag) { ++result; (skk_dictionary + i)->close(); (skk_dictionary + i)->open(*(dictionary_filename_table + i)); syslog_.printf(1, SkkSyslog::LEVEL_INFO, "dictionary \"%s\" (index = %d) updated", *(dictionary_filename_table + i), i); } } else { syslog_.printf(1, SkkSyslog::LEVEL_WARNING, "dictionary \"%s\" (index = %d) check failed", *(dictionary_filename_table + i), i); } } } } } return result; } /// mainLoop() accept() ޤ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" bool main_loop_accept(fd_set &fd_set_read, int select_result) { socklen_t length = sizeof(struct sockaddr_in); if (FD_ISSET(file_descriptor_, &fd_set_read)) { int counter = 0; for (int i = 0; i != max_connection_; ++i) { if ((work_ + i)->flag == false) { int fd = accept(file_descriptor_, reinterpret_cast(&(work_ + i)->socket), reinterpret_cast(&length)); if (fd == -1) { // goto ERROR_BREAK; // return false; } else { syslog_.printf(2, SkkSyslog::LEVEL_INFO, "connected from %s", inet_ntoa((work_ + i)->socket.sin_addr)); (work_ + i)->flag = true; (work_ + i)->file_descriptor = fd; ++counter; if (counter >= select_result) { break; } } } } if (counter == 0) { struct sockaddr_in dummy_socket; int dummy_fd = accept(file_descriptor_, reinterpret_cast(&dummy_socket), reinterpret_cast(&length)); if (dummy_fd == -1) { return false; } close(dummy_fd); } } return true; } /// MainLoop() recv() ٤ɤ֤ޤ bool main_loop_is_recv(int work_index, fd_set &fd_set_read) { if ((work_ + work_index)->flag && FD_ISSET((work_ + work_index)->file_descriptor, &fd_set_read)) { return true; } else { return false; } } #pragma GCC diagnostic pop /// MainLoop() recv() read_buffer ɤ߹ߤޤ read_buffer 򻲾ȤƤϤʤʤʤп֤ޤ bool main_loop_recv(int work_index, int &recv_result, bool &error_break_flag) { bool result = true; recv_result = SkkSocket::receive((work_ + work_index)->file_descriptor, (work_ + work_index)->read_buffer + (work_ + work_index)->read_process_index, MIDASI_SIZE + MIDASI_TERMINATOR_SIZE - (work_ + work_index)->read_process_index); error_break_flag = false; if (recv_result == -1) { switch (errno) { default: error_break_flag = true; goto ERROR_BREAK; case EAGAIN: case EINTR: case ECONNABORTED: case ECONNREFUSED: case ECONNRESET: break; } (work_ + work_index)->reset(); } else if (recv_result == 0) { close((work_ + work_index)->file_descriptor); (work_ + work_index)->reset(); (work_ + work_index)->file_descriptor = 0; (work_ + work_index)->flag = false; } else if (recv_result > MIDASI_SIZE + MIDASI_TERMINATOR_SIZE) { // recv() ǻꤷɤ߹ߥϡӤͤ꾮Τǡ // 뤳ȤϤޤ DEBUG_ASSERT(0); (work_ + work_index)->reset(); } else { result = false; } ERROR_BREAK: return result; } /// mainLoop() "0" ν򤷤ޤ void main_loop_0(int work_index) { close((work_ + work_index)->file_descriptor); (work_ + work_index)->file_descriptor = 0; (work_ + work_index)->flag = false; } /// mainLoop() "2" ν򤷤ޤ void main_loop_2(int work_index, const char *version_string, int version_string_size) { if (!send((work_ + work_index)->file_descriptor, version_string, version_string_size - 1)) { (work_ + work_index)->closeAndReset(); } } /// mainLoop() "3" ν򤷤ޤ void main_loop_3(int work_index) { const char hostname[] = "hostname:addr:...: "; if (!send((work_ + work_index)->file_descriptor, hostname, sizeof(hostname) - 1)) { (work_ + work_index)->closeAndReset(); } } /// mainLoop() ʥޥɤν򤷤ޤ void main_loop_illegal_command(int work_index) { const char result[] = "0\n"; if (!send((work_ + work_index)->file_descriptor, result, sizeof(result) - 1)) { (work_ + work_index)->closeAndReset(); } } /// ХåեꥻåȤ٤ʤп֤ޤ /** * ֤Τ 1 ٤ recv() ʤäǤ * * ¾ʥץȥʤɤǤХåեϥꥻåȤ٤ʤΤǡ * ޤ * * recv ʸ '\n' ޤˤ⤫餺 ' ' ¸ߤʤ * ץȥȤ illegal_protocol_flag 򿿤ˤޤΤȤƤӽ * ¦Ǥ "4" ֤٤Ǥ */ bool main_loop_check_buffer(int work_index, int recv_result, bool &illegal_protocol_flag) { DEBUG_ASSERT(recv_result > 0); DEBUG_ASSERT(recv_result <= MIDASI_SIZE + MIDASI_TERMINATOR_SIZE); bool result = true; illegal_protocol_flag = false; bool cr_found_flag = false; bool space_found_flag = false; int body_bytes = 0; if (recv_result >= 2) { for (int h = 1; h <= recv_result - 1; ++h) { int c = static_cast(static_cast(*((work_ + work_index)->read_buffer + h))); if ((c == '\n') || (c == ' ') || (c == '\0')) { if (body_bytes == 0) { illegal_protocol_flag = true; } break; } else { ++body_bytes; } } } if (!illegal_protocol_flag) { for (int h = recv_result - 1; h >= 0; --h) { int tmp = (work_ + work_index)->read_process_index + h; int c = static_cast(static_cast(*((work_ + work_index)->read_buffer + tmp))); if (c == '\n') { cr_found_flag = true; } if (c == ' ') { space_found_flag = true; break; } } if (!space_found_flag) { if (cr_found_flag) { // '\n' ޤˤ⤫餺 ' ' ¸ߤʤΤʥץȥǤ illegal_protocol_flag = true; } else { // ü '\n' ' ' ¸ߤʤȤȤ recv() ɤڤƤ // ᡢХåեꥻåȤޤ result = false; } } } return result; } /// MainLoop() ɬפʤХХåեꥻåȤ򤪤ʤޤ void main_loop_check_buffer_reset(int work_index, int recv_result, bool buffer_reset_flag) { if (buffer_reset_flag) { (work_ + work_index)->reset(); } else { (work_ + work_index)->read_process_index += recv_result; if ((work_ + work_index)->read_process_index > MIDASI_SIZE + MIDASI_TERMINATOR_SIZE) { // ʥꥯȤǤ (work_ + work_index)->reset(); } } } /// MainLoop() Υեʥ饤Ǥ bool main_loop_finalize() { for (int i = 0; i != max_connection_; ++i) { if ((work_ + i)->flag) { close((work_ + i)->file_descriptor); (work_ + i)->file_descriptor = 0; (work_ + i)->flag = false; } } close(file_descriptor_); return true; } protected: enum { // ǥ󥳡ɻƬ \\1 դ 1 Х礭ʤǽ // ޤ MIDASI_SIZE = 1 + 510, // ФΥߥ͡Ȥʤ륹ڡ (0x20) ΥǤ MIDASI_TERMINATOR_SIZE = 1, // main_loop_send_not_found() ʤɤǥޡΰѤ뤿ᡢФ // ɬפǤ MIDASI_MARGIN_SIZE = 4, // struct Work read_buffer ΥǤ READ_BUFFER_SIZE = MIDASI_SIZE + MIDASI_TERMINATOR_SIZE + MIDASI_MARGIN_SIZE }; struct Work { private: Work(Work &source); Work& operator=(Work &source); public: Work() : read_buffer(0), file_descriptor(0), read_process_index(0), socket(), flag(false) { SkkUtility::clearMemory(&socket, sizeof(socket)); } void reset() { read_process_index = 0; *(read_buffer + 0) = '\0'; } void closeAndReset() { close(file_descriptor); reset(); file_descriptor = 0; flag = false; } char *read_buffer; int file_descriptor; int read_process_index; struct sockaddr_in socket; bool flag; }; SkkSyslog syslog_; Work *work_; int port_; const char *address_; int max_connection_; int listen_queue_; int file_descriptor_; }; } #endif // SKK_SERVER_H yaskkserv-1.1.0/source/skk/skk_simple_string.hpp000066400000000000000000001221331262716711600220760ustar00rootroot00000000000000/* Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012, 2013, 2014 Tadashi Watanabe This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef SKK_SIMPLE_STRING_HPP #define SKK_SIMPLE_STRING_HPP #include "skk_architecture.hpp" #ifdef YASKKSERV_DEBUG #define SKK_SIMPLE_STRING_DEBUG_BUFFER #endif // YASKKSERV_DEBUG namespace YaSkkServ { /// ñʸ󥯥饹Ǥ /** * 󥹥ȥ饯ǻꤷХåեʸɲäǴޤ * * ХåեϰʲΤ褦ʹ¤ˤʤäƤޤ * *
+--------+----------------+--------+
| MARGIN | ʸХåե | MARGIN |
+--------+----------------+--------+
* * MARGIN ϥǥХåʤɤ˻ѤΰǤΤ᰷ȤΤǤʸ * Ĺϡ󥹥ȥ饯ǻꤷХåեʬʤΤȤʤ * * *

append, appendFast() overwrite

* * append ʸɲä \\0 ǽüޤХåե˼ޤ뤫 * ɤåơɲäǤʤв⤻֤ޤ * appendFast append ƱͤǤɲòǽɤ򤷤ޤ * isAppendSize() ʤɤǻ˸ڤɬפޤ * * overwrite ϻ֤ʸ񤭤ǤΤȤ \\0 * 񤭤뤳ȤϤޤ󡣤Ĥޤ \\0 ǽüޤ * * ޤȤȰʲΤ褦ˤʤޤ * *
*
append *
ʸɲá \\0 ɲáɲååꡣ *
appendFast *
ʸɲá \\0 ɲáɲååʤ isAppendSize() ʤɤǻ˥åɬס *
overwrite *
ʸ񤭡 \\0 ˿ʤ *
* * *

ʸХåե MARGIN

* * ̾ʸü \\0 ʸХåե֤ޤ * DEBUG_PARANOIA_ASSERT() ǤʸХåե˼ޤʤ祢 * ޤξǡ MARGIN Ƭ 1 ХȤ 0 Ǥ뤳Ȥݾ * ޤ * * Ĥޤꡢ̾ϽüǤ \\0 ʸХåե֤ʤФʤ * 󤬡 \\0 ʸХåե˼ޤ꤭ʤä (̾ * ꤨޤ) Ǥ MARGIN Ƭ 0 Ǥ뤳Ȥ顢ɬʸ * Ͻü뤳Ȥݾڤޤ * * *

󥹥ȥ饯

* * ХåեؤΥݥ󥿤Ϥ硢ݥ󥿤 0 ΤȤȤͭ * ХȤޤ * * *

¾᥽åɤδư

* * ʤɤʾ硢ȤͭʤХȤޤ */ class SkkSimpleString { SkkSimpleString(SkkSimpleString &source); SkkSimpleString& operator=(SkkSimpleString &source); public: enum { MARGIN_SIZE = 4, STRING_SIZE_MAXIMUM = 8 * 1024 }; enum Flag { FLAG_RIGHT, FLAG_RIGHT_ZERO, FLAG_LEFT, }; protected: void update_string_size_from_current() { #ifdef YASKKSERV_DEBUG check_margin_for_debug(); #endif // YASKKSERV_DEBUG string_size_ = static_cast(current_ - get_buffer()); } void update_string_size_by_strlen() { #ifdef YASKKSERV_DEBUG check_margin_for_debug(); #endif // YASKKSERV_DEBUG string_size_ = 0; const char *p = get_buffer(); for (int i = 0; i < getValidBufferSize(); ++i) { if (*(p + i) == '\0') { string_size_ = i; return; } } DEBUG_ASSERT(0); } void fill_margin_for_debug() { #ifdef YASKKSERV_DEBUG *(buffer_ + 0) = 0; *(buffer_ + buffer_size_ - MARGIN_SIZE + 0) = 0; for (int i = 1; i != MARGIN_SIZE; ++i) { *(buffer_ + i) = static_cast(1 + i); *(buffer_ + buffer_size_ - MARGIN_SIZE + i) = static_cast(1 + i); } #endif // YASKKSERV_DEBUG } void check_margin_for_debug() const { #ifdef YASKKSERV_DEBUG DEBUG_ASSERT(*(buffer_ + 0) == 0); DEBUG_ASSERT(*(buffer_ + buffer_size_ - MARGIN_SIZE + 0) == 0); for (int i = 1; i != MARGIN_SIZE; ++i) { DEBUG_ASSERT(*(buffer_ + i) == 1 + i); DEBUG_ASSERT(*(buffer_ + buffer_size_ - MARGIN_SIZE + i) == 1 + i); } #endif // YASKKSERV_DEBUG } char *get_buffer() const { return buffer_ + MARGIN_SIZE; } void initialize_buffer() { fill_margin_for_debug(); // ʸƬ 0 ˡ *get_buffer() = '\0'; // ޡƬ 0 ˤʸΰ褬դξ // ü뤳Ȥݾڤޤ *(buffer_ + buffer_size_ - MARGIN_SIZE) = '\0'; } static int compare_internal(const void *s_1, const void *s_2) { DEBUG_ASSERT_POINTER(s_1); DEBUG_ASSERT_POINTER(s_2); for (int i = 0;; ++i) { int tmp_1 = *(static_cast(s_1) + i); int tmp_2 = *(static_cast(s_2) + i); if (tmp_1 == '\0') { if (tmp_2 == '\0') { return 0; } else { return -(i + 1); } } else if (tmp_2 == '\0') { if (tmp_1 == '\0') { return 0; } else { return i + 1; } } else if (tmp_1 > tmp_2) { return i + 1; } else if (tmp_1 < tmp_2) { return -(i + 1); } } return 0; } static int compare_internal(const void *s_1, const void *s_2, int compare_size) { DEBUG_ASSERT_POINTER(s_1); DEBUG_ASSERT_POINTER(s_2); for (int i = 0; i != compare_size; ++i) { int tmp_1 = *(static_cast(s_1) + i); int tmp_2 = *(static_cast(s_2) + i); if (tmp_1 == '\0') { if (tmp_2 == '\0') { return 0; } else { return -(i + 1); } } else if (tmp_2 == '\0') { if (tmp_1 == '\0') { return 0; } else { return i + 1; } } else if (tmp_1 > tmp_2) { return i + 1; } else if (tmp_1 < tmp_2) { return -(i + 1); } } return 0; } /// ʸΥХȥ֤ޤ˽ü \\0 ϴޤߤޤ /** * \attention * limit ʾεʥǡξ硢Ƿ¬ 0 ֤ޤ * ȤȤͭʤХȤޤ */ static int get_size_internal(const void *p, int limit = 64 * 1024) { const char *tmp = static_cast(p); for (int i = 0; i != limit; ++i) { if (*tmp++ == '\0') { return i; } } DEBUG_ASSERT(0); return 0; } /// ʸ򥳥ԡޤ /** * \attention * c \\0 ꤷƽ񤭹ߡʸǤ뤳ȤǤޤ */ static void overwrite_internal(char c, void *destination) { char *p = static_cast(destination); *p = c; } /// ʸ򥳥ԡޤʸκǸ + 1 ؤݥ󥿤֤ޤ /** * \attention * \\0 ϥԡޤ */ static char *overwrite_internal(const void *source, void *destination, int size) { const char *s = static_cast(source); char *d = static_cast(destination); for (; size > 0; --size) { if (*s == '\0') { break; } *d++ = *s++; } return d; } /// column 10 ʸޤʸκǸ + 1 ؤݥ󥿤֤ޤ /** * column ˴ޤޤޤ * * \attention * column ¿ηɽޤ󡣤ξ硢̤ηϺޤ */ static char *overwrite_internal(void *destination, int scalar, Flag flag = FLAG_LEFT, int column = 11) { static const int table[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, }; int space = (flag == FLAG_RIGHT_ZERO) ? '0' : ' '; int sign; int absolute; const int table_size = sizeof(table)/sizeof(table[0]); char *p = static_cast(destination); bool zero_print_flag = false; bool right_flag = ((flag == FLAG_RIGHT_ZERO) || (flag == FLAG_RIGHT)) ? true : false; DEBUG_ASSERT_RANGE(column, 1, 11); if (scalar < 0) { sign = '-'; absolute = -scalar; } else { sign = 0; absolute = scalar; if (right_flag && (column == 11)) { *p++ = ' '; } } for (int i = table_size - 1; i >= 0; --i) { int d = absolute / table[i]; if (d == 0) { if (zero_print_flag || (i == 0)) { if (i < column) { *p++ = '0'; } } else { if (right_flag) { if (i < column) { *p++ = static_cast(space); } } } } else { if (sign != 0) { if (i < column - 1) { if (column != 11) { --column; if (p != destination) { --p; } } *p++ = static_cast(sign); } sign = 0; } absolute -= d * table[i]; zero_print_flag = true; if (i < column) { *p++ = static_cast('0' + d); } } } return p; } /// column 10 ʸޤʸκǸ + 1 ؤݥ󥿤֤ޤ /** * ȥɥåȤ column ˴ޤޤޤ * * \attention * column ¿ηɽޤ󡣤ξ硢̤ηϺޤ */ static char *overwrite_internal(void *destination, float scalar, int decimal = 1, Flag flag = FLAG_LEFT, int column = 11) { DEBUG_ASSERT_RANGE(column, 2, 11); DEBUG_ASSERT_RANGE(column - 1 - decimal, 1, 9); char *p = static_cast(destination); p = overwrite_internal(p, static_cast(scalar), flag, column - 1 - decimal); *p++ = '.'; int po = 1; for (int i = 0; i != decimal; ++i) { po *= 10; } p = overwrite_internal(p, static_cast(scalar * static_cast(po)) % po, FLAG_RIGHT_ZERO, decimal); return p; } /// column 16 ʸޤʸκǸ + 1 ؤݥ󥿤֤ޤ /** * \attention * column ¿ηɽޤ󡣤ξ硢̤ηϺޤ */ static char *overwrite_internal_hexadecimal(void *destination, int scalar, int column = 8) { char *p = static_cast(destination); DEBUG_ASSERT_RANGE(column, 1, 8); for (int i = column - 1; i >= 0; --i) { int tmp = (scalar >> (i * 4)) & 0xf; if (tmp > 0xa) { *p++ = static_cast('a' - 0xa + tmp); } else { *p++ = static_cast('0' + tmp); } } return p; } public: virtual ~SkkSimpleString() { check_margin_for_debug(); DEBUG_ASSERT_POINTER(buffer_); DEBUG_ASSERT(buffer_size_ != 0); if (dynamic_allocation_flag_) { delete[] buffer_; } #ifdef SKK_SIMPLE_STRING_DEBUG_BUFFER delete[] debug_buffer_; #endif // SKK_SIMPLE_STRING_DEBUG_BUFFER } SkkSimpleString(int buffer_size) : #ifdef SKK_SIMPLE_STRING_DEBUG_BUFFER debug_buffer_(new char[buffer_size]), debug_write_buffer_start_(0), #endif // SKK_SIMPLE_STRING_DEBUG_BUFFER buffer_(new char[buffer_size]), current_(get_buffer()), buffer_size_(buffer_size), string_size_(0), dynamic_allocation_flag_(true) { DEBUG_ASSERT(buffer_size_ != 0); initialize_buffer(); } SkkSimpleString(void *buffer, int buffer_size) : #ifdef SKK_SIMPLE_STRING_DEBUG_BUFFER debug_buffer_(new char[buffer_size]), debug_write_buffer_start_(0), #endif // SKK_SIMPLE_STRING_DEBUG_BUFFER buffer_(static_cast(buffer)), current_(get_buffer()), buffer_size_(buffer_size), string_size_(0), dynamic_allocation_flag_(false) { DEBUG_ASSERT(buffer_size_ != 0); if (buffer_ == 0) { DEBUG_ASSERT(0); } else { initialize_buffer(); } } template SkkSimpleString(char (&array)[N]) : #ifdef SKK_SIMPLE_STRING_DEBUG_BUFFER debug_buffer_(new char[N]), debug_write_buffer_start_(0), #endif // SKK_SIMPLE_STRING_DEBUG_BUFFER buffer_(array), current_(get_buffer()), buffer_size_(N), string_size_(0), dynamic_allocation_flag_(false) { DEBUG_ASSERT(buffer_size_ != 0); if (buffer_ == 0) { DEBUG_ASSERT(0); } else { fill_margin_for_debug(); *(buffer_ + 0) = '\0'; *(buffer_ + buffer_size_ - MARGIN_SIZE) = '\0'; } } /// append() ϥ᥽åɤΥǥåꤷޤ /** * \attention * ХåեȤޤ魯 setAppendIndex(0) Ȥ reset() Ѥ * Ƥ * * \attention * index ꤷϲ⤻ȴޤǥХåӥɤǤ * Ȥޤ */ void setAppendIndex(int index) { if ((index < 0) || (index >= buffer_size_ - MARGIN_SIZE * 2 - 1)) { DEBUG_ASSERT(0); } else { current_ = get_buffer() + index; update_string_size_from_current(); } } /// ֤ꥻåȤʸꤷޤ /** * ХåեȤޤ路ʣʸۤ뤿˻Ȥޤ * * \verbatim ex.) char buffer[256]; SimpleString object(buffer); object.append("ABC="); object.append(999); PRINT(object.getBuffer()); object.reset(); object.append("DEF="); object.append(999); PRINT(object.getBuffer()); \endverbatim */ void reset() { current_ = get_buffer(); *current_ = '\0'; string_size_ = 0; } /// ʸХåեؤΥݥ󥿤֤ޤ /** * ʸϡܥ᥽åɤǼɬפޤ */ const char *getBuffer() const { return get_buffer(); } /// ʸХåեؤΥݥ󥿤֤ޤ /** * append() Ϥΰ֤ؼ¹Ԥޤ */ const char *getCurrentBuffer() const { return current_; } /// Хåեľܽ񤭹ľ˽񤭹ޤΰޤɬڥȤʤ endWriteBuffer() ƤɬפޤΰؤƤе֤ޤǥХåӥɤǤϥǡڥѤ˥ǡХååפޤ /** * \attention * ΰؤƤ硢ǥХåӥɤǤϥȤޤ */ bool beginWriteBuffer(const char *start, int reserve_size) { const char *p = getBuffer(); #ifdef SKK_SIMPLE_STRING_DEBUG_BUFFER DEBUG_ASSERT(debug_write_buffer_start_ == 0); // Хåեޤ뤴ȥԡ debug_write_buffer_start_ = start; memcpy(debug_buffer_, buffer_, buffer_size_); #endif // SKK_SIMPLE_STRING_DEBUG_BUFFER if ((start < p) || (start + reserve_size > p + getValidBufferSize())) { DEBUG_PRINTF("start=%p getBuffer()=%p (start+reserve_size)=%p (getBuffer()+getValidBufferSize())=%p\n", start, getBuffer(), start + reserve_size, p + getValidBufferSize()); DEBUG_ASSERT(0); return false; } return true; } /// Хåեľܽ񤭹ΰꤷޤǥХåӥɤǤϥǡڥäϥȤޤ /** * \attention * ꡼ӥɤǤϲ⤷ޤ֤ͤޤ󡣤ϡоݤ̿Ūʥ顼Ǥ뤿Ǥ */ void endWriteBuffer(int write_size) { #ifdef SKK_SIMPLE_STRING_DEBUG_BUFFER const char *p = getBuffer(); if ((debug_write_buffer_start_ < p) || (debug_write_buffer_start_ + write_size > p + getValidBufferSize())) { DEBUG_PRINTF("start=%p getBuffer()=%p (start+write_size)=%p (getBuffer()+getValidBufferSize())=%p\n", debug_write_buffer_start_, getBuffer(), debug_write_buffer_start_ + write_size, p + getValidBufferSize()); DEBUG_ASSERT(0); } DEBUG_ASSERT_POINTER(debug_write_buffer_start_); // Хåեΰ賰Ƭն const char *before_a = buffer_; const char *before_b = debug_buffer_; DEBUG_ASSERT(before_a <= debug_write_buffer_start_); for (;;) { if (before_a >= debug_write_buffer_start_) { break; } if (*before_a++ != *before_b++) { DEBUG_ASSERT(0); } } // Хåեΰ賰üն size_t offset = debug_write_buffer_start_ - buffer_; const char *after_a = debug_write_buffer_start_ + MARGIN_SIZE + write_size; const char *after_b = debug_buffer_ + offset + MARGIN_SIZE + write_size; DEBUG_ASSERT(after_a <= buffer_ + buffer_size_); // DEBUG_PRINTF("a=%p b()=%p (buffer_ + buffer_size_)=%p\n", // after_a, // after_b, // buffer_ + buffer_size_); // DEBUG_PRINTF("write_size=%d\n", write_size); for (;;) { if (after_a >= buffer_ + buffer_size_) { break; } if (*after_a++ != *after_b++) { DEBUG_PRINTF("0x%02x : 0x%02x\n", *(after_a - 1) & 0xff, *(after_b - 1) & 0xff); DEBUG_ASSERT(0); } } debug_write_buffer_start_ = 0; #else // SKK_SIMPLE_STRING_DEBUG_BUFFER (void)write_size; #endif // SKK_SIMPLE_STRING_DEBUG_BUFFER } /// ͭʥХåե֤ޤ /** * MARGIN Хåե֤ޤ */ int getValidBufferSize() const { return buffer_size_ - MARGIN_SIZE * 2; } /// ʸĹ֤ޤʸĹ˽ü \\0 ϴޤߤޤ int getSize() const { return string_size_; } /// ХåեɲäǤ \\0 Хȿ֤ޤͤϼºݤ̤ \\0 ʬ 1 ХȾʤʤޤ int getRemainSize() const { const int terminator_size = 1; int remain_size = static_cast(buffer_ + buffer_size_ - MARGIN_SIZE - current_ - terminator_size); DEBUG_ASSERT_RANGE(remain_size, 0, buffer_size_ - MARGIN_SIZE * 2 - 1); return remain_size; } /// ꤷͤʸХåեνüľޤޤ /** * \attention * ʸХåեνüؤϾ \\0 񤭹ޤޤ */ void fillStringBuffer(int c = '\0') { char *p = get_buffer(); for (int i = 0; i != buffer_size_ - MARGIN_SIZE * 2 - 1; ++i) { *p++ = static_cast(c); } *p = '\0'; current_ = p; update_string_size_from_current(); } /// '\0' size ХȤΥǡ append() ǽʤп֤ޤ bool isAppendSize(int size) const { if (getRemainSize() < size) { return false; } else { return true; } } bool isAppend(SkkSimpleString &string) const { return isAppendSize(string.getSize()); } /// ֤ʸǤޤ /** * \attention */ void terminate(int index) { char *d = get_buffer() + index; #ifdef YASKKSERV_DEBUG_PARANOIA const int terminator_size = 1; int size = static_cast(buffer_ + buffer_size_ - MARGIN_SIZE - d - terminator_size); DEBUG_ASSERT_RANGE(size, 1, buffer_size_ - MARGIN_SIZE * 2 - 1); #endif // YASKKSERV_DEBUG_PARANOIA if (index >= getSize()) { DEBUG_ASSERT(0); } else { overwrite_internal('\0', d); update_string_size_by_strlen(); } } #if 0 /// ֤ʸ񤭤ޤ /** * \attention * c \\0 ꤷƽ񤭹ߡʸǤ뤳ȤǤޤ index * ߤʸ˼ޤʤϲ⤷ޤ󡣥Ȥͭʤ * Ȥޤ */ void overwrite(char c, int index) { char *d = get_buffer() + index; #ifdef YASKKSERV_DEBUG_PARANOIA const int terminator_size = 1; int size = static_cast(buffer_ + buffer_size_ - MARGIN_SIZE - d - terminator_size); DEBUG_ASSERT_RANGE(size, 1, buffer_size_ - MARGIN_SIZE * 2 - 1); #endif // YASKKSERV_DEBUG_PARANOIA if (index >= getSize()) { DEBUG_ASSERT(0); } else { overwrite_internal(c, d); update_string_size_by_strlen(); } } /// ֤ʸ񤭤ޤ /** * \attention * ʸ p ¦ \\0 ϥԡޤ */ void overwrite(const void *p, int index) { char *d = get_buffer() + index; const int terminator_size = 1; int size = static_cast(buffer_ + buffer_size_ - MARGIN_SIZE - d - terminator_size); DEBUG_ASSERT_RANGE(size, 1, buffer_size_ - MARGIN_SIZE * 2 - 1); #ifdef YASKKSERV_DEBUG_PARANOIA int tmp = static_cast(buffer_ + buffer_size_ - MARGIN_SIZE - (d + getSize(p) - 1) - terminator_size); DEBUG_ASSERT_RANGE(tmp, 1, buffer_size_ - MARGIN_SIZE * 2 - 1); #endif // YASKKSERV_DEBUG_PARANOIA overwrite_internal(p, d, size); } /// ֤ʸ񤭤ޤʸ p copy_size Хʬޤ \\0 դޤɲäޤ /** * \attention * ʸ p ¦ \\0 ϥԡޤ * * ̾ overwrite() Ȱۤʤꡢ p \\0 ǽüƤɬפޤ */ void overwrite(const void *p, int index, int copy_size) { char *d = get_buffer() + index; const int terminator_size = 1; int size = static_cast(buffer_ + buffer_size_ - MARGIN_SIZE - d - terminator_size); DEBUG_ASSERT_RANGE(size, 1, buffer_size_ - MARGIN_SIZE * 2 - 1); #ifdef YASKKSERV_DEBUG_PARANOIA int debug_size = copy_size; int tmp = static_cast(buffer_ + buffer_size_ - MARGIN_SIZE - (d + debug_size - 1) - terminator_size); DEBUG_ASSERT_RANGE(tmp, 1, buffer_size_ - MARGIN_SIZE * 2 - 1); #endif // YASKKSERV_DEBUG_PARANOIA copy_size = (copy_size < size) ? copy_size : size; overwrite_internal(p, d, size); } #endif /// ʸɲäޤ /** * \attention * ʸ \\0 ǽüޤ */ void appendFast(const SkkSimpleString &object) { appendFast(object.getBuffer()); } /// ʸɲäޤ /** * \attention * ʸ \\0 ǽüޤ */ void appendFast(const void *p) { #ifdef YASKKSERV_DEBUG_PARANOIA const int terminator_size = 1; const int append_terminator_legth = 1; int tmp = static_cast(buffer_ + buffer_size_ - MARGIN_SIZE - (current_ + get_size_internal(p) + append_terminator_legth - 1) - terminator_size); DEBUG_ASSERT_RANGE(tmp, 0, buffer_size_ - MARGIN_SIZE * 2 - 1); DEBUG_ASSERT_RANGE(get_size_internal(p), 0, buffer_size_ - MARGIN_SIZE * 2 - 1); #endif // YASKKSERV_DEBUG_PARANOIA current_ = overwrite_internal(p, current_, getRemainSize()); *current_ = '\0'; update_string_size_from_current(); } /// ʸɲäޤʸ p copy_size Хʬޤ \\0 դޤɲäޤɲä˼Ԥʤе֤ޤ /** * \attention * ̾ append() Ȱۤʤꡢ p \\0 ǽüƤɬפޤ */ bool append(const void *p, int copy_size) { if (getRemainSize() < copy_size) { return false; } current_ = overwrite_internal(p, current_, copy_size); *current_ = '\0'; update_string_size_from_current(); return true; } /// ʸɲäޤ bool append(char c) { if (getRemainSize() < 1) { return false; } if (c == '\0') { *current_ = c; } else { *current_++ = c; *current_ = '\0'; } update_string_size_from_current(); return true; } void appendFast(char c) { #ifdef YASKKSERV_DEBUG_PARANOIA const int terminator_size = 1; const int append_terminator_size = 1; int tmp = static_cast(buffer_ + buffer_size_ - MARGIN_SIZE - (current_ + 1 + append_terminator_size - 1) - terminator_size); DEBUG_ASSERT_RANGE(tmp, 0, buffer_size_ - MARGIN_SIZE * 2 - 1); #endif // YASKKSERV_DEBUG_PARANOIA if (c == '\0') { *current_ = c; } else { *current_++ = c; *current_ = '\0'; } update_string_size_from_current(); } /// scalar 10 ʸѴɲäޤ /** * \attention * ʸ \\0 ǽüޤ */ bool append(int scalar, Flag flag = FLAG_LEFT, int column = 11) { #ifdef YASKKSERV_DEBUG_PARANOIA const int append_terminator_size = 1; DEBUG_ASSERT_RANGE(getRemainSize(), 11 + append_terminator_size, buffer_size_ - MARGIN_SIZE * 2 - 1); #endif // YASKKSERV_DEBUG_PARANOIA if (getRemainSize() <= 11 + 1) { return false; } current_ = overwrite_internal(current_, scalar, flag, column); *current_ = '\0'; update_string_size_from_current(); return true; } bool append(float scalar, int decimal, Flag flag = FLAG_LEFT, int column = 11) { #ifdef YASKKSERV_DEBUG_PARANOIA const int append_terminator_size = 1; DEBUG_ASSERT_RANGE(getRemainSize(), 11 + append_terminator_size, buffer_size_ - MARGIN_SIZE * 2 - 1); #endif // YASKKSERV_DEBUG_PARANOIA if (getRemainSize() <= 11 + 1) { return false; } current_ = overwrite_internal(current_, scalar, decimal, flag, column); *current_ = '\0'; update_string_size_from_current(); return true; } /// scalar 16 ʸѴɲäޤ /** * \attention * ʸ \\0 ǽüޤ */ bool appendHexadecimal(int scalar, int column = 8) { #ifdef YASKKSERV_DEBUG_PARANOIA const int append_terminator_size = 1; DEBUG_ASSERT_RANGE(getRemainSize(), 8 + append_terminator_size, buffer_size_ - MARGIN_SIZE * 2); #endif // YASKKSERV_DEBUG_PARANOIA if (getRemainSize() <= 8 + 1) { return false; } current_ = overwrite_internal_hexadecimal(current_, scalar, column); *current_ = '\0'; update_string_size_from_current(); return true; } /// strncmp(3) ƱͤʸӤޤ /** * ʬȤΥ֥Ȥʸ󤬰٤ơ -1 ʲ * 0 礭 1 ʾ֤ޤ */ int compare(SkkSimpleString &object) { return compare_internal(getBuffer(), object.getBuffer()); } int compare(const char *p) { return compare_internal(getBuffer(), p); } int compare(const char *p, int size) { return compare_internal(getBuffer(), p, size); } /// ʸ 1 ʸ֤ޤ /** * index ϰϳʤ \\0 ֤ޤ * * \attention * index ϰϳξϥ˿줺ʽȤưޤ * ȤʤȤդɬפǤ */ char getCharacter(int index) const { if ((index >= getSize()) || (index < 0)) { return '\0'; } return *(getBuffer() + index); } template char getCharacter() const { if (index == 0) { return *getBuffer(); } else { return getCharacter(index); } } /// ʸ c Ʊʤйʸޤ repeat_flag ʤо郎Ω¤ޤʸ֤ޤ /** * c 0 ξ硢ԥɤޤԥɤ \\r ޤ \\n * Ȥʤޤ DOS βԥɤʤɤ̻뤷ʤΤǡμ¤˲ԥ * ɤˤ repeat_flag 򿿤ˤɬפޤ */ int chomp(char c = 0, bool repeat_flag = true) { int index = getSize() - 1; if (index < 0) { return 0; } int result = 0; char *p = get_buffer(); if (c == 0) { if (repeat_flag) { while ((*(p + index) == '\r') || (*(p + index) == '\n')) { *(p + index) = '\0'; ++result; if (--index <= 0) { break; } } } else { if ((*(p + index) == '\r') || (*(p + index) == '\n')) { *(p + index) = '\0'; ++result; } } } else { if (repeat_flag) { while (*(p + index) == c) { *(p + index) = '\0'; ++result; if (--index <= 0) { break; } } } else { if (*(p + index) == c) { *(p + index) = '\0'; ++result; } } } update_string_size_by_strlen(); return result; } /// base_size ХȤʸ base search_size ХȤ search ˤ곫ϤƤп֤ޤ /** * üɤȤ ' ' ޤ '\0' ǧޤ */ static bool startWith(const char *base, const char *search, int base_size, int search_size) { DEBUG_ASSERT_POINTER(base); DEBUG_ASSERT_POINTER(search); DEBUG_ASSERT(base_size > 0); DEBUG_ASSERT(search_size > 0); for (int i = 0; ; ++i) { if (i >= search_size) { return true; } int s_2 = *(reinterpret_cast(search + i)); if ((s_2 == ' ') || (s_2 == '\0')) { return true; } if (i >= base_size) { return false; } int s_1 = *(reinterpret_cast(base + i)); if (s_1 != s_2) { return false; } if ((s_1 == ' ') || (s_1 == '\0')) { return false; } } return false; // NOTREACHED } /// base_size ХȤʸ base c ޤޤƤп֤ޤ /** * üɤȤ ' ' ޤ '\0' ǧޤ */ static bool search(const char *base, char c, int base_size) { DEBUG_ASSERT_POINTER(base); DEBUG_ASSERT(base_size > 0); for (int i = 0; ; ++i) { if (i >= base_size) { return false; } int s_1 = *(reinterpret_cast(base + i)); if (s_1 == c) { return true; } if ((s_1 == ' ') || (s_1 == '\0')) { return false; } } return false; // NOTREACHED } /// strncmp(3) ƱͤʸӤޤ /** * s_1 s_2 ٤ơ -1 ʲ 0 * 1 ʾ֤ޤ */ static int compare(const void *s_1, const void *s_2) { return compare_internal(s_1, s_2); } static int compare(const void *s_1, const void *s_2, int buffer_size) { return compare_internal(s_1, s_2, buffer_size); } protected: #ifdef SKK_SIMPLE_STRING_DEBUG_BUFFER char *debug_buffer_; const char *debug_write_buffer_start_; #endif // SKK_SIMPLE_STRING_DEBUG_BUFFER char *buffer_; char *current_; int buffer_size_; int string_size_; bool dynamic_allocation_flag_; }; } #endif // SKK_SIMPLE_STRING_HPP yaskkserv-1.1.0/source/skk/skk_utility.hpp000066400000000000000000001225721262716711600207310ustar00rootroot00000000000000/* Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012, 2013, 2014 Tadashi Watanabe This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef SKK_UTILITY_HPP #define SKK_UTILITY_HPP #include "skk_architecture.hpp" #include "skk_utility_architecture.hpp" #include "skk_simple_string.hpp" namespace YaSkkServ { namespace SkkUtility { inline int getStringOkuriAriLength() { const char data[] = ";; okuri-ari entries.\n"; return sizeof(data); } inline int getStringOkuriNasiLength() { const char data[] = ";; okuri-nasi entries.\n"; return sizeof(data); } /// ";; okuri-ari entries.\n" Ȥʸ˰פп֤ޤ inline bool isStringOkuriAri(const char *p) { DEBUG_ASSERT_POINTER(p); const char data[] = ";; okuri-ari entries.\n"; for (int i = 0; i != sizeof(data) - 1; ++i) { if (*(p + i) != data[i]) { return false; } } return true; } /// ";; okuri-nasi entries.\n" Ȥʸ˰פп֤ޤ inline bool isStringOkuriNasi(const char *p) { DEBUG_ASSERT_POINTER(p); const char data[] = ";; okuri-nasi entries.\n"; for (int i = 0; i != sizeof(data) - 1; ++i) { if (*(p + i) != data[i]) { return false; } } return true; } enum { // ФϺǤ 510 + (+ \\1 ڡ佪üɤʤ) // ȤǤ뤳ȤθƤޤ ENCODED_MIDASI_BUFFER_SIZE = 512 + 16, MIDASI_DECODE_HIRAGANA_BUFFER_SIZE = 1024 }; /// ڡޤ \\0 ǥߥ͡Ȥ줿 source 򥨥󥳡ɤޤ󥳡ɸΥХȥ֤ޤ󥳡ɤ줿ʸϥߥ͡Ȥޤ󡣥󥳡ɤ˼Ԥ 0 ֤ޤ inline int encodeHiragana(const char *source, char *destination, int size) { DEBUG_ASSERT_POINTER(source); DEBUG_ASSERT_POINTER(destination); int result = 0; for (int i = 0; i < size;) { int c = *(source + i) & 0xff; if ((c == ' ') || (c == '\0')) { return result; } if (c == 0xa4) { if (i + 1 >= size) { return 0; } *(destination + result) = *(source + i + 1); i += 2; ++result; } else if ((c >= 0x21) && (c <= 0x7e)) { *(destination + result) = static_cast(c); ++i; ++result; } else { return 0; } } return 0; } /// ' ' (ڡ) ޤ '\\0' ǥߥ͡Ȥ줿󥳡ɤ줿ʸ source ǥɤޤǥɸΥХȥ֤ޤǥɸʸϥߥ͡ȤޤϤ󥳡ɤƤʤʸʸޤޤƤ 0 ֤ޤ inline int decodeHiragana(const char *source, char *destination, int size) { DEBUG_ASSERT_POINTER(source); DEBUG_ASSERT_POINTER(destination); if (*source == '\1') { return 0; } int result = 0; for (int i = 0; i < size; ++i) { int c = *(source + i) & 0xff; if ((c == ' ') || (c == '\0')) { return result; } if (c & 0x80) { *(destination + result++) = static_cast(0xa4); *(destination + result++) = static_cast(c); } else if ((c >= 0x21) && (c <= 0x7e)) { *(destination + result++) = static_cast(c); } else { return 0; } } return 0; } /// ʸ󤬡ꤢפʤп֤ޤʸ '\\0' ' ' ǽüΤȤޤʸξ絶֤ޤ DEBUG_ASSERT ͭʤХȤޤ /** * ꤢפȤʤϰʲ (1.1. || 1.2.) && (2.) ξǤ * * 1.1. 1 ʸܤ '>' or '#' 2 ʸܤܸ * 1.2. 1 ʸܤܸ * * 2. a-z */ inline bool isOkuriAri(const char *p, int size) { DEBUG_ASSERT_POINTER(p); DEBUG_ASSERT(size >= 1); int i = 1; int before_c = *reinterpret_cast(p); if ((before_c == '>') || (before_c == '#')) { ++i; before_c = *reinterpret_cast(p + 1); } if ((before_c & 0x80) == 0) { return false; } for (; i != size; ++i) { int c = *reinterpret_cast(p + i); if ((c == '\0') || (c == ' ')) { break; } before_c = c; } if (before_c & 0x80) { return false; } else { if ((before_c >= 'a') && (before_c <= 'z')) { return true; } else { return false; } } } /// ʸ󤬡ʤפޤϡabbrevפʤп֤ޤʸ '\\0' ' ' ǽüΤȤޤʸξ絶֤ޤ DEBUG_ASSERT ͭʤХȤޤ inline bool isOkuriNasiOrAbbrev(const char *p, int size) { DEBUG_ASSERT_POINTER(p); DEBUG_ASSERT(size >= 1); return !isOkuriAri(p, size); } /// 1 ԸιƬؤΥǥå֤ޤХåեü˺ݤ -1 ֤ޤâԤˤбƤ餺Ԥɬ 1 ʸʾʸޤǤɬפ뤳ȤդɬפǤ inline int getNextLineIndex(const char *p, int index, int size) { DEBUG_ASSERT_POINTER(p); DEBUG_ASSERT(size > 0); while (*(p + index) != '\n') { ++index; if (index >= size) { return -1; } } ++index; if (index >= size) { return -1; } return index; } /// 1 ιƬؤΥǥå֤ޤХåեü˺ݤ -1 ֤ޤХåեƬ˺ݤ 0 ֤ޤâԤˤбƤ餺Ԥɬ 1 ʸʾʸޤǤɬפ뤳ȤդɬפǤ inline int getPreviousLineIndex(const char *p, int index, int size) { DEBUG_ASSERT_POINTER(p); DEBUG_ASSERT(size > 0); while (*(p + index) != '\n') { --index; if (index <= 0) { return 0; } } --index; if (index <= 0) { return 0; } while (*(p + index) != '\n') { --index; if (index <= 0) { return 0; } } ++index; if (index >= size) { return -1; } return index; } /// ƬؤΥǥå֤ޤХåեü˺ݤ -1 ֤ޤХåեƬ˺ݤ 0 ֤ޤâԤˤбƤ餺Ԥɬ 1 ʸʾʸޤǤɬפ뤳ȤդɬפǤ inline int getBeginningOfLineIndex(const char *p, int index, int size) { DEBUG_ASSERT_POINTER(p); DEBUG_ASSERT(size > 0); if (*(p + index) == '\n') { --index; if (index <= 0) { return 0; } } while (*(p + index) != '\n') { --index; if (index <= 0) { return 0; } } ++index; if (index >= size) { return -1; } return index; } /// index Ƭ֤ˤȤơ destination ءָФפ򥳥ԡޤԡʸ \\0 ǥߥ͡Ȥޤߥ͡ޤޤʤԡХȿ֤ޤԡ˼Ԥ 0 ֤ޤ /** * ԡ˼Ԥ DEBUG_ASSERT ͭʤХȤޤ */ inline int copyMidasi(const char *p, int index, int size, char *destination, int destination_size) { DEBUG_ASSERT_POINTER(p); DEBUG_ASSERT_POINTER(destination); DEBUG_ASSERT(size > 0); DEBUG_ASSERT(destination_size > 0); const int margin = 8; for (int i = 0; i < destination_size - margin; ++i) { if ((index + i >= size) || (i >= destination_size - margin)) { DEBUG_PRINTF("index=%d size=%d destination_size=%d\n", index, size, destination_size); DEBUG_ASSERT(0); break; } if (*(p + index + i) == ' ') { *(destination + i) = '\0'; return i; } *(destination + i) = *(p + index + i); } DEBUG_ASSERT(0); return 0; } /// index Ƭ֤ˤȤơ destination ءѴʸפ򥳥ԡޤԡʸ \\0 ǥߥ͡Ȥޤʸϥԡޤ󡣥ߥ͡ޤޤʤԡХȿ֤ޤԡ˼Ԥ 0 ֤ޤ /** * žХåեۤžƤǤ DEBUG_ASSERT * ͭʤХȤޤ */ inline int copyHenkanmojiretsu(const char *p, int index, int size, char *destination, int destination_size) { DEBUG_ASSERT_POINTER(p); DEBUG_ASSERT_POINTER(destination); DEBUG_ASSERT(size > 0); DEBUG_ASSERT(destination_size > 0); const int margin = 8; for (;;) { if (index >= size) { DEBUG_ASSERT(0); return 0; } if (*(p + index) == ' ') { ++index; break; } ++index; } for (int i = 0; i < destination_size - margin; ++i) { if (index + i >= size) { DEBUG_ASSERT(0); break; } if (*(p + index + i) == '\n') { *(destination + i) = '\0'; return i; } *(destination + i) = *(p + index + i); } DEBUG_ASSERT(0); return 0; } /// index Ƭ֤ˤȤơѴʸפΥݥ󥿤֤ޤ inline const char *getHenkanmojiretsuPointer(const char *p, int index, int size) { for (;;) { if (index >= size) { DEBUG_ASSERT(0); return 0; } if (*(p + index) == ' ') { ++index; break; } ++index; } return p + index; } /// Ѵʸ candidate θĿ֤ޤѴʸפνüɤȤ '\\0' ޤ '\\n' ǧޤ /** * * ߤ /candidate0/candidate1/ * ^ * | * p ϡѴʸפƬꤷޤ */ inline int getCandidateLength(const char *henkanmojiretsu) { DEBUG_ASSERT_POINTER(henkanmojiretsu); DEBUG_ASSERT(*(henkanmojiretsu + 0) == '/'); int entries = 0; // /entry0/entry1/entry2/ for (;;) { char c = *henkanmojiretsu++; if ((c == '\n') || (c == '\0')) { if (entries > 0) { --entries; // üʬ } break; } if (c == '/') { ++entries; } } return entries; } /// index ܤ candidate ؤΥݥ󥿤ȥХȥޤѴʸפνüɤȤ '\\0' ޤ '\n' ǧޤ /** * ˼Ԥ硢 start size ˤϿޤ */ inline bool getCandidateInformation(const char *henkanmojiretsu, int index, const char *&start, int &size) { DEBUG_ASSERT_POINTER(henkanmojiretsu); DEBUG_ASSERT(*(henkanmojiretsu + 0) == '/'); DEBUG_ASSERT(index >= 0); int count = 0; char c; for (;;) { c = *henkanmojiretsu++; if ((c == '\n') || (c == '\0')) { return false; } if (c == '/') { if (count == index) { if ((*henkanmojiretsu == '\n') || (*henkanmojiretsu == '\0')) { DEBUG_ASSERT(0); return false; } else { const char *tmp = henkanmojiretsu; int tmp_size = 0; for (;;) { c = *henkanmojiretsu++; if ((c == '\n') || (c == '\0')) { DEBUG_ASSERT(0); return false; } if (c == '/') { start = tmp; size = tmp_size; return true; } ++tmp_size; } } } ++count; } } return false; // NOTREACHED } /// ָФʸ p + index ʸ compare Ӥޤ strncmp(3) Ʊ֤ͤͤޤ /** * ָФʸ p + index Ȼʸ compare ϡ֤Ҥ餬ʥ󥳡 * ɡפƤ뤳ȤդɬפǤ * * üɤȤ ' ' ޤ '\0' ǧޤ * * ͤ strncmp(3) Ʊ͡ʤ p + index compare ٤ơ * -1 ʲ 0 礭 1 ʾ * ֤ޤ */ inline int compareMidasi(const char *p, int index, int size, const char *compare) { DEBUG_ASSERT_POINTER(p); DEBUG_ASSERT(size > 0); DEBUG_ASSERT_POINTER(compare); if (index < 0) { return -1; } if (index >= size) { return 1; } if (((*(p + index) != '\1') && (*compare != '\1')) || ((*(p + index) == '\1') && (*compare == '\1'))) { for (int i = 0; ; ++i) { if ((index + i) >= size) { return 1; } int s_1 = *(reinterpret_cast(p + index + i)); int s_2 = *(reinterpret_cast(compare + i)); if (s_1 == ' ') { s_1 = '\0'; } if (s_2 == ' ') { s_2 = '\0'; } if (s_1 > s_2) { return i + 1; } else if (s_1 < s_2) { return -(i + 1); } if (s_1 == '\0') { return 0; } } } else if (*(p + index) == '\1') { ++p; int index_2 = 0; for (int i = 0; ; ++i) { if ((index + i) >= size) { return 1; } int s_1 = *(reinterpret_cast(p + index + i)); int s_2; if ((i & 0x1) == 0) { s_2 = 0xa4; } else { s_2 = *(reinterpret_cast(compare + index_2++)); } if (s_1 == ' ') { s_1 = '\0'; } if (s_2 == ' ') { s_2 = '\0'; } if (s_1 > s_2) { return i + 1; } else if (s_1 < s_2) { return -(i + 1); } if (s_1 == '\0') { return 0; } } } else { int index_1 = 0; ++compare; for (int i = 0; ; ++i) { if ((index + i) >= size) { return 1; } int s_1; int s_2 = *(reinterpret_cast(compare + i)); if ((i & 0x1) == 0) { s_1 = 0xa4; } else { s_1 = *(reinterpret_cast(p + index + index_1++)); } if (s_1 == ' ') { s_1 = '\0'; } if (s_2 == ' ') { s_2 = '\0'; } if (s_1 > s_2) { return i + 1; } else if (s_1 < s_2) { return -(i + 1); } if (s_1 == '\0') { return 0; } } } DEBUG_ASSERT(0); return -1; // NOTREACHED } /// ָФʸ (p + index) ΥХȥ֤ޤüʸȤ ' ' ǧޤХȥ˽üʸϴޤޤޤ󡣼˼Ԥ 0 ֤ޤ /** * ˼Ԥ DEBUG_ASSERT ͭʤХȤޤ */ inline int getMidasiSize(const char *p, int index, int size) { DEBUG_ASSERT_POINTER(p); DEBUG_ASSERT(index >= 0); DEBUG_ASSERT(size > 0); for (int midasi_size = 0;; ++midasi_size, ++index) { if (index >= size) { DEBUG_ASSERT(0); return 0; } if (*(p + index) == ' ') { return midasi_size; } } return 0; // NOTREACHED } /// index Ƭ֤ˤȤơѴʸΥХȥ֤ޤХȥ˲ʸϴޤߤޤ inline int getHenkanmojiretsuSize(const char *p, int index, int size) { DEBUG_ASSERT_POINTER(p); DEBUG_ASSERT(index >= 0); DEBUG_ASSERT(size > 0); for (;;) { if (index >= size) { DEBUG_ASSERT(0); return 0; } if (*(p + index) == ' ') { ++index; break; } ++index; } int result = 0; for (;;) { if (index >= size) { DEBUG_ASSERT(0); return 0; } if (*(p + index) == '\n') { return result; } ++result; ++index; } return 0; // NOTREACHED } /// index Ƭ֤ˤȤơ 1 ԤΥХȥ֤ޤХȥ˲ʸϴޤߤޤ inline int getLineSize(const char *p, int index, int size) { DEBUG_ASSERT_POINTER(p); DEBUG_ASSERT(index >= 0); DEBUG_ASSERT(size > 0); int result = 0; for (;;) { if (index >= size) { DEBUG_ASSERT(0); return 0; } if (*(p + index) == '\n') { return result; } ++result; ++index; } return 0; // NOTREACHED } /// 1 ʸܤбեåɥ쥤ǥå֤ޤ /** * Ҥ餬ʤޤ ASCII ʤХեåɥ쥤ǥå֤ޤ * ʳʸ-1 ֤ޤ */ inline int getFixedArrayIndex(const char *p) { DEBUG_ASSERT_POINTER(p); int index; int c = *(p + 0) & 0xff; if (c == '\1') { c = *(p + 1) & 0xff; if (c == 0xa4) { // ֤Ҥ餬ʡ index = *(p + 2) & 0xff; } else if (c <= 0x7e) { #ifdef YASKKSERV_DEBUG if ((c < 0x21) || (c > 0x7e)) { DEBUG_PRINTF("illegal character c=0x%02x\n", c); } #endif // YASKKSERV_DEBUG // ASCII index = c; } else { return -1; } } else { if (c <= 0x7e) { #ifdef YASKKSERV_DEBUG if ((c < 0x21) || (c > 0x7e)) { DEBUG_PRINTF("illegal character c=0x%02x\n", c); } #endif // YASKKSERV_DEBUG // ASCII } else { // ֤Ҥ餬ʡ } index = c; } DEBUG_ASSERT(index <= 0xff); return index; } /// Хʥꥵ search õޤդп֤ޤ result_index ˤϸդǥåդʤäμõΤŬǥå֤ޤ inline bool searchBinary(const char *p, int size, const char *search, int &result_index) { DEBUG_ASSERT_POINTER(p); DEBUG_ASSERT_POINTER(search); DEBUG_ASSERT(size > 0); int index = getNextLineIndex(p, size / 2, size); int before_index = index; int diff = index / 2; for (;;) { int tmp = compareMidasi(p, index, size, search); if (tmp < 0) { index += diff; if (index >= size) { // index ǽԤƬ˰ưޤ result_index = getBeginningOfLineIndex(p, size, size); return false; } } else if (tmp > 0) { index -= diff; if (index < 0) { result_index = 0; return false; } } else { result_index = index; return true; } index = getNextLineIndex(p, index, size); if (index == -1) { result_index = 0; return false; } diff /= 2; if (index == before_index) { result_index = index; return false; } before_index = index; } return false; // NOTREACHED } /// õ search õޤդп֤ޤ result_index ˤϸդǥå֤ޤդʤ result_index Ǥ inline bool searchLinear(const char *p, int size, const char *search, int &result_index) { DEBUG_ASSERT_POINTER(p); DEBUG_ASSERT_POINTER(search); DEBUG_ASSERT(size > 0); int direction = 0; for (;;) { int tmp = compareMidasi(p, result_index, size, search); if (tmp == 0) { return true; } else if (tmp < 0) { if (direction == 0) { direction = -1; } else if (direction != -1) { return false; } result_index = getNextLineIndex(p, result_index, size); if (result_index < 0) { return false; } } else { if (direction == 0) { direction = 1; } else if (direction != 1) { return false; } int before_index = result_index; result_index = getPreviousLineIndex(p, result_index, size); if ((before_index == 0) && (result_index <= 0)) { return false; } } } return false; // NOTREACHED } inline void clearMemory(void *p, int size) { DEBUG_ASSERT_POINTER(p); DEBUG_ASSERT(size > 0); memset(p, 0, static_cast(size)); } inline void copyMemory(const void *source, void *destination, int size) { DEBUG_ASSERT_POINTER(source); DEBUG_ASSERT_POINTER(destination); DEBUG_ASSERT(size > 0); memcpy(destination, source, static_cast(size)); } inline int getStringLength(const void * const string) { DEBUG_ASSERT_POINTER(string); return static_cast(strlen(static_cast(string))); } /// ʸ C μʸؤΥݥ󥿤֤ޤ template const char *getNextPointer(const char *p) { DEBUG_ASSERT_POINTER(p); while (*p++ != c) { } return p; } inline bool getInteger(const void *p, int &result) { char *end; result = static_cast(strtol(reinterpret_cast(p), &end, 10)); if (result == 0) { if ((*end != '\0') || (errno == EINVAL) || (errno == ERANGE)) { return false; } } return true; } #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wfloat-equal" inline bool getFloat(const void *p, float &result) { char *end; result = static_cast(strtof(reinterpret_cast(p), &end)); if ((result == 0.0f) && (p == end)) { return false; } if (errno == ERANGE) { return false; } return true; } #pragma GCC diagnostic pop /// SortKey 򥽡Ȥޤ /** * ͥȺѤߤΥǡʾ塢ǤɬפϤʤΤǥ르ꥺ * ϥ륽ȤѤƤޤ */ struct SortKey { int index; int i; }; inline void sortMidasi(const char *buffer, int buffer_size, SortKey *p, int length) { SortKey tmp; int h; for (h = 1; h < length / 9; h = h * 3 + 1) { } for (; h > 0; h /= 3) { for (int i = h; i < length; ++i) { int j; j = i; while ((j >= h) && (compareMidasi(buffer, (p + (j - h))->index, buffer_size, buffer + (p + j)->index) > 0)) { tmp = *(p + j); *(p + j) = *(p + j - h); *(p + j - h) = tmp; j -= h; } } } } enum HashType { HASH_TYPE_CANDIDATE, HASH_TYPE_MIDASI }; template struct HashWrapper_ { }; template<> struct HashWrapper_ { static bool is_terminator(char c) { return (c == '\0'); } static bool is_right(char c) { return (c == '/'); } }; template<> struct HashWrapper_ { static bool is_terminator(char c) { return ((c == ' ') || (c == '\0')); } static bool is_right(char c) { return ((c == ' ') || (c == '/')); } }; /// candidate or ָФѥϥåǤʸνü HashType ˱ '/' ޤ ' ' ȤʤޤǰΤ '\\0' Ǥ⽪üޤϥǥХåӥɤǤϥȤޤ /** * Ȥʤʸ add() ʹ˲ƤϤʤޤ󡣤Τ񤭴 * ȯƥݥХåեʤɤؤλѤϤǤʤȤդɬפ * */ template class Hash { Hash(Hash &source); Hash& operator=(Hash &source); public: enum { PRIME_2 = 2, PRIME_4 = 5, PRIME_8 = 11, PRIME_16 = 17, PRIME_32 = 37, PRIME_64 = 67, PRIME_128 = 131, PRIME_256 = 257, PRIME_512 = 547, PRIME_1024 = 1031, PRIME_2048 = 2053, PRIME_4096 = 4099, PRIME_8192 = 8209, PRIME_16384 = 16411, PRIME_32768 = 32771, PRIME_65536 = 65539 }; /// hash_table_length ϥåơ֥륵˺Ŭ (礭ܤǿ) ֤ޤ˼Ԥ 0 ֤ޤ static int getPrimeHashTableLength(int hash_table_length) { // candidate_length Ϲ®Τᡢ礭ܤ˳ݤޤ if (hash_table_length <= 512) { hash_table_length = PRIME_1024; } else if (hash_table_length <= 1024) { hash_table_length = PRIME_2048; } else if (hash_table_length <= 2048) { hash_table_length = PRIME_4096; } else if (hash_table_length <= 4096) { hash_table_length = PRIME_8192; } else if (hash_table_length <= 8192) { hash_table_length = PRIME_16384; } else if (hash_table_length <= 16384) { hash_table_length = PRIME_32768; } else if (hash_table_length <= 32768) { hash_table_length = PRIME_65536; } else { hash_table_length = 0; DEBUG_ASSERT(0); // candidate ¿᤮ޤ // // 2500 Ĥ candidate ĥȥ꤬ 26 ĤμǥҥåȤ褦ʾ // ʤΤǡޤϤʤȻפޤ } return hash_table_length; } virtual ~Hash() { delete[] hash_table_; } /// hash_table_length Υϥåơ֥Ĺĥ֥Ȥ򥳥ȥ饯Ȥޤ hash_table_length getPrimeHashTableLength() ΤѤǽ夷ޤ Hash(int hash_table_length) : hash_table_(new Unit[hash_table_length]), hash_table_length_(hash_table_length), add_counter_(0) { DEBUG_PRINTF("hash_table_length = %d size = %d\n", hash_table_length_, hash_table_length_ * static_cast(sizeof(Unit))); } int getHashTableLength() { return hash_table_length_; } /// candidate ʸ key ϥåϿޤϿп򡢥ХåեդϿ˼Ԥ뤫ϿƤе֤ޤ /** * \attention * key '/' ǽü뤳ȤդɬפǤ */ bool add(const char *key, int size) { DEBUG_ASSERT_POINTER(key); DEBUG_ASSERT(size >= 1); // 1 ʸ if (add_counter_ >= hash_table_length_) { return false; } int hash_root = get_hash_root(key, size); for (int i = 0; i != hash_table_length_; ++i) { int index = hash_root + i; index %= hash_table_length_; if ((hash_table_ + index)->key) { if (compare(key, (hash_table_ + index)->key, size)) { return false; } } else { (hash_table_ + index)->key = key; #ifdef YASKKSERV_DEBUG (hash_table_ + index)->debug_offset = i; #endif // YASKKSERV_DEBUG ++add_counter_; return true; } } return false; } /// size ХȤ candidate ʸ key ϥåϿƤп֤ޤ /** * \attention * key '/' ǽü뤳ȤդɬפǤ */ bool contain(const char *key, int size) const { DEBUG_ASSERT_POINTER(key); DEBUG_ASSERT(size >= 1); // 1 ʸ int hash_root = get_hash_root(key, size); int first_index = hash_root % hash_table_length_; if ((hash_table_ + first_index)->key) { for (int i = 0; i != hash_table_length_; ++i) { int index = hash_root + i; index %= hash_table_length_; if ((hash_table_ + index)->key) { if (compare(key, (hash_table_ + index)->key, size)) { return true; } } else { return false; } } } return false; } int getEmptyHashTableLength() const { return hash_table_length_ - add_counter_; } /// ǥХåӥɤǼǤǥХåޤ꡼ӥɤǤϼ 0 ˤʤޤ void getDebugBuildInformation(int &counter, int &offset_max, double &average) { counter = 0; offset_max = 0; average = 0.0; #ifdef YASKKSERV_DEBUG for (int i = 0; i != hash_table_length_; ++i) { if ((hash_table_ + i)->key) { ++counter; int tmp = (hash_table_ + i)->debug_offset; average += tmp; if (tmp > offset_max) { offset_max = tmp; } } } if (counter) { average /= counter; } #endif // YASKKSERV_DEBUG } private: bool compare(const char *key_0, const char *key_1, int size) const { DEBUG_ASSERT_POINTER(key_0); DEBUG_ASSERT_POINTER(key_1); DEBUG_ASSERT(size >= 1); for (int i = 0; i != size; ++i) { char tmp_0 = *key_0; char tmp_1 = *key_1; if (HashWrapper_::is_terminator(tmp_0)) { tmp_0 = '/'; } if (HashWrapper_::is_terminator(tmp_1)) { tmp_1 = '/'; } if (tmp_0 != tmp_1) { return false; } else { if (tmp_0 == '/') { DEBUG_ASSERT(HashWrapper_::is_right(*key_0)); return true; } ++key_0; ++key_1; } } return true; } int get_hash_root(const char *key, int size) const { DEBUG_ASSERT_POINTER(key); // get_hash_root() ϽüޤޤʤΤ size >= 1 ʤȤդɬ // פǤ DEBUG_ASSERT(size >= 1); // 1 ʸ // result λмϼºݤ¬ꤷơʤȤʤɤͤФΤѤ // Ƥޤ // // time perl sandbox/send_server.pl --timeout_second=30.0 --port=10013 '40 ' > /dev/null // // factor = 23 // real 0m0.104s // offset_max=87 // average=1.485140 // // factor = 24 // real 0m0.103s // offset_max=51 // average=0.814867 // // factor = 27 // real 0m0.104s // offset_max=41 // average=0.713104 // // factor = 33 // real 0m0.101s // offset_max=41 // average=1.112136 // // factor = 61 // real 0m0.107s // offset_max=23 // average=0.662954 // // factor = 1999 // real 0m0.103s // offset_max=33 // average=1.025329 // // factor = 2203 // real 0m0.106s // offset_max=25 // average=0.791383 int result = 0; const int factor = 61; for (int i = 0; i != size; ++i) { result = result * factor + *reinterpret_cast(key + i); } return result & 0x7fffffff; } private: struct Unit { private: Unit(Unit &source); Unit& operator=(Unit &source); public: Unit() : #ifdef YASKKSERV_DEBUG key(0), debug_offset(0) #else // YASKKSERV_DEBUG key(0) #endif // YASKKSERV_DEBUG { } const char *key; #ifdef YASKKSERV_DEBUG int debug_offset; #endif // YASKKSERV_DEBUG }; Unit *hash_table_; int hash_table_length_; int add_counter_; }; } } #endif // SKK_UTILITY_HPP yaskkserv-1.1.0/source/yaskkserv_hairy/000077500000000000000000000000001262716711600202625ustar00rootroot00000000000000yaskkserv-1.1.0/source/yaskkserv_hairy/Makefile.bsd_cygwin_linux_gcc000066400000000000000000000053351262716711600261120ustar00rootroot00000000000000# -*- Makefile -*- include ../Makefile.$(ARCHITECTURE_LOWER_CASE).common TARGET_BASE = yaskkserv_hairy # RUN_FLAGS = --port=9999 --google-japanese-input=dictionary --google-japanese-input-timeout=1.1 /home/wac/local/share/skk/SKK-JISYO.total+zipcode.yaskkserv # RUN_FLAGS = --port=9999 --google-japanese-input=dictionary --google-suggest --google-japanese-input-timeout=1.1 /home/wac/local/share/skk/SKK-JISYO.total+zipcode.yaskkserv https://suggest.google.com https://www.google.com # RUN_FLAGS = --port=9999 --google-japanese-input=dictionary --google-suggest --google-japanese-input-timeout=1.1 --google-cache=512 --google-cache-file=/tmp/yaskkserv.cache /home/wac/local/share/skk/SKK-JISYO.total+zipcode.yaskkserv https://www.google.com https://suggest.google.com RUN_FLAGS = --port=9999 --google-japanese-input=dictionary --google-japanese-input-timeout=1.1 --google-cache=512 --google-cache-file=/tmp/yaskkserv.cache /home/wac/local/share/skk/SKK-JISYO.total+zipcode.yaskkserv https://www.google.com # RUN_FLAGS = --port=9999 /home/wac/local/share/skk/SKK-JISYO.total+zipcode.yaskkserv # RUN_FLAGS = --port=9999 --google-japanese-input=dictionary --google-suggest --google-japanese-input-timeout=1.1 https://www.google.com # RUN_FLAGS = --port=9999 --google-japanese-input=dictionary --google-japanese-input-timeout=1.1 http://www.google.com /home/wac/local/share/skk/SKK-JISYO.total+zipcode.yaskkserv # RUN_FLAGS = --port=9999 --google-japanese-input=dictionary --google-japanese-input-timeout=1.1 http://www.google.com CXXFLAGS += $(CXXFLAGS_OPTIMIZE_SERVER_HAIRY) $(CXXFLAGS_WARNING_SERVER_HAIRY) SOURCES = ${wildcard *.cpp} OBJECTS = ${addprefix $(VAR_PATH)/$(TARGET_BASE)/,$(SOURCES:.cpp=.o)} OBJECTS_SKK = ${wildcard $(VAR_PATH)/skk/*.o} ${wildcard $(VAR_PATH)/skk/architecture/$(ARCHITECTURE_LOWER_CASE)/*.o} DEPEND_FILE = $(VAR_PATH)/depend.$(TARGET_BASE) TARGET = $(VAR_PATH)/$(TARGET_BASE)/$(TARGET_BASE) .SUFFIXES : .PHONY : all clean run makerun break makebreak kill makekill debugger vlist vhist vreport test depend cleandepend all : $(TARGET) $(TARGET) : $(OBJECTS_SKK) $(OBJECTS) $(LD) $(LDFLAGS) -o $@ $^ $(LDFLAGS_LIBRARY_HAIRY) ifndef DEBUG $(STRIP) $@$(EXECUTE_FILE_SUFFIX) endif run : cd $(PROJECT_ROOT); export SEGFAULT_SIGNALS=all && export LD_PRELOAD=/lib/libSegFault.so && time $(TARGET) $(RUN_FLAGS) makerun : all run $(DEPEND_FILE) : $(MAKEDEPEND) $(VAR_PATH)/$(TARGET_BASE) $(DEPEND_FILE) '$(CXX) $(CXXFLAGS)' '$(CPP) -E -MM $(CPPFLAGS) $(SOURCES)' depend : $(MAKEDEPEND) $(VAR_PATH)/$(TARGET_BASE) $(DEPEND_FILE) '$(CXX) $(CXXFLAGS)' '$(CPP) -E -MM $(CPPFLAGS) $(SOURCES)' cleandepend : -$(RM) $(DEPEND_FILE) include $(DEPEND_FILE) clean : -$(RM) $(TARGET) $(TARGET).map -$(RM) $(OBJECTS) yaskkserv-1.1.0/source/yaskkserv_hairy/yaskkserv_hairy.cpp000066400000000000000000005742761262716711600242310ustar00rootroot00000000000000/* Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012, 2013, 2014 Tadashi Watanabe This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "skk_dictionary.hpp" #include "skk_server.hpp" #include "skk_utility.hpp" #include "skk_command_line.hpp" #include "skk_simple_string.hpp" // #define YASKKSERV_HAIRY_TEST namespace YaSkkServ { namespace { #define SERVER_IDENTIFIER "hairy" char version_string[] = YASKKSERV_VERSION ":yaskkserv_" SERVER_IDENTIFIER " "; #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT class SimpleStringForHairy : public SkkSimpleString { public: virtual ~SimpleStringForHairy() { } SimpleStringForHairy(int buffer_size) : SkkSimpleString(buffer_size), read_index_(0) { } void reset() { SkkSimpleString::reset(); read_index_ = 0; } bool appendOctet(int code) { if (!isAppendSize(4)) { return false; } int c_3 = code / 64; code -= c_3 * 64; int c_2 = code / 8; code -= c_2 * 8; c_3 += static_cast(static_cast('0')); c_2 += static_cast(static_cast('0')); code += static_cast(static_cast('0')); appendFast('\\'); appendFast(static_cast(c_3)); appendFast(static_cast(c_2)); appendFast(static_cast(code)); return true; } void setReadIndex(int index) { read_index_ = index; } int getReadIndex() const { return read_index_; } bool isReadIndex(int index) const { int margin = 4; int valid_buffer_size = getValidBufferSize() - margin; DEBUG_ASSERT(index >= 0); if ((index < valid_buffer_size) && (index >= 0)) { return true; } return false; } #if 0 char readCharacter(char &result) const { if (isReadIndex(read_index_)) { result = getCharacter(read_index_); return true; } return false; } #endif bool readCharacterAndAddReadIndex(char &result) { if (isReadIndex(read_index_)) { result = getCharacter(read_index_); ++read_index_; return true; } return false; } protected: int read_index_; }; class SimpleCache { private: SimpleCache(SimpleCache &source); SimpleCache& operator=(SimpleCache &source); enum { FAST_KEY_LENGTH = 28, FAST_VALUE_LENGTH = 256 - FAST_KEY_LENGTH, LARGE_KEY_LENGTH = 128, LARGE_VALUE_LENGTH = 2 * 1024 - LARGE_KEY_LENGTH, }; struct FastKey { FastKey() : hash_binary_size(0) { } bool isValidKeySize(int key_binary_size) const { return key_binary_size < FAST_KEY_LENGTH; } uint32_t hash_binary_size; // 16bit hash Dz 16bit getHashBinarySize() Ǻޤ }; struct FastValue { FastValue() : binary_size(0), key(), value() { memset(key, 0, FAST_KEY_LENGTH); memset(value, 0, FAST_VALUE_LENGTH); } int binary_size; char key[FAST_KEY_LENGTH]; char value[FAST_VALUE_LENGTH]; }; struct LargeKey { LargeKey() : hash_binary_size(0) { } bool isValidKeySize(int key_binary_size) const { return key_binary_size < LARGE_KEY_LENGTH; } uint32_t hash_binary_size; // 16bit hash Dz 16bit getHashBinarySize() Ǻޤ }; struct LargeValue { LargeValue() : binary_size(0), key(), value() { memset(key, 0, LARGE_KEY_LENGTH); memset(value, 0, LARGE_VALUE_LENGTH); } int binary_size; char key[LARGE_KEY_LENGTH]; char value[LARGE_VALUE_LENGTH]; }; public: virtual ~SimpleCache() { delete[] fast_key_; delete[] fast_value_; delete[] large_key_; delete[] large_value_; } SimpleCache() : fast_entries_(0), fast_index_(0), large_entries_(0), large_index_(0), fast_key_(0), fast_value_(0), large_key_(0), large_value_(0) { } void create(int fast_entries, int large_entries) { if ((fast_entries_ != 0) || (large_entries_ != 0)) { DEBUG_ASSERT(0); } else { fast_entries_ = fast_entries; fast_index_ = 0; large_entries_ = large_entries; large_index_ = 0; if (fast_entries_ > 0) { fast_key_ = new FastKey[fast_entries_]; fast_value_ = new FastValue[fast_entries_]; } if (large_entries_ > 0) { large_key_ = new LargeKey[large_entries_]; large_value_ = new LargeValue[large_entries_]; } DEBUG_PRINTF("fast_entries=%d large_entries=%d fast size=%d large size=%d\n", fast_entries_, large_entries_, fast_entries_ * (sizeof(FastKey) + sizeof(FastValue)), large_entries_ * (sizeof(LargeKey) + sizeof(LargeValue))); } } static bool isFast(int key_binary_size, int value_binary_size) { return ((key_binary_size < FAST_KEY_LENGTH) && (value_binary_size < FAST_VALUE_LENGTH)); } static bool isLarge(int key_binary_size, int value_binary_size) { return ((key_binary_size < LARGE_KEY_LENGTH) && (value_binary_size < LARGE_VALUE_LENGTH)); } void appendInformation(SkkSimpleString &string) { int fast_use_count = 0; for (int i = 0; i != fast_entries_; ++i) { if ((fast_key_ + i)->hash_binary_size != 0) { ++fast_use_count; } } int large_use_count = 0; for (int i = 0; i != large_entries_; ++i) { if ((large_key_ + i)->hash_binary_size != 0) { ++large_use_count; } } const char fast[] = "fast="; const char large[] = " large="; string.append(fast, sizeof(fast) - 1); string.append(fast_index_); string.append('/'); string.append(fast_use_count); string.append('/'); string.append(fast_entries_); string.append(large, sizeof(large) - 1); string.append(large_index_); string.append('/'); string.append(large_use_count); string.append('/'); string.append(large_entries_); } // åϤΤɬפʥХåե֤ޤ int getCacheBufferSize() const { const int entries_size = 2 * 4; const int index_size = 2 * 4; return (entries_size + index_size + fast_entries_ * static_cast(sizeof(FastKey)) + fast_entries_ * static_cast(sizeof(FastValue)) + large_entries_ * static_cast(sizeof(LargeKey)) + large_entries_ * static_cast(sizeof(LargeValue))); } void getCacheBufferInformation(int &fast_entries, int &fast_index, int &large_entries, int &large_index) const { fast_entries = fast_entries_; fast_index = fast_index_; large_entries = large_entries_; large_index = large_index_; } // åƤ buffer ˽񤭽Фޤ񤭽ФΥХåեݥ󥿤֤ޤ char *getCacheForSave(char *buffer) const { SkkUtility::copyMemory(&fast_entries_, buffer, 4); buffer += 4; SkkUtility::copyMemory(&fast_index_, buffer, 4); buffer += 4; SkkUtility::copyMemory(&large_entries_, buffer, 4); buffer += 4; SkkUtility::copyMemory(&large_index_, buffer, 4); buffer += 4; SkkUtility::copyMemory(fast_key_, buffer, fast_entries_ * static_cast(sizeof(FastKey))); buffer += fast_entries_ * sizeof(FastKey); SkkUtility::copyMemory(fast_value_, buffer, fast_entries_ * static_cast(sizeof(FastValue))); buffer += fast_entries_ * sizeof(FastValue); SkkUtility::copyMemory(large_key_, buffer, large_entries_ * static_cast(sizeof(LargeKey))); buffer += large_entries_ * sizeof(LargeKey); SkkUtility::copyMemory(large_value_, buffer, large_entries_ * static_cast(sizeof(LargeValue))); buffer += large_entries_ * sizeof(LargeValue); return buffer; } // buffer ƤɤĴ٤ޤƤ 0 ֤ޤϼΥХåեݥ󥿤֤ޤ const char *verifyBufferForLoad(const char *buffer) { int fast_entries; int fast_index; int large_entries; int large_index; SkkUtility::copyMemory(buffer, &fast_entries, 4); buffer += 4; SkkUtility::copyMemory(buffer, &fast_index, 4); buffer += 4; SkkUtility::copyMemory(buffer, &large_entries, 4); buffer += 4; SkkUtility::copyMemory(buffer, &large_index, 4); buffer += 4; if ((fast_index >= fast_entries) || (fast_index < 0) || (fast_entries < 0)) { return 0; } if ((large_index >= large_entries) || (large_index < 0) || (large_entries < 0)) { return 0; } buffer += fast_entries * sizeof(FastKey); buffer += fast_entries * sizeof(FastValue); buffer += large_entries * sizeof(LargeKey); buffer += large_entries * sizeof(LargeValue); return buffer; } // buffer 򥭥å˽񤭹ߤޤΥХåեݥ󥿤֤ޤǡǤ뤳ȤȤƤΤǡ餫 verifyBufferForLoad() ǡåƤɬפޤ const char *setCacheForLoad(const char *buffer) { int file_fast_entries; int file_fast_index; int file_large_entries; int file_large_index; SkkUtility::copyMemory(buffer, &file_fast_entries, 4); buffer += 4; SkkUtility::copyMemory(buffer, &file_fast_index, 4); buffer += 4; SkkUtility::copyMemory(buffer, &file_large_entries, 4); buffer += 4; SkkUtility::copyMemory(buffer, &file_large_index, 4); buffer += 4; int copy_fast_entries = file_fast_entries; int copy_large_entries = file_large_entries; if (file_fast_index >= fast_entries_) { fast_index_ = 0; } else { fast_index_ = file_fast_index; } if (file_large_index >= large_entries_) { large_index_ = 0; } else { large_index_ = file_large_index; } if (file_fast_entries > fast_entries_) { copy_fast_entries = fast_entries_; } if (file_large_entries > large_entries_) { copy_large_entries = large_entries_; } DEBUG_PRINTF("copy_fast_entries=%d fast_entries_=%d fast_index_=%d file_fast_entries=%d file_fast_index=%d\n", copy_fast_entries, fast_entries_, fast_index_, file_fast_entries, file_fast_index); DEBUG_PRINTF("copy_large_entries=%d large_entries_=%d large_index_=%d file_large_entries=%d file_large_index=%d\n", copy_large_entries, large_entries_, large_index_, file_large_entries, file_large_index); SkkUtility::copyMemory(buffer, fast_key_, copy_fast_entries * static_cast(sizeof(FastKey))); buffer += file_fast_entries * sizeof(FastKey); SkkUtility::copyMemory(buffer, fast_value_, copy_fast_entries * static_cast(sizeof(FastValue))); buffer += file_fast_entries * sizeof(FastValue); SkkUtility::copyMemory(buffer, large_key_, copy_large_entries * static_cast(sizeof(LargeKey))); buffer += file_large_entries * sizeof(LargeKey); SkkUtility::copyMemory(buffer, large_value_, copy_large_entries * static_cast(sizeof(LargeValue))); buffer += file_large_entries * sizeof(LargeValue); return buffer; } protected: uint32_t getHashBinarySize(const SimpleStringForHairy &key) const { uint32_t hash = 0; uint32_t shift = 0; uint32_t size = static_cast(key.getSize()); const uint8_t * const p = reinterpret_cast(key.getBuffer()); for (uint32_t i = 0; i != size; ++i) { uint32_t tmp = static_cast(*(p + i)); hash += tmp << shift; if (++shift >= 9) { shift = 0; } } const int terminator_size = 1; return (hash << 16) | (size + terminator_size); } template bool getBase(const SimpleStringForHairy &key, SimpleStringForHairy &value, int entries, const T_1 &key_table, T_2 &value_table) const { if (entries > 0) { const char * const key_pointer = key.getBuffer(); const int terminator_size = 1; int key_compare_binary_size = key.getSize() + terminator_size; uint32_t key_compare_hash = getHashBinarySize(key); DEBUG_PRINTF("getBase() key_compare_hash=0x%08x\n", key_compare_hash); DEBUG_ASSERT(key_compare_binary_size > 0); DEBUG_ASSERT(key_table->isValidKeySize(key_compare_binary_size)); if ((key_compare_binary_size > 0) && key_table->isValidKeySize(key_compare_binary_size)) { for (int i = 0; i != entries; ++i) { if (((key_table + i)->hash_binary_size == key_compare_hash) && (memcmp(key_pointer, (value_table + i)->key, static_cast(key_compare_binary_size)) == 0)) { DEBUG_ASSERT(value.getValidBufferSize() > (value_table + i)->binary_size); if (value.getValidBufferSize() > (value_table + i)->binary_size) { value.reset(); value.appendFast((value_table + i)->value); DEBUG_PRINTF("getBase() value=%s size=%d cur=%p\n", value.getBuffer(), value.getSize(), value.getCurrentBuffer()); return true; } } } } } return false; } template bool setBase(const SimpleStringForHairy &key, const SimpleStringForHairy &value, int entries, const T_1 &key_table, T_2 &value_table, int &index) const { if (entries > 0) { const int terminator_size = 1; int key_copy_size = key.getSize() + terminator_size; (key_table + index)->hash_binary_size = getHashBinarySize(key); DEBUG_PRINTF("setBase() key_compare_hash=0x%08x value size=%d\n", (key_table + index)->hash_binary_size, value.getSize()); memcpy((value_table + index)->key, key.getBuffer(), static_cast(key_copy_size)); int value_copy_size = value.getSize() + terminator_size; (value_table + index)->binary_size = value_copy_size; memcpy((value_table + index)->value, value.getBuffer(), static_cast(value_copy_size)); ++index; if (index >= entries) { index = 0; } return true; } return false; } public: bool getFast(const SimpleStringForHairy &key, SimpleStringForHairy &value) const { return getBase(key, value, fast_entries_, fast_key_, fast_value_); } bool setFast(const SimpleStringForHairy &key, const SimpleStringForHairy &value) { return setBase(key, value, fast_entries_, fast_key_, fast_value_, fast_index_); } bool getLarge(const SimpleStringForHairy &key, SimpleStringForHairy &value) const { return getBase(key, value, large_entries_, large_key_, large_value_); } bool setLarge(const SimpleStringForHairy &key, const SimpleStringForHairy &value) { return setBase(key, value, large_entries_, large_key_, large_value_, large_index_); } bool set(const SimpleStringForHairy &key, const SimpleStringForHairy &value) { int terminator_size = 1; if (isFast(key.getSize() + terminator_size, value.getSize())) { return setFast(key, value); } else if (isLarge(key.getSize() + terminator_size, value.getSize())) { return setLarge(key, value); } return false; } bool get(const SimpleStringForHairy &key, SimpleStringForHairy &value) const { int terminator_size = 1; if (isFast(key.getSize() + terminator_size, 0)) { return getFast(key, value); } else if (isLarge(key.getSize() + terminator_size, 0)) { return getLarge(key, value); } return false; } private: int fast_entries_; int fast_index_; int large_entries_; int large_index_; FastKey *fast_key_; FastValue *fast_value_; LargeKey *large_key_; LargeValue *large_value_; }; class GoogleJapaneseInput { GoogleJapaneseInput(GoogleJapaneseInput &source); GoogleJapaneseInput& operator=(GoogleJapaneseInput &source); public: virtual ~GoogleJapaneseInput() { } GoogleJapaneseInput() : skk_socket_(), work_a_buffer_(4 * 1024), work_b_buffer_(4 * 1024), midashi_buffer_(1 * 1024), http_send_buffer_(2 * 1024), http_receive_buffer_(4 * 1024), skk_output_buffer_(4 * 1024), http_send_string_(1 * 1024), cache_(), #if defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) is_https_(true), #else // defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) is_https_(false), #endif // defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) is_ipv6_(false) { } void createCache(int cache_entries) { int fast_cache_entries = cache_entries; int large_cache_entries = cache_entries / 16; cache_.create(fast_cache_entries, large_cache_entries); } void appendCacheInformation(SkkSimpleString &string) { cache_.appendInformation(string); } int getCacheBufferSize() const { return cache_.getCacheBufferSize(); } void getCacheBufferInformation(int &fast_entries, int &fast_index, int &large_entries, int &large_index) const { cache_.getCacheBufferInformation(fast_entries, fast_index, large_entries, large_index); } char *getCacheForSave(char *buffer) const { return cache_.getCacheForSave(buffer); } const char *verifyBufferForLoad(const char *buffer) { return cache_.verifyBufferForLoad(buffer); } const char *setCacheForLoad(const char *buffer) { return cache_.setCacheForLoad(buffer); } bool isHttps() const { return is_https_; } void setHttpsFlag(bool is_https) { is_https_ = is_https; } void setIpv6Flag(bool is_ipv6) { is_ipv6_ = is_ipv6; } // СХåեΥݥ󥿤򡢼Ԥ 0 ֤ޤ search_word νüɤϥڡǤɬפޤ const char *getSkkCandidatesEuc(const char *search_word, float timeout) { int search_word_size = 0; for (search_word_size = 0; ; ++search_word_size) { int c = static_cast(static_cast(*(search_word + search_word_size))); if (c == '\0') { return 0; } if (c == ' ') { break; } } // euc 2bytes // utf8 3bytes // url 9bytes // ʤΤǡ¿ܤˤߤ 5 ܤǷ׻Хåեˤϰ // Ф礭ʥݻꤷƤ // ǡΤ餤ޤʤ if (search_word_size >= work_b_buffer_.getValidBufferSize() / 5) { return 0; } work_a_buffer_.reset(); midashi_buffer_.reset(); skk_output_buffer_.reset(); DEBUG_PRINTF("google search_word_size=\"%d\"\n", search_word_size); for (int i = 0; ; ++i) { int c = static_cast(static_cast(*(search_word + i))); if (c == '\0') { return 0; } if (c == ' ') { if (SkkUtility::isOkuriAri(search_word, search_word_size)) { // ꤢξϺǸ if (i <= 0) { DEBUG_ASSERT(0); } else { midashi_buffer_.terminate(i - 1); break; } } break; } if (!midashi_buffer_.append(static_cast(c))) { return 0; } } if (cache_.get(midashi_buffer_, skk_output_buffer_)) { DEBUG_PRINTF("cache found:%s %s\n", midashi_buffer_.getBuffer(), skk_output_buffer_.getBuffer()); } else { if (!convertIconv(midashi_buffer_, work_a_buffer_, "euc-jp", "utf-8")) { return 0; } work_b_buffer_.reset(); if (!convertUtf8ToUrl(work_a_buffer_, work_b_buffer_)) { return 0; } if (!getHttp(work_b_buffer_, timeout)) { return 0; } if (!convertJsonToSkk()) { return 0; } if (!confirmSkk(skk_output_buffer_, search_word, search_word_size)) { return 0; } cache_.set(midashi_buffer_, skk_output_buffer_); } return skk_output_buffer_.getBuffer(); } const char *getSkkCandidatesEucSuggest(const char *search_word, float timeout) { int search_word_size = 0; for (search_word_size = 0; ; ++search_word_size) { int c = static_cast(static_cast(*(search_word + search_word_size))); if (c == '\0') { return 0; } if (c == ' ') { break; } } // euc 2bytes // utf8 3bytes // url 9bytes // ʤΤǡ¿ܤˤߤ 5 ܤǷ׻Хåեˤϰ // Ф礭ʥݻꤷƤ // ǡΤ餤ޤʤ if (search_word_size >= work_b_buffer_.getValidBufferSize() / 5) { return 0; } DEBUG_PRINTF("google search_word_size=\"%d\"\n", search_word_size); work_a_buffer_.reset(); midashi_buffer_.reset(); skk_output_buffer_.reset(); for (int i = 0; ; ++i) { int c = static_cast(static_cast(*(search_word + i))); if (c == '\0') { return 0; } if (c == ' ') { if (SkkUtility::isOkuriAri(search_word, search_word_size)) { // ꤢξϺǸ if (i <= 0) { DEBUG_ASSERT(0); } else { midashi_buffer_.terminate(i - 1); break; } } break; } if (!midashi_buffer_.append(static_cast(c))) { return 0; } } if (cache_.get(midashi_buffer_, skk_output_buffer_)) { DEBUG_PRINTF("cache found:%s %s\n", midashi_buffer_.getBuffer(), skk_output_buffer_.getBuffer()); } else { if (!convertIconv(midashi_buffer_, work_a_buffer_, "euc-jp", "utf-8")) { return 0; } work_b_buffer_.reset(); if (!convertUtf8ToUrl(work_a_buffer_, work_b_buffer_)) { return 0; } if (!getHttpSuggest(work_b_buffer_, timeout)) { return 0; } if (!convertXMLToSkk()) { return 0; } if (!confirmSkk(skk_output_buffer_, search_word, search_word_size)) { return 0; } cache_.set(midashi_buffer_, skk_output_buffer_); } return skk_output_buffer_.getBuffer(); } static int getByteSize(const char *p) { int byte_size = 0; while (*(p + byte_size++)) {} return byte_size - 1; } private: // from_code source to_code Ѵ destination ˽񤭹ߤޤп֤ޤԤ destination ƤǤ static bool convertIconv(const SimpleStringForHairy &source, SimpleStringForHairy &destination, const char *from_code, const char *to_code) { iconv_t icd = iconv_open(to_code, from_code); if (icd == reinterpret_cast(-1)) { return false; } else { const int nul_size = 1; int byte_size = source.getSize() + nul_size; #ifdef YASKKSERV_CONFIG_ICONV_ARGUMENT_CONST_CHAR const char *in_buffer = source.getBuffer(); #else // YASKKSERV_CONFIG_ICONV_ARGUMENT_CONST_CHAR char *in_buffer = const_cast(source.getBuffer()); #endif // YASKKSERV_CONFIG_ICONV_ARGUMENT_CONST_CHAR char *out_buffer = const_cast(destination.getBuffer()); size_t in_size = static_cast(byte_size); size_t out_size = static_cast(destination.getValidBufferSize()); for (;;) { size_t result = static_cast(-1); if (destination.beginWriteBuffer(const_cast(out_buffer), static_cast(out_size))) { result = iconv(icd, &in_buffer, &in_size, &out_buffer, &out_size); } destination.endWriteBuffer(static_cast(out_size)); if (result == static_cast(-1)) { // error DEBUG_PRINTF("iconv error\n"); return false; } if (in_size == 0) { break; } } if (iconv_close(icd) != 0) { // error return false; } destination.setAppendIndex(getByteSize(destination.getBuffer())); } return true; } // character ASCII 0-9 A-F a-f Хʥ 0x0-0xf Ѵ result ֤ޤп֤ޤԤ result ˿ޤ static bool getEscapeBinary(int character, int &result) { if ((character >= '0') && (character <= '9')) { result = character - '0'; return true; } if ((character >= 'A') && (character <= 'F')) { result = 0xa + character - 'A'; return true; } if ((character >= 'a') && (character <= 'f')) { result = 0xa + character - 'a'; return true; } return false; } // escape Υ 4 UTF8 Ѵ utf8 ˽񤭹ߤޤп֤ޤԤ utf8 ƤǤ static bool convertEscape4ToUtf8(SimpleStringForHairy &escape, SimpleStringForHairy &utf8) { int previous_c = 0; for (;;) { const int largish_margin = 6; if (!escape.isAppendSize(largish_margin) || !utf8.isAppendSize(largish_margin)) { return false; } char c; if (!escape.readCharacterAndAddReadIndex(c)) { return false; } if (c == 0) { utf8.appendFast(static_cast(c)); break; } else if (c == '\\') { } else if (previous_c == '\\') { if (c == 'u') { int bin_0; int bin_1; int bin_2; int bin_3; char tmp; if (!escape.readCharacterAndAddReadIndex(tmp)) { return false; } if (!getEscapeBinary(tmp, bin_0)) { return false; } if (!escape.readCharacterAndAddReadIndex(tmp)) { return false; } if (!getEscapeBinary(tmp, bin_1)) { return false; } if (!escape.readCharacterAndAddReadIndex(tmp)) { return false; } if (!getEscapeBinary(tmp, bin_2)) { return false; } if (!escape.readCharacterAndAddReadIndex(tmp)) { return false; } if (!getEscapeBinary(tmp, bin_3)) { return false; } int unicode = (bin_0 << 12) | (bin_1 << 8) | (bin_2 << 4) | bin_3; int utf8_data = (((unicode & 0xf000) << 4) | 0xe00000) | (((unicode & 0xfc0) << 2) | 0x8000) | ((unicode & 0x3f) | 0x80); utf8.appendFast(static_cast((utf8_data >> 16) & 0xff)); utf8.appendFast(static_cast((utf8_data >> 8) & 0xff)); utf8.appendFast(static_cast(utf8_data & 0xff)); } else { utf8.appendFast(static_cast(c)); } } else { utf8.appendFast(static_cast(c)); } previous_c = c; } return true; } static bool convertUtf8ToUrl(SimpleStringForHairy &source, SimpleStringForHairy &destination) { // URL encode 1byte -> 3byte ʤΤǡ // SkkSimpleString Υޡʤɤ¿ܤˤߤ 4 ܤǷ // if (source.getSize() >= destination.getValidBufferSize() / 4) { return false; } for (;;) { char c; if (!source.readCharacterAndAddReadIndex(c)) { return false; } if (c == 0) { break; } static const char table[] = "0123456789ABCDEF"; if (!destination.isAppendSize(3)) { return false; } destination.appendFast('%'); destination.appendFast(table[(c >> 4) & 0xf]); destination.appendFast(table[c & 0xf]); } return true; } bool isBusySocket() { bool result = false; switch (errno) { default: break; case EAGAIN: case EINTR: case ECONNABORTED: case ECONNREFUSED: case ECONNRESET: result = true; break; } return result; } int send(int socket_fd) { int send_result; for (;;) { #if defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) if (isHttps()) { send_result = skk_socket_.writeSsl(http_send_string_.getBuffer(), http_send_string_.getSize()); DEBUG_PRINTF("send_result=%d data size=%d\n", send_result, http_send_string_.getSize()); } else { send_result = SkkSocket::send(socket_fd, http_send_string_.getBuffer(), http_send_string_.getSize()); } #else // defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) send_result = SkkSocket::send(socket_fd, http_send_string_.getBuffer(), http_send_string_.getSize()); #endif // defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) if (send_result == http_send_string_.getSize()) { break; } #if defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) if (isHttps()) { if (!skk_socket_.isBusySsl(send_result)) { DEBUG_PRINTF("busy break send_result=%d\n", send_result); break; } } else { if ((errno != EAGAIN) && (errno != EWOULDBLOCK)) { break; } } #endif // defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) usleep(10 * 1000); } return send_result; } int receive(int socket_fd, float timeout) { bool result = true; int receive_buffer_index = 0; SkkUtility::WaitAndCheckForGoogleJapaneseInput wait_and_check_for_google_japanese_input; for (;;) { // select() ǤϤʤݡ󥰤ǥ롼׽Ƥ뤳ȤդɬפǤ if (!wait_and_check_for_google_japanese_input.waitAndCheckLoopHead(timeout)) { result = false; break; } const int margin = 256; int receive_size = -2; int unit_receive_size = http_receive_buffer_.getValidBufferSize() - receive_buffer_index - margin; if (unit_receive_size <= 0) { DEBUG_ASSERT(0); result = false; break; } #if defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) if (isHttps()) { if (http_receive_buffer_.beginWriteBuffer(const_cast(http_receive_buffer_.getBuffer()) + receive_buffer_index, unit_receive_size)) { receive_size = skk_socket_.readSsl(const_cast(http_receive_buffer_.getBuffer()) + receive_buffer_index, unit_receive_size); } http_receive_buffer_.endWriteBuffer(receive_size); DEBUG_PRINTF("receive_size=%d\n", receive_size); } else { if (http_receive_buffer_.beginWriteBuffer(const_cast(http_receive_buffer_.getBuffer()) + receive_buffer_index, unit_receive_size)) { receive_size = SkkSocket::receive(socket_fd, const_cast(http_receive_buffer_.getBuffer()) + receive_buffer_index, unit_receive_size); } http_receive_buffer_.endWriteBuffer(receive_size); } #else // defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) if (http_receive_buffer_.beginWriteBuffer(const_cast(http_receive_buffer_.getBuffer()) + receive_buffer_index, unit_receive_size)) { receive_size = SkkSocket::receive(socket_fd, const_cast(http_receive_buffer_.getBuffer()) + receive_buffer_index, unit_receive_size); } http_receive_buffer_.endWriteBuffer(receive_size); #endif // defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) if (receive_size == 0) { #if defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) if ((receive_buffer_index == 0) && skk_socket_.isBusySsl(receive_size)) { DEBUG_PRINTF("receive_size=0 busy!\n"); } else #endif // defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) { break; } } else if (receive_size == -2) { // error on beginWriteBuffer() result = false; break; } else if (receive_size == -1) { // error/busy on receive()/readSsl() #if defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) if (isHttps()) { if (!skk_socket_.isBusySsl(receive_size)) { result = false; break; } } else { if (!isBusySocket()) { result = false; break; } } #else // defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) if (!isBusySocket()) { result = false; break; } #endif // defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) } else { receive_buffer_index += receive_size; http_receive_buffer_.setAppendIndex(receive_buffer_index); } usleep(1 * 1000); } if (!http_receive_buffer_.append('\0')) { return false; } return result; } bool getHttp(SimpleStringForHairy &url_encode_word, float timeout) { http_receive_buffer_.reset(); http_send_string_.reset(); if (isHttps()) { http_send_string_.appendFast("GET https://www.google.com/transliterate?langpair=ja-Hira|ja&text="); } else { http_send_string_.appendFast("GET http://www.google.com/transliterate?langpair=ja-Hira|ja&text="); } { const int cr_lf_and_margin = 16; if (http_send_string_.getRemainSize() < url_encode_word.getSize() + cr_lf_and_margin) { return false; } } http_send_string_.appendFast(url_encode_word); http_send_string_.appendFast(",\x0d\x0a\x0d\x0a"); int socket_fd; if (isHttps()) { #if defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) socket_fd = skk_socket_.prepareASyncSocketSsl("www.google.com", "https", timeout, is_ipv6_); #else // defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) socket_fd = -1; #endif // defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) } else { socket_fd = skk_socket_.prepareASyncSocket("www.google.com", "http", timeout, is_ipv6_); } bool result = socket_fd >= 0; if (result) { int send_result = send(socket_fd); if (send_result == -1) { result = false; } if (result) { result = receive(socket_fd, timeout); } #if defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) if (isHttps()) { skk_socket_.shutdownASyncSocketSsl(); } #endif // defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) close(socket_fd); } return result; } bool getHttpSuggest(SimpleStringForHairy &url_encode_word, float timeout) { http_receive_buffer_.reset(); http_send_string_.reset(); if (isHttps()) { http_send_string_.appendFast("GET https://www.google.com/complete/search?hl=ja&output=toolbar&q="); } else { http_send_string_.appendFast("GET http://www.google.com/complete/search?hl=ja&output=toolbar&q="); } { const int cr_lf_and_margin = 16; if (http_send_string_.getRemainSize() < url_encode_word.getSize() + cr_lf_and_margin) { return false; } } http_send_string_.appendFast(url_encode_word); http_send_string_.appendFast(",\x0d\x0a\x0d\x0a"); int socket_fd; if (isHttps()) { #if defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) socket_fd = skk_socket_.prepareASyncSocketSsl("www.google.com", "https", timeout, is_ipv6_); #else // defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) socket_fd = -1; #endif // defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) } else { socket_fd = skk_socket_.prepareASyncSocket("www.google.com", "http", timeout, is_ipv6_); } bool result = socket_fd >= 0; if (result) { int send_result = send(socket_fd); if (send_result == -1) { result = false; } if (result) { result = receive(socket_fd, timeout); } #if defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) if (isHttps()) { skk_socket_.shutdownASyncSocketSsl(); } #endif // defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) close(socket_fd); } return result; } // ǰΰ skk Хåեǧޤơޤ search_word ƱΤΤߤ֤Ƥʤе֤ޤ Lisp Ūʥɤ(ϤʤȤϻפޤ)ǰΰ٤˵֤ޤߤɬװʾˤĤƤ뤳ȤդɬפǤ static bool confirmSkk(SimpleStringForHairy &skk, const char *search_word, int search_word_size) { { const int offset_1_slash = 2; const int offset_1_slash_slash_crlf = offset_1_slash + 2; // search_word_size = sizeof("WORD") // search_word="WORD \n" // skk="1/WORD/\n" if (search_word_size == skk.getSize() - offset_1_slash_slash_crlf) { const char *skk_buffer = skk.getBuffer() + offset_1_slash; bool same_flag = true; for (int i = 0; i < search_word_size; ++i) { char c_search_word = *(search_word + i); char c_skk = *(skk_buffer + i); if (c_search_word != c_skk) { same_flag = false; break; } } if (same_flag) { return false; } } } skk.setReadIndex(0); for (;;) { char c; if (!skk.readCharacterAndAddReadIndex(c)) { DEBUG_PRINTF("failure readindex=%d\n", skk.getReadIndex()); return false; } if (c == 0) { break; } else if (c == '(') { const char concat[] = "concat "; const int nul_size = 1; for (int i = 0; i != sizeof(concat) - nul_size; ++i) { char concat_c = concat[i]; char skk_c; if (!skk.readCharacterAndAddReadIndex(skk_c)) { return false; } if (concat_c != skk_c) { return false; } } } } return true; } // HTTP إåΥơåĤġåפޤʥإåޤ 200 OK Ǥʤʤе֤ޤ static bool checkStatusAndSkipHttpHeader(SimpleStringForHairy &buffer) { int cr_lf_counter = 0; int previous_c = 0; bool first_line = true; bool first_space = false; bool second_space = false; SkkSimpleString status_code_string(256); for (;;) { if (!buffer.isAppendSize(1)) { return false; } char c; if (!buffer.readCharacterAndAddReadIndex(c)) { return false; } if (c == 0) { return false; } if (c == 0x0a) { if (first_line) { first_line = false; if (status_code_string.compare("200") != 0) { DEBUG_PRINTF("illegal status code=\"%s\"\n", status_code_string.getBuffer()); return false; } } if (previous_c == 0x0d) { ++cr_lf_counter; if (cr_lf_counter == 2) { break; } } } if ((c != 0x0d) && (c != 0x0a)) { cr_lf_counter = 0; } if (first_line) { if (c == ' ') { if (!second_space) { if (first_space) { second_space = true; } else { first_space = true; } } } else if (first_space && !second_space) { status_code_string.append(c); } } previous_c = c; } return true; } static bool isAppendGoogleJapanesInput(SimpleStringForHairy &string) { int length = string.getSize(); const char *p = string.getBuffer(); DEBUG_PRINTF("isAppendGoogleJapanesInput() %s length=%d\n", string.getBuffer(), string.getSize()); for (int i = 0; i < length; ++i) { int c_1 = static_cast(static_cast(*p++)); if (c_1 >= 0x80) { ++i; if (i >= length) { DEBUG_PRINTF("illegal string %s\n", string.getBuffer()); return false; } int c_2 = static_cast(static_cast(*p++)); if (c_1 == 0xa4) // Ҥ餬 { if ((c_2 < 0xa1) || (c_2 > 0xf3)) { return true; } } else if (c_1 == 0xa5) // { if ((c_2 < 0xa1) || (c_2 > 0xf6)) { return true; } } else if (c_1 == 0x8e) // Ⱦѥ { if ((c_2 < 0xa6) || (c_2 > 0xdf)) { return true; } } else if (c_1 == 0xa1) // Ĺ { if (c_2 != 0xbc) { return true; } } else { return true; } } else { return true; } } return false; } // json skk ɬפʺǽθꥹȤ SKK ΡѴʸ׷ǽ񤭹ߤޤҤ餬ʤޤϡȾѤޤ५ʤΤߤǹǤϺޤп֤ޤԤ skk ƤǤ static bool convertJsonToSkkCore(SimpleStringForHairy &json, SimpleStringForHairy &skk, SimpleStringForHairy &candidate_buffer, SimpleStringForHairy &iconv_buffer) { json.setReadIndex(0); skk.reset(); candidate_buffer.reset(); static const char protocol[] = "1/"; if (!skk.isAppendSize(sizeof(protocol))) { return false; } skk.appendFast(protocol); bool skk_write_flag = false; int kakko_counter = 0; bool double_quote_flag = false; bool concat_flag = false; int candidate_counter = 0; DEBUG_PRINTF("json:\"%s\"\n", json.getBuffer()); for (;;) { char c; if (!json.readCharacterAndAddReadIndex(c)) { return false; } if (c == 0) { if (skk_write_flag && !double_quote_flag) { break; } else { return false; } } else if (!skk_write_flag) { if (c == '[') { ++kakko_counter; if (kakko_counter >= 3) { skk_write_flag = true; } } } else if (!double_quote_flag) { if (c == '"') { double_quote_flag = true; concat_flag = false; candidate_buffer.reset(); } else if (c == ']') { if (skk_write_flag && !double_quote_flag) { break; } else { return false; } } } else if (c == '\\') { if (skk_write_flag) { char force; if (!json.readCharacterAndAddReadIndex(force)) { return false; } if (!skk.isAppendSize(2)) { return false; } skk.appendFast(c); skk.appendFast(force); } } else if (c == '"') { double_quote_flag = false; DEBUG_PRINTF("candidate_buffer:\"%s\"\n", candidate_buffer.getBuffer()); iconv_buffer.reset(); if (!convertIconv(candidate_buffer, iconv_buffer, "utf-8", "euc-jp")) { // convert fail skip } else { if (!isAppendGoogleJapanesInput(iconv_buffer)) { // ɲä٤ǤϤʤ(Ҥ餬ʥʤΤߤ)Τ skip DEBUG_PRINTF("isAppendGoogleJapanesInput() skip=%s\n", iconv_buffer.getBuffer()); } else { if (concat_flag) { static const char concat[] = "(concat \""; if (!skk.isAppendSize(sizeof(concat))) { return false; } skk.appendFast(concat); } if (!skk.isAppend(iconv_buffer)) { return false; } skk.appendFast(iconv_buffer); if (concat_flag) { static const char kokka[] = "\")"; if (!skk.isAppendSize(sizeof(kokka))) { return false; } skk.appendFast(kokka); } if (!skk.append('/')) { return false; } ++candidate_counter; } } } else { DEBUG_ASSERT(double_quote_flag); // \057 \073 ޤ candidate concat ˡ if ((c == '/') || (c == ';')) { concat_flag = true; if (!candidate_buffer.appendOctet(c)) { return false; } } else { if (!candidate_buffer.append(c)) { return false; } } } } if (!skk.append('\n')) { return false; } if (candidate_counter == 0) { return false; } return true; } // http_receive_buffer_ JSON ǡɬפǥꥹ (κǽΥꥹ) Τߤ SKK Ѵ skk_output_buffer_ ˽ϤޤԤ˵֤ޤԤ skk_output_buffer_ ƤǤ bool convertJsonToSkk() { if (!checkStatusAndSkipHttpHeader(http_receive_buffer_)) { return false; } if (!convertEscape4ToUtf8(http_receive_buffer_, work_a_buffer_)) { return false; } // λ http_receive_buffer_ ˲ƤʤΤǡ candidate buffer Ȥƺѡ http_send_buffer_ Ʊͤ iconv buffer Ȥƺѡ if (!convertJsonToSkkCore(work_a_buffer_, skk_output_buffer_, http_receive_buffer_, // candidate buffer http_send_buffer_)) // iconv buffer { DEBUG_PRINTF("FAILED convertJsonToSkkCore()\n"); return false; } DEBUG_PRINTF("success convertJsonToSkkCore()\n"); return true; } // json skk ɬפʺǽθꥹȤ SKK ΡѴʸ׷ǽ񤭹ߤޤп֤ޤԤ skk ƤǤ static bool convertXMLToSkkCore(SimpleStringForHairy &xml, SimpleStringForHairy &skk, SimpleStringForHairy &candidate_buffer, SimpleStringForHairy &iconv_buffer) { xml.setReadIndex(0); skk.reset(); candidate_buffer.reset(); static const char protocol[] = "1/"; if (!skk.isAppendSize(sizeof(protocol))) { return false; } skk.appendFast(protocol); bool skk_write_flag = false; int skip_double_quote_counter = 0; bool double_quote_flag = false; bool concat_flag = false; int candidate_counter = 0; DEBUG_PRINTF("xml:\"%s\"\n", xml.getBuffer()); for (;;) { char c; if (!xml.readCharacterAndAddReadIndex(c)) { return false; } if (c == 0) { if (skk_write_flag && !double_quote_flag) { break; } else { return false; } } else if (!skk_write_flag) { if (c == '"') { if (++skip_double_quote_counter >= 2) { skk_write_flag = true; } } } else if (!double_quote_flag) { if (c == '"') { double_quote_flag = true; concat_flag = false; candidate_buffer.reset(); } } else if (c == '\\') { if (skk_write_flag) { char force; if (!xml.readCharacterAndAddReadIndex(force)) { return false; } if (!skk.isAppendSize(2)) { return false; } skk.appendFast(c); skk.appendFast(force); } } else if (c == '"') { double_quote_flag = false; DEBUG_PRINTF("candidate_buffer:\"%s\"\n", candidate_buffer.getBuffer()); iconv_buffer.reset(); if (!convertIconv(candidate_buffer, iconv_buffer, "Shift_JIS", "euc-jp")) { // convert fail skip } else { if (concat_flag) { static const char concat[] = "(concat \""; if (!skk.isAppendSize(sizeof(concat))) { return false; } skk.appendFast(concat); } if (!skk.isAppend(iconv_buffer)) { return false; } skk.appendFast(iconv_buffer); if (concat_flag) { static const char kokka[] = "\")"; if (!skk.isAppendSize(sizeof(kokka))) { return false; } skk.appendFast(kokka); } if (!skk.append('/')) { return false; } ++candidate_counter; // ȤꤢǽΰĤ֤ break; } } else { DEBUG_ASSERT(double_quote_flag); // \057 \073 ޤ candidate concat ˡ if ((c == '/') || (c == ';')) { concat_flag = true; if (!candidate_buffer.appendOctet(c)) { return false; } } else { if (!candidate_buffer.append(c)) { return false; } } } } if (!skk.append('\n')) { return false; } if (candidate_counter == 0) { return false; } return true; } // http_receive_buffer_ XML ǡɬפǥꥹ (κǽΥꥹ) Τߤ SKK Ѵ skk_output_buffer_ ˽ϤޤԤ˵֤ޤԤ skk_output_buffer_ ƤǤ bool convertXMLToSkk() { if (!checkStatusAndSkipHttpHeader(http_receive_buffer_)) { return false; } if (!convertEscape4ToUtf8(http_receive_buffer_, work_a_buffer_)) { return false; } // λ http_receive_buffer_ ˲ƤʤΤǡ candidate buffer Ȥƺѡ http_send_buffer_ Ʊͤ iconv buffer Ȥƺѡ if (!convertXMLToSkkCore(work_a_buffer_, skk_output_buffer_, http_receive_buffer_, // candidate buffer http_send_buffer_)) // iconv buffer { return false; } return true; } private: SkkSocket skk_socket_; SimpleStringForHairy work_a_buffer_; SimpleStringForHairy work_b_buffer_; SimpleStringForHairy midashi_buffer_; SimpleStringForHairy http_send_buffer_; SimpleStringForHairy http_receive_buffer_; SimpleStringForHairy skk_output_buffer_; SimpleStringForHairy http_send_string_; SimpleCache cache_; bool is_https_; bool is_ipv6_; }; #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT class LocalSkkDictionary : public SkkDictionary { LocalSkkDictionary(LocalSkkDictionary &source); LocalSkkDictionary& operator=(LocalSkkDictionary &source); public: ~LocalSkkDictionary() { } LocalSkkDictionary() : SkkDictionary(), google_japanese_input_flag_(false), google_suggest_flag_(false), is_https_(true) { } bool isGoogleJapaneseInput() const { return google_japanese_input_flag_; } void setGoogleJapaneseInputFlag(bool flag, bool is_https) { google_japanese_input_flag_ = flag; is_https_ = is_https; } bool isGoogleSuggest() const { return google_suggest_flag_; } void setGoogleSuggestFlag(bool flag, bool is_https) { google_suggest_flag_ = flag; is_https_ = is_https; } bool isHttps() const { return is_https_; } private: bool google_japanese_input_flag_; bool google_suggest_flag_; bool is_https_; }; class LocalSkkServer : private SkkServer { LocalSkkServer(LocalSkkServer &source); LocalSkkServer& operator=(LocalSkkServer &source); public: enum GoogleJapaneseInputType { GOOGLE_JAPANESE_INPUT_TYPE_DISABLE, GOOGLE_JAPANESE_INPUT_TYPE_NOTFOUND, GOOGLE_JAPANESE_INPUT_TYPE_NOTFOUND_SUGGEST_INPUT, GOOGLE_JAPANESE_INPUT_TYPE_NOTFOUND_INPUT_SUGGEST, GOOGLE_JAPANESE_INPUT_TYPE_DICTIONARY }; virtual ~LocalSkkServer() { } LocalSkkServer(int port = 1178, int log_level = 0, const char *address = "0.0.0.0") : SkkServer("yaskkserv_" SERVER_IDENTIFIER, port, log_level, address), skk_dictionary_(0), dictionary_filename_table_(0), #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT google_japanese_input_(), google_japanese_input_type_(GOOGLE_JAPANESE_INPUT_TYPE_DISABLE), google_japanese_input_timeout_(2.5f), #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST google_suggest_(), #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST google_suggest_flag_(false), google_cache_file_(0), #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT skk_dictionary_length_(0), max_connection_(0), listen_queue_(0), server_completion_midasi_length_(0), server_completion_midasi_string_size_(0), server_completion_test_(1), server_completion_test_protocol_('4'), dictionary_check_update_flag_(false), no_daemonize_flag_(false), use_http_flag_(false) { } void initialize(LocalSkkDictionary *skk_dictionary, const char * const *dictionary_filename_table, int skk_dictionary_length, int max_connection, int listen_queue, int server_completion_midasi_length, int server_completion_midasi_string_size, int server_completion_test, int google_cache_entries, #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT const char *google_cache_file, #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT bool dictionary_check_update_flag, bool no_daemonize_flag, bool use_http_flag, bool use_ipv6_flag) { #ifndef YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT (void)use_ipv6_flag; #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT skk_dictionary_ = skk_dictionary; dictionary_filename_table_ = dictionary_filename_table; skk_dictionary_length_ = skk_dictionary_length; max_connection_ = max_connection; listen_queue_ = listen_queue; server_completion_midasi_length_ = server_completion_midasi_length; server_completion_midasi_string_size_ = server_completion_midasi_string_size; server_completion_test_ = server_completion_test; dictionary_check_update_flag_ = dictionary_check_update_flag; no_daemonize_flag_ = no_daemonize_flag; use_http_flag_ = use_http_flag; #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT google_japanese_input_.createCache(google_cache_entries); google_japanese_input_.setIpv6Flag(use_ipv6_flag); #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST google_suggest_.createCache(google_cache_entries); google_suggest_.setIpv6Flag(use_ipv6_flag); #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST google_cache_file_ = google_cache_file; if (use_http_flag) { google_japanese_input_.setHttpsFlag(false); #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST google_suggest_.setHttpsFlag(false); #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST } // google japanese input google suggest ϡ줾 1 ĤǤʤȤա for (int i = 0; i != skk_dictionary_length; ++i) { if ((skk_dictionary_ + i)->isGoogleJapaneseInput()) { google_japanese_input_.setHttpsFlag((skk_dictionary_ + i)->isHttps()); syslog_.printf(1, SkkSyslog::LEVEL_INFO, "google japanese input dictionary found (index=%d)", i); } #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST else if ((skk_dictionary_ + i)->isGoogleSuggest()) { google_suggest_.setHttpsFlag((skk_dictionary_ + i)->isHttps()); syslog_.printf(1, SkkSyslog::LEVEL_INFO, "google suggest dictionary found (index=%d)", i); } #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST } syslog_.printf(1, SkkSyslog::LEVEL_INFO, "google japanese input (protocol=%s)", google_japanese_input_.isHttps() ? "https" : "http"); #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST syslog_.printf(1, SkkSyslog::LEVEL_INFO, "google suggest (protocol=%s)", google_suggest_.isHttps() ? "https" : "http"); #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT } #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT void setGoogleJapaneseInputParameter(GoogleJapaneseInputType type, float timeout) { google_japanese_input_type_ = type; google_japanese_input_timeout_ = timeout; } #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST void setGoogleSuggestParameter(bool flag) { google_suggest_flag_ = flag; } #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT bool mainLoop() { bool result = main_loop_initialize(max_connection_, listen_queue_); if (result) { #ifndef YASKKSERV_DEBUG if (!no_daemonize_flag_) { if (fork() != 0) { exit(0); } if (chdir("/") != 0) { // why? } close(2); close(1); close(0); printFirstSyslog(); } #endif // YASKKSERV_DEBUG result = local_main_loop(); if (result) { result = main_loop_finalize(); } } return result; } private: bool local_main_loop_loop(fd_set &fd_set_read); void local_main_loop_sighup(); bool local_main_loop(); #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT bool local_main_loop_1_google_japanese_input(int work_index); bool local_main_loop_1_google_suggest(int work_index); #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT bool local_main_loop_1_search_single_dictionary(int work_index); void main_loop_get_plural_dictionary_information(int work_index, LocalSkkDictionary *skk_dictionary, int skk_dictionary_length, int &found_times, int &candidate_length, int &total_henkanmojiretsu_size, const char *&google_japanese_input_candidates, const char *&google_suggest_candidates); static bool add_candidates_string(SkkUtility::Hash &hash, SkkSimpleString &candidates_string, const char *add_c_string); bool local_main_loop_1_search_plural_dictionary(int work_index, int candidate_length, int total_henkanmojiretsu_size, const char *google_japanese_input_candidates, const char *google_suggest_candidates); bool local_main_loop_1_search(int work_index); #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT bool local_main_loop_1_notfound(int work_index); #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST bool local_main_loop_1_notfound_first_second(int work_index, const char *&first, const char *&second); bool local_main_loop_1_notfound_suggest_input(int work_index); bool local_main_loop_1_notfound_input_suggest(int work_index); #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT /// ХåեꥻåȤ٤ʤп֤ޤ bool local_main_loop_1(int work_index, int recv_result); bool local_main_loop_4_search_core(int work_index, int recv_result, SkkUtility::Hash *hash, SkkSimpleString &string); bool local_main_loop_4_search(int work_index, int recv_result); /// ХåեꥻåȤ٤ʤп֤ޤ bool local_main_loop_4(int work_index, int recv_result); void print_syslog_cache_information(); #if defined(YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT) && (defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL)) void save_cache_file(const char *filename); void load_cache_file_read_all(const char header[64], int fd, int file_size, int bitflags); void load_cache_file(const char *filename); #endif // defined(YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT) && (defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL)) private: LocalSkkDictionary *skk_dictionary_; const char * const *dictionary_filename_table_; #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT GoogleJapaneseInput google_japanese_input_; GoogleJapaneseInputType google_japanese_input_type_; float google_japanese_input_timeout_; #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST GoogleJapaneseInput google_suggest_; #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST bool google_suggest_flag_; const char *google_cache_file_; #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT int skk_dictionary_length_; int max_connection_; int listen_queue_; int server_completion_midasi_length_; int server_completion_midasi_string_size_; int server_completion_test_; char server_completion_test_protocol_; bool dictionary_check_update_flag_; bool no_daemonize_flag_; bool use_http_flag_; }; #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT bool LocalSkkServer::local_main_loop_1_google_japanese_input(int work_index) { bool result = false; const char *candidates = google_japanese_input_.getSkkCandidatesEuc((work_ + work_index)->read_buffer + 1, google_japanese_input_timeout_); if (candidates) { if (!send((work_ + work_index)->file_descriptor, candidates, GoogleJapaneseInput::getByteSize(candidates))) { (work_ + work_index)->closeAndReset(); } result = true; } return result; } bool LocalSkkServer::local_main_loop_1_google_suggest(int work_index) { #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST bool result = false; const char *candidates = google_suggest_.getSkkCandidatesEucSuggest((work_ + work_index)->read_buffer + 1, google_japanese_input_timeout_); if (candidates) { if (!send((work_ + work_index)->file_descriptor, candidates, GoogleJapaneseInput::getByteSize(candidates))) { (work_ + work_index)->closeAndReset(); } result = true; } return result; #else // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST (void)work_index; return false; #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST } #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT bool LocalSkkServer::local_main_loop_1_search_single_dictionary(int work_index) { bool result = false; #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT if (skk_dictionary_->isGoogleJapaneseInput()) { const char *candidates = google_japanese_input_.getSkkCandidatesEuc((work_ + work_index)->read_buffer + 1, google_japanese_input_timeout_); if (candidates) { if (!send((work_ + work_index)->file_descriptor, candidates, GoogleJapaneseInput::getByteSize(candidates))) { (work_ + work_index)->closeAndReset(); } result = true; } } #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST else if (skk_dictionary_->isGoogleSuggest() && google_suggest_flag_) { const char *candidates = google_suggest_.getSkkCandidatesEucSuggest((work_ + work_index)->read_buffer + 1, google_japanese_input_timeout_); if (candidates) { if (!send((work_ + work_index)->file_descriptor, candidates, GoogleJapaneseInput::getByteSize(candidates))) { (work_ + work_index)->closeAndReset(); } result = true; } } #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST else #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT { if (skk_dictionary_->search((work_ + work_index)->read_buffer + 1)) { main_loop_send_found(work_index, skk_dictionary_); result = true; } } return result; } void LocalSkkServer::main_loop_get_plural_dictionary_information(int work_index, LocalSkkDictionary *skk_dictionary, int skk_dictionary_length, int &found_times, int &candidate_length, int &total_henkanmojiretsu_size, const char *&google_japanese_input_candidates, const char *&google_suggest_candidates) { found_times = 0; candidate_length = 0; total_henkanmojiretsu_size = 0; google_japanese_input_candidates = 0; google_suggest_candidates = 0; for (int h = 0; h != skk_dictionary_length; ++h) { #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT if ((skk_dictionary + h)->isGoogleJapaneseInput()) { google_japanese_input_candidates = google_japanese_input_.getSkkCandidatesEuc((work_ + work_index)->read_buffer + 1, google_japanese_input_timeout_); if (google_japanese_input_candidates) { const int protocol_1_offset = 1; DEBUG_PRINTF("henkanmojiretsu_size=%d\n", SkkUtility::getStringLength(google_japanese_input_candidates + protocol_1_offset)); DEBUG_PRINTF("candidate_length=%d\n", SkkUtility::getCandidateLength(google_japanese_input_candidates + protocol_1_offset)); total_henkanmojiretsu_size += SkkUtility::getStringLength(google_japanese_input_candidates + protocol_1_offset); candidate_length += SkkUtility::getCandidateLength(google_japanese_input_candidates + protocol_1_offset); ++found_times; } } #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST else if ((skk_dictionary + h)->isGoogleSuggest() && google_suggest_flag_) { google_suggest_candidates = google_suggest_.getSkkCandidatesEucSuggest((work_ + work_index)->read_buffer + 1, google_japanese_input_timeout_); if (google_suggest_candidates) { const int protocol_1_offset = 1; DEBUG_PRINTF("henkanmojiretsu_size=%d\n", SkkUtility::getStringLength(google_suggest_candidates + protocol_1_offset)); DEBUG_PRINTF("candidate_length=%d\n", SkkUtility::getCandidateLength(google_suggest_candidates + protocol_1_offset)); total_henkanmojiretsu_size += SkkUtility::getStringLength(google_suggest_candidates + protocol_1_offset); candidate_length += SkkUtility::getCandidateLength(google_suggest_candidates + protocol_1_offset); ++found_times; } } #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST else #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT { if ((skk_dictionary + h)->search((work_ + work_index)->read_buffer + 1)) { const int cr_size = 1; total_henkanmojiretsu_size += (skk_dictionary + h)->getHenkanmojiretsuSize() + cr_size; candidate_length += SkkUtility::getCandidateLength((skk_dictionary + h)->getHenkanmojiretsuPointer()); ++found_times; } } } } #pragma GCC diagnostic push #ifndef YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT #pragma GCC diagnostic ignored "-Wunused-parameter" #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT bool LocalSkkServer::add_candidates_string(SkkUtility::Hash &hash, SkkSimpleString &candidates_string, const char *add_c_string) { DEBUG_ASSERT_POINTER(add_c_string); int length = SkkUtility::getCandidateLength(add_c_string); for (int i = 0; i != length; ++i) { const char *start; int size; if (SkkUtility::getCandidateInformation(add_c_string, i, start, size)) { if (!hash.contain(start, size)) { hash.add(start, size); const int tail_slash_size = 1; if (!candidates_string.append(start, size + tail_slash_size)) { return false; } } } else { return false; } } return true; } bool LocalSkkServer::local_main_loop_1_search_plural_dictionary(int work_index, int candidate_length, int total_henkanmojiretsu_size, const char *google_japanese_input_candidates, const char *google_suggest_candidates) { #ifndef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST (void)google_suggest_candidates; #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST // candidate_length Ŭ hash_table_length Ѵޤ int hash_table_length = SkkUtility::Hash::getPrimeHashTableLength(candidate_length); if (hash_table_length == 0) { return false; } // դäʣμ candidate ʬ򡢹ޤ // ʸ string ɲäޤʣå hash Ǥʤޤ // Ѵʸ󥵥˥ޡäΤ temporary_buffer_size Ȥ // ޤ int temporary_buffer_size = total_henkanmojiretsu_size; { const int protocol_header_margin_size = 8; const int terminator_size = 1; const int margin_size = 8; temporary_buffer_size += protocol_header_margin_size; temporary_buffer_size += terminator_size; temporary_buffer_size += margin_size; } SkkSimpleString string(temporary_buffer_size); SkkUtility::Hash hash(hash_table_length); // protocol header + first slash string.appendFast("1/"); for (int h = 0; h != skk_dictionary_length_; ++h) { const char *p = 0; #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT if ((skk_dictionary_ + h)->isGoogleJapaneseInput() && google_japanese_input_candidates) { const int protocol_1_offset = 1; p = google_japanese_input_candidates + protocol_1_offset; } #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST else if ((skk_dictionary_ + h)->isGoogleSuggest() && google_suggest_candidates && google_suggest_flag_) { const int protocol_1_offset = 1; p = google_suggest_candidates + protocol_1_offset; } #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST else if ((skk_dictionary_ + h)->isSuccess()) { p = (skk_dictionary_ + h)->getHenkanmojiretsuPointer(); } #else // YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT if ((skk_dictionary_ + h)->isSuccess()) { p = (skk_dictionary_ + h)->getHenkanmojiretsuPointer(); } #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT if (p) { if (!add_candidates_string(hash, string, p)) { return false; } } } if (!string.append('\n')) { return false; } if (!send((work_ + work_index)->file_descriptor, string.getBuffer(), string.getSize())) { (work_ + work_index)->closeAndReset(); } return true; } #pragma GCC diagnostic pop bool LocalSkkServer::local_main_loop_1_search(int work_index) { // // õϡޤ˰ʲΤ褦ʬޤ // // - ꤵ줿 1 Ĥξ // // - ꤵ줿ʣξ // // = ȥ꤬ 1 ĤμǤդʤä // // = ȥ꤬ʣμǸդä // if (skk_dictionary_length_ == 1) { // ꤵ줿 1 ġ return local_main_loop_1_search_single_dictionary(work_index); } // ꤵ줿ʣ int found_times; int candidate_length; int total_henkanmojiretsu_size; const char *google_japanese_input_candidates; const char *google_suggest_candidates; main_loop_get_plural_dictionary_information(work_index, skk_dictionary_, skk_dictionary_length_, found_times, candidate_length, total_henkanmojiretsu_size, google_japanese_input_candidates, google_suggest_candidates); if (found_times == 0) { // դʤä return false; } if (found_times == 1) { // ȥ꤬ 1 ĤμǤդʤä for (int h = 0; h != skk_dictionary_length_; ++h) { #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT if ((skk_dictionary_ + h)->isGoogleJapaneseInput() && google_japanese_input_candidates) { if (!send((work_ + work_index)->file_descriptor, google_japanese_input_candidates, GoogleJapaneseInput::getByteSize(google_japanese_input_candidates))) { (work_ + work_index)->closeAndReset(); } } #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST else if ((skk_dictionary_ + h)->isGoogleSuggest() && google_suggest_candidates && google_suggest_flag_) { if (!send((work_ + work_index)->file_descriptor, google_suggest_candidates, GoogleJapaneseInput::getByteSize(google_suggest_candidates))) { (work_ + work_index)->closeAndReset(); } } #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST else if ((skk_dictionary_ + h)->isSuccess()) { main_loop_send_found(work_index, skk_dictionary_ + h); } #else // YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT if ((skk_dictionary_ + h)->isSuccess()) { main_loop_send_found(work_index, skk_dictionary_ + h); } #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT } return true; } // ȥ꤬ʣμǸդä return local_main_loop_1_search_plural_dictionary(work_index, candidate_length, total_henkanmojiretsu_size, google_japanese_input_candidates, google_suggest_candidates); } #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT bool LocalSkkServer::local_main_loop_1_notfound(int work_index) { bool found_flag = false; if (google_suggest_flag_) { if (google_japanese_input_type_ == GOOGLE_JAPANESE_INPUT_TYPE_NOTFOUND) { found_flag = local_main_loop_1_google_suggest(work_index); } } else { if (google_japanese_input_type_ == GOOGLE_JAPANESE_INPUT_TYPE_NOTFOUND) { found_flag = local_main_loop_1_google_japanese_input(work_index); } } return found_flag; } #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST bool LocalSkkServer::local_main_loop_1_notfound_first_second(int work_index, const char *&first, const char *&second) { int found_times = 0; int candidate_length = 0; int total_henkanmojiretsu_size = 0; const int protocol_1_offset = 1; if (first) { total_henkanmojiretsu_size += SkkUtility::getStringLength(first + protocol_1_offset); candidate_length += SkkUtility::getCandidateLength(first + protocol_1_offset); ++found_times; } if (second) { total_henkanmojiretsu_size += SkkUtility::getStringLength(second + protocol_1_offset); candidate_length += SkkUtility::getCandidateLength(second + protocol_1_offset); ++found_times; } if (found_times == 0) { return false; } else if (found_times == 1) { bool result = false; const char *candidates = first ? first : second; DEBUG_ASSERT_POINTER(candidates); if (candidates) { if (!send((work_ + work_index)->file_descriptor, candidates, GoogleJapaneseInput::getByteSize(candidates))) { (work_ + work_index)->closeAndReset(); } result = true; } return result; } else { int temporary_buffer_size = total_henkanmojiretsu_size; { const int protocol_header_margin_size = 8; const int terminator_size = 1; const int margin_size = 8; temporary_buffer_size += protocol_header_margin_size; temporary_buffer_size += terminator_size; temporary_buffer_size += margin_size; } SkkSimpleString string(temporary_buffer_size); string.appendFast("1/"); // candidate_length Ŭ hash_table_length Ѵޤ int hash_table_length = SkkUtility::Hash::getPrimeHashTableLength(candidate_length); if (hash_table_length == 0) { return false; } SkkUtility::Hash hash(hash_table_length); if (!add_candidates_string(hash, string, first + protocol_1_offset)) { return false; } if (!add_candidates_string(hash, string, second + protocol_1_offset)) { return false; } if (!string.append('\n')) { return false; } if (!send((work_ + work_index)->file_descriptor, string.getBuffer(), string.getSize())) { (work_ + work_index)->closeAndReset(); } } return true; } bool LocalSkkServer::local_main_loop_1_notfound_suggest_input(int work_index) { const char *google_suggest_candidates = google_suggest_.getSkkCandidatesEucSuggest((work_ + work_index)->read_buffer + 1, google_japanese_input_timeout_); const char *google_japanese_input_candidates = google_japanese_input_.getSkkCandidatesEuc((work_ + work_index)->read_buffer + 1, google_japanese_input_timeout_); return local_main_loop_1_notfound_first_second(work_index, google_suggest_candidates, google_japanese_input_candidates); } bool LocalSkkServer::local_main_loop_1_notfound_input_suggest(int work_index) { const char *google_japanese_input_candidates = google_japanese_input_.getSkkCandidatesEuc((work_ + work_index)->read_buffer + 1, google_japanese_input_timeout_); const char *google_suggest_candidates = google_suggest_.getSkkCandidatesEucSuggest((work_ + work_index)->read_buffer + 1, google_japanese_input_timeout_); return local_main_loop_1_notfound_first_second(work_index, google_japanese_input_candidates, google_suggest_candidates); } #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT bool LocalSkkServer::local_main_loop_1(int work_index, int recv_result) { bool illegal_protocol_flag; bool result = main_loop_check_buffer(work_index, recv_result, illegal_protocol_flag); if (result) { bool found_flag = false; if (!illegal_protocol_flag) { #ifdef YASKKSERV_DEBUG struct timeval time_begin; struct timeval time_end; gettimeofday(&time_begin, 0); #endif // YASKKSERV_DEBUG found_flag = local_main_loop_1_search(work_index); #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT if (!found_flag) { switch (google_japanese_input_type_) { default: DEBUG_ASSERT(0); break; case GOOGLE_JAPANESE_INPUT_TYPE_DISABLE: // FALLTHROUGH case GOOGLE_JAPANESE_INPUT_TYPE_DICTIONARY: break; case GOOGLE_JAPANESE_INPUT_TYPE_NOTFOUND: found_flag = local_main_loop_1_notfound(work_index); break; case GOOGLE_JAPANESE_INPUT_TYPE_NOTFOUND_SUGGEST_INPUT: #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST found_flag = local_main_loop_1_notfound_suggest_input(work_index); #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST break; case GOOGLE_JAPANESE_INPUT_TYPE_NOTFOUND_INPUT_SUGGEST: #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST found_flag = local_main_loop_1_notfound_input_suggest(work_index); #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST break; } } #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT #ifdef YASKKSERV_DEBUG gettimeofday(&time_end, 0); unsigned long long usec_begin = static_cast(time_begin.tv_sec * 1000 * 1000 + time_begin.tv_usec); unsigned long long usec_end = static_cast(time_end.tv_sec * 1000 * 1000 + time_end.tv_usec); DEBUG_PRINTF("ms.=%f\n", static_cast(usec_end - usec_begin) / 1000.0f); #endif // YASKKSERV_DEBUG } if (!found_flag) { main_loop_send_not_found(work_index, recv_result); } } return result; } bool LocalSkkServer::local_main_loop_4_search_core(int work_index, int recv_result, SkkUtility::Hash *hash, SkkSimpleString &string) { // դäΡָФפޤȤޤ // ָФפϡ֤Ҥ餬ʥ󥳡ɡפƤ뤳ȤդɬפǤ char decode_buffer[SkkUtility::MIDASI_DECODE_HIRAGANA_BUFFER_SIZE]; switch (server_completion_test_) { default: // FALLTHROUGH DEBUG_ASSERT(0); case 2: // FALLTHROUGH case 1: string.appendFast("1/"); break; case 3: string.appendFast("1 "); break; case 4: if (server_completion_test_protocol_ == '4') { string.appendFast("1/"); } else { string.appendFast("1 "); } break; } int add_counter = 0; for (int h = 0; h != skk_dictionary_length_; ++h) { if (!(skk_dictionary_ + h)->isGoogleJapaneseInput() && !(skk_dictionary_ + h)->isGoogleSuggest() && (skk_dictionary_ + h)->isSuccess()) { bool found_flag = false; do { const char *p = (skk_dictionary_ + h)->getMidasiPointer(); // DecodeHiragana() ϥߥ͡¸ߤʤȤդɬפǤ // size ⥿ߥ͡ޤޤʤǤ int size = SkkUtility::decodeHiragana(p, decode_buffer, sizeof(decode_buffer)); if (size == 0) { const int raw_code = 1; // \1 ʬ p += raw_code; size = (skk_dictionary_ + h)->getMidasiSize() - raw_code; } else { p = decode_buffer; } if (SkkSimpleString::startWith(p, (work_ + work_index)->read_buffer + 1, size, (work_ + work_index)->read_process_index + recv_result - 1)) { found_flag = true; } else { if (found_flag) { break; } else { continue; } } if (SkkUtility::isOkuriNasiOrAbbrev(p, size)) { if ((hash == 0) || !hash->contain(p, size)) { if ((server_completion_test_ == 2) && SkkSimpleString::search(p, '/', size)) { // ignore slash } else { const int separator_size = 1; if (!string.isAppendSize(size + separator_size)) { return false; } const char *current = string.getCurrentBuffer(); string.append(p, size); switch (server_completion_test_) { default: DEBUG_ASSERT(0); // FALLTHROUGH case 1: string.appendFast('/'); // + separator_size break; case 3: string.appendFast(' '); // + separator_size break; case 4: if (server_completion_test_protocol_ == '4') { string.appendFast('/'); // + separator_size } else { string.appendFast(' '); // + separator_size } break; } // ץȥ "4" Ǥϥ꡼ɥХåեưŪ˽񤭴뤿ᡢľܥ꡼ // ɥХåե򻲾ȤƤϤʤޤ󡣤μǤ string ХåեȤ // ѤƤޤ if (hash) { if (!hash->add(current, size)) { return false; } } if (++add_counter >= server_completion_midasi_length_) { return false; } } } } } while ((skk_dictionary_ + h)->searchNextEntry()); } } #ifdef YASKKSERV_DEBUG if (hash) { int counter; int offset_max; double average; hash->getDebugBuildInformation(counter, offset_max, average); DEBUG_PRINTF("counter=%d\n" "offset_max=%d\n" "average=%f\n" , counter, offset_max, average); } #endif // YASKKSERV_DEBUG if (add_counter == 0) { return false; } if (!string.append('\n')) { return false; } return true; } bool LocalSkkServer::local_main_loop_4_search(int work_index, int recv_result) { // // 1. ָФפꤢפʤ¨¤˵֤ޤ // // 2. ָФפõޤ // // 3. ָФפդä硢Υȥ꤫ SearchNextEntry() // Ϥޤ // // 4. ָФפդʤä硢Υȥ꤬ޤޤƤǤ // ֥åƬ SearchNextEntry() 򳫻Ϥޤ // if (SkkUtility::isOkuriAri((work_ + work_index)->read_buffer + 1, recv_result - 1)) { return false; } int found_times = 0; for (int h = 0; h != skk_dictionary_length_; ++h) { if (!(skk_dictionary_ + h)->isGoogleJapaneseInput() && !(skk_dictionary_ + h)->isGoogleSuggest()) { if ((skk_dictionary_ + h)->search((work_ + work_index)->read_buffer + 1) || (skk_dictionary_ + h)->searchForFirstCharacter((work_ + work_index)->read_buffer + 1)) { ++found_times; } } } if (found_times == 0) { // դʤä return false; } SkkSimpleString string(server_completion_midasi_string_size_); { SkkUtility::Hash *hash = 0; if (found_times > 1) { // ʣåɬפʤΤʣμǤ int prime_length = SkkUtility::Hash::getPrimeHashTableLength(server_completion_midasi_length_); hash = new SkkUtility::Hash(prime_length); } bool core_result = local_main_loop_4_search_core(work_index, recv_result, hash, string); delete hash; if (!core_result) { syslog_.printf(1, SkkSyslog::LEVEL_WARNING, "server completion failed"); return false; } } if (!send((work_ + work_index)->file_descriptor, string.getBuffer(), string.getSize())) { (work_ + work_index)->closeAndReset(); } return true; } bool LocalSkkServer::local_main_loop_4(int work_index, int recv_result) { bool illegal_protocol_flag; bool result = main_loop_check_buffer(work_index, recv_result, illegal_protocol_flag); if (result) { bool found_flag = false; if (!illegal_protocol_flag) { found_flag = local_main_loop_4_search(work_index, recv_result); } if (!found_flag) { main_loop_send_not_found(work_index, recv_result); } } return result; } #if defined(YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT) && (defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL)) void LocalSkkServer::print_syslog_cache_information() { int fast_entries; int fast_index; int large_entries; int large_index; google_japanese_input_.getCacheBufferInformation(fast_entries, fast_index, large_entries, large_index); syslog_.printf(1, SkkSyslog::LEVEL_INFO, "google japanese input:"); syslog_.printf(1, SkkSyslog::LEVEL_INFO, " fast entries=%d fast index=%d large entries=%d large index=%d", fast_entries, fast_index, large_entries, large_index); #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST google_suggest_.getCacheBufferInformation(fast_entries, fast_index, large_entries, large_index); syslog_.printf(1, SkkSyslog::LEVEL_INFO, "google suggest:"); syslog_.printf(1, SkkSyslog::LEVEL_INFO, " fast entries=%d fast index=%d large entries=%d large index=%d", fast_entries, fast_index, large_entries, large_index); #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST } // ** cache file format // 0 : "yaskkserv cache" (16bytes) // 16 : version (4bytes) // 20 : filesize (4bytes) // 24 : bitflags (bit0: google japanese input Cache bit1: google suggest Cache) // 28 : reserved // 32-47 : md5 (16bytes md5 reserved 0 ξ֤Ǥΰ md5) // 48-63 : reserved // 64 : google japanese input CacheUnit // N : google suggest CacheUnit // // *** CacheUnit format // // 0 fast_entries_ // 4 fast_index_ // 8 large_entries_ // 12 large_index_ // FastKey // FastValue // LargeKey // LargeValue // // *** load εư // // С󤬰ۤʤмԡ // // md5 ۤʤмԡ // // entries Ʊ yaskkserv entries 礭ʤäƤФΤޤ // ɡ index load ͤ͡򸡽Ф顢λǼ // Cache ؤϽ񤭹ޤʤ // // yaskkserv entries ʤäƤɤ߹ʬɤ // index 0 ˡ void LocalSkkServer::save_cache_file(const char *filename) { int cache_buffer_size = google_japanese_input_.getCacheBufferSize(); #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST cache_buffer_size += google_suggest_.getCacheBufferSize(); #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST if (cache_buffer_size <= 0) { syslog_.printf(1, SkkSyslog::LEVEL_WARNING, "save cache failed (illegal cache_buffer_size)"); return; } const int header_size = 64; const int margin_footer_size = 64; const int file_size = header_size + cache_buffer_size; const int buffer_size = file_size + margin_footer_size; DEBUG_PRINTF("file_size:%d buffer_size:%d\n", file_size, buffer_size); char *buffer_top = new char[buffer_size]; DEBUG_PRINTF("buffer_top=%p\n", buffer_top); if (buffer_top == 0) { syslog_.printf(1, SkkSyslog::LEVEL_WARNING, "save cache failed (memory allocation error)"); return; } SkkUtility::clearMemory(buffer_top, buffer_size); const char header_keyword[16] = "yaskkserv cache"; const int version = 1; int bitflags = 0x1 << 0; #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST bitflags |= 0x1 << 1; #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST SkkUtility::copyMemory(header_keyword, buffer_top + 0, sizeof(header_keyword)); SkkUtility::copyMemory(&version, buffer_top + 16, sizeof(version)); SkkUtility::copyMemory(&file_size, buffer_top + 20, sizeof(file_size)); SkkUtility::copyMemory(&bitflags, buffer_top + 24, sizeof(bitflags)); char *cache_unit_buffer = buffer_top + 64; DEBUG_PRINTF("cache_unit_buffer=%p buffer_top=%p diff=%d\n", cache_unit_buffer, buffer_top, cache_unit_buffer - buffer_top); cache_unit_buffer = google_japanese_input_.getCacheForSave(cache_unit_buffer); DEBUG_PRINTF("cache_unit_buffer=%p buffer_top=%p diff=%d\n", cache_unit_buffer, buffer_top, cache_unit_buffer - buffer_top); #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST cache_unit_buffer = google_suggest_.getCacheForSave(cache_unit_buffer); DEBUG_PRINTF("cache_unit_buffer=%p buffer_top=%p diff=%d\n", cache_unit_buffer, buffer_top, cache_unit_buffer - buffer_top); #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST if (cache_unit_buffer - buffer_top != file_size) { syslog_.printf(1, SkkSyslog::LEVEL_WARNING, "save cache failed (illegal file size)"); DEBUG_ASSERT(0); } else { unsigned char md5[MD5_DIGEST_LENGTH]; MD5_CTX ctx; MD5_Init(&ctx); MD5_Update(&ctx, buffer_top, file_size); MD5_Final(md5, &ctx); SkkUtility::copyMemory(md5, buffer_top + 32, sizeof(md5)); DEBUG_PRINTF("md5:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", md5[0], md5[1], md5[2], md5[3], md5[4], md5[5], md5[6], md5[7], md5[8], md5[9], md5[10], md5[11], md5[12], md5[13], md5[14], md5[15]); int fd = open(filename, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR); if (fd < 0) { syslog_.printf(1, SkkSyslog::LEVEL_WARNING, "save cache failed (file open error)"); } else { if (write(fd, buffer_top, file_size) != file_size) { syslog_.printf(1, SkkSyslog::LEVEL_WARNING, "save cache failed (file write error)"); } else { print_syslog_cache_information(); } close(fd); } } delete[] buffer_top; } void LocalSkkServer::load_cache_file_read_all(const char header[64], int fd, int file_size, int bitflags) { unsigned char header_md5[MD5_DIGEST_LENGTH]; SkkUtility::copyMemory(&header[32], header_md5, sizeof(header_md5)); const int margin_footer_size = 64; const int buffer_size = file_size + margin_footer_size; char *buffer_top = new char[buffer_size]; if (buffer_top == 0) { syslog_.printf(1, SkkSyslog::LEVEL_WARNING, "load cache failed (memory allocation error size=%d)", buffer_size); return; } lseek(fd, 0, SEEK_SET); if (read(fd, buffer_top, file_size) != file_size) { syslog_.printf(1, SkkSyslog::LEVEL_WARNING, "load cache failed (file read error)"); } else { unsigned char test_md5[MD5_DIGEST_LENGTH]; // md5 ΰ褬 0 md5 ΤǡꥢƤ뤳Ȥա SkkUtility::clearMemory(buffer_top + 32, sizeof(header_md5)); MD5_CTX ctx; MD5_Init(&ctx); MD5_Update(&ctx, buffer_top, file_size); MD5_Final(test_md5, &ctx); DEBUG_PRINTF("header_md5:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", header_md5[0], header_md5[1], header_md5[2], header_md5[3], header_md5[4], header_md5[5], header_md5[6], header_md5[7], header_md5[8], header_md5[9], header_md5[10], header_md5[11], header_md5[12], header_md5[13], header_md5[14], header_md5[15]); DEBUG_PRINTF("test_md5:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", test_md5[0], test_md5[1], test_md5[2], test_md5[3], test_md5[4], test_md5[5], test_md5[6], test_md5[7], test_md5[8], test_md5[9], test_md5[10], test_md5[11], test_md5[12], test_md5[13], test_md5[14], test_md5[15]); if (memcmp(header_md5, test_md5, sizeof(header_md5)) != 0) { syslog_.printf(1, SkkSyslog::LEVEL_WARNING, "load cache failed (md5 error)"); } else { const char *cache_unit_buffer = google_japanese_input_.verifyBufferForLoad(buffer_top + 64); if (cache_unit_buffer == 0) { syslog_.printf(1, SkkSyslog::LEVEL_WARNING, "load cache failed (google japanese input verify error)"); } else { DEBUG_PRINTF("bitflags:%08x\n", bitflags); #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST if (bitflags & (0x1 << 1)) { cache_unit_buffer = google_suggest_.verifyBufferForLoad(cache_unit_buffer); } #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST if (cache_unit_buffer == 0) { syslog_.printf(1, SkkSyslog::LEVEL_WARNING, "load cache failed (google suggest verify error)"); } else { cache_unit_buffer = google_japanese_input_.setCacheForLoad(buffer_top + 64); #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST if (bitflags & (0x1 << 1)) { cache_unit_buffer = google_suggest_.setCacheForLoad(cache_unit_buffer); } #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST } } } } delete[] buffer_top; } void LocalSkkServer::load_cache_file(const char *filename) { char header[64]; int fd = open(filename, O_RDONLY); if (fd < 0) { syslog_.printf(1, SkkSyslog::LEVEL_WARNING, "load cache failed (file open error)"); return; } int read_size = static_cast(read(fd, header, sizeof(header))); if (read_size != static_cast(sizeof(header))) { syslog_.printf(1, SkkSyslog::LEVEL_WARNING, "load cache failed (header read error)"); } else { const char header_keyword[16] = "yaskkserv cache"; if (memcmp(header_keyword, &header[0], sizeof(header_keyword)) != 0) { syslog_.printf(1, SkkSyslog::LEVEL_WARNING, "load cache failed (file format error)"); } else { const int file_size_minimum = sizeof(header) + 256; const int file_size_maximum = 8 * 1024 * 1024; int version; int file_size; int bitflags; SkkUtility::copyMemory(&header[16], &version, 4); SkkUtility::copyMemory(&header[20], &file_size, 4); SkkUtility::copyMemory(&header[24], &bitflags, 4); if ((version != 1) || (file_size < file_size_minimum) || (file_size > file_size_maximum) || (bitflags == 0)) { syslog_.printf(1, SkkSyslog::LEVEL_WARNING, "load cache failed (file header error)"); } else { load_cache_file_read_all(header, fd, file_size, bitflags); print_syslog_cache_information(); } } } close(fd); } #endif // defined(YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT) && (defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL)) // main_loop_recv() ˼Ԥ error break ٤ʤе֤ޤ bool LocalSkkServer::local_main_loop_loop(fd_set &fd_set_read) { for (int i = 0; i != max_connection_; ++i) { if (main_loop_is_recv(i, fd_set_read)) { int recv_result; bool error_break_flag; if (main_loop_recv(i, recv_result, error_break_flag)) { if (error_break_flag) { // goto ERROR_BREAK; return false; } } else { bool buffer_reset_flag; if ((work_ + i)->read_process_index == 0) { server_completion_test_protocol_ = *(work_ + i)->read_buffer; switch (*(work_ + i)->read_buffer) { default: buffer_reset_flag = true; main_loop_illegal_command(i); break; case '0': buffer_reset_flag = true; main_loop_0(i); break; case '1': buffer_reset_flag = local_main_loop_1(i, recv_result); break; case '2': buffer_reset_flag = true; main_loop_2(i, version_string, sizeof(version_string)); break; case '3': buffer_reset_flag = true; main_loop_3(i); break; case '4': buffer_reset_flag = local_main_loop_4(i, recv_result); break; case 'c': if (server_completion_test_ == 4) { buffer_reset_flag = local_main_loop_4(i, recv_result); } else { buffer_reset_flag = true; main_loop_illegal_command(i); } break; } } else { buffer_reset_flag = local_main_loop_1(i, recv_result); } main_loop_check_buffer_reset(i, recv_result, buffer_reset_flag); } } } return true; } void LocalSkkServer::local_main_loop_sighup() { char buffer[1024]; SkkSimpleString string(buffer); #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT #if defined(YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT) && (defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL)) if (google_cache_file_) { syslog_.printf(1, SkkSyslog::LEVEL_INFO, "save cache file \"%s\"", google_cache_file_); save_cache_file(google_cache_file_); } #endif // defined(YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT) && (defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL)) const char google_japanese_input[] = "cache status google japanese Input : "; string.append(google_japanese_input, sizeof(google_japanese_input) - 1); google_japanese_input_.appendCacheInformation(string); #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST const char google_suggest[] = " google suggest : "; string.append(google_suggest, sizeof(google_suggest) - 1); google_suggest_.appendCacheInformation(string); #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST syslog_.printf(1, SkkSyslog::LEVEL_INFO, string.getBuffer()); #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT global_sighup_flag = 0; } #ifdef YASKKSERV_CONFIG_HAVE_PTHREAD void *signal_thread(void *args) { (void)args; sigset_t sigset; sigfillset(&sigset); sigdelset(&sigset, SIGTERM); sigdelset(&sigset, SIGINT); pthread_sigmask(SIG_SETMASK, &sigset, 0); for (;;) { siginfo_t siginfo; int result = sigwaitinfo(&sigset, &siginfo); // DEBUG_PRINTF("thread result=%d errno=%d siginfo.si_signo=%d\n", result, errno, siginfo.si_signo); if (result < 0) { if (errno != EINTR) { break; } } else { switch (siginfo.si_signo) { default: break; case SIGHUP: global_sighup_flag = 2; break; } } } return 0; } #endif // YASKKSERV_CONFIG_HAVE_PTHREAD #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" void setup_signal() { signal(SIGHUP, SIG_IGN); } #pragma GCC diagnostic pop bool LocalSkkServer::local_main_loop() { #ifdef YASKKSERV_CONFIG_HAVE_PTHREAD sigset_t sigset; sigfillset(&sigset); sigdelset(&sigset, SIGTERM); sigdelset(&sigset, SIGINT); pthread_sigmask(SIG_SETMASK, &sigset, 0); pthread_t pthread; pthread_create(&pthread, 0, signal_thread, 0); #endif // YASKKSERV_CONFIG_HAVE_PTHREAD #if defined(YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT) && (defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL)) if (google_cache_file_) { syslog_.printf(1, SkkSyslog::LEVEL_INFO, "load cache file \"%s\"", google_cache_file_); load_cache_file(google_cache_file_); } #endif // defined(YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT) && (defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL)) bool result = true; for (;;) { fd_set fd_set_read; int select_result = main_loop_select_polling(fd_set_read); DEBUG_PRINTF("select_result=%d\n", select_result); if (global_sighup_flag) { local_main_loop_sighup(); } if (select_result == 0) { } else { main_loop_check_reload_dictionary(skk_dictionary_, skk_dictionary_length_, dictionary_filename_table_, dictionary_check_update_flag_); if (select_result == -1) { if (errno == EINTR) { continue; } } if (!main_loop_accept(fd_set_read, select_result)) { goto ERROR_BREAK; } if (!local_main_loop_loop(fd_set_read)) { goto ERROR_BREAK; } } } ERROR_BREAK: result = false; #ifdef YASKKSERV_CONFIG_HAVE_PTHREAD pthread_join(pthread, 0); #endif // YASKKSERV_CONFIG_HAVE_PTHREAD return result; } int print_usage() { SkkUtility::printf("Usage: yaskkserv [OPTION] dictionary [dictionary...]\n" " -a, --address listen address (default 0.0.0.0)\n" " -c, --check-update check update dictionary (default disable)\n" " -d, --debug enable debug mode (default disable)\n" " -h, --help print this help and exit\n" " -l, --log-level=LEVEL loglevel (range [0 - 9] default 1)\n" " -m, --max-connection=N max connection (default 8)\n" " -p, --port=PORT set port (default 1178)\n" " -f, --no-daemonize not daemonize\n" " --server-completion-midasi-length=LENGTH\n" " set midasi length (range [256 - 32768] default 2048)\n" " --server-completion-midasi-string-size=SIZE\n" " set midasi string size (range [16384 - 1048576] default 262144)\n" " --server-completion-test=type\n" " 1:default 2:ignore slash 3:space 4:space and protocol 'c'\n" #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT #if defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) " --google-cache=N use google cache(default 0(disable))\n" #endif // defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) " --use-http force use http(default https or http)\n" " --use-ipv6 use ipv6(default ipv4)\n" " --google-japanese-input=TYPE\n" " enable google japanese input\n" " disable : disable\n" " notfound : use japanese input or suggest if not found in dictionary\n" #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST " notfound-suggest-input : Suggest -> JapaneseInput\n" " notfound-input-suggest : JapaneseInput -> Suggest\n" #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST " dictionary : JapaneseInput = https://www.google.com\n" #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST " Suggest = https://suggest.google.com\n" #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST " ex.)\n" " https\n" #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST " # yaskkserv --google-japanese-input=dictionary --google-suggest DIC https://suggest.google.com https://www.google.com\n" " # yaskkserv --google-japanese-input=notfound-suggest-input --google-suggest DIC\n" " # yaskkserv --google-japanese-input=notfound --google-suggest DIC\n" #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST " # yaskkserv --google-japanese-input=dictionary DIC https://www.google.com\n" " # yaskkserv --google-japanese-input=notfound DIC\n" " # yaskkserv --google-japanese-input=notfound DIC\n" " http\n" #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST " # yaskkserv --google-japanese-input=dictionary --google-suggest DIC http://suggest.google.com http://www.google.com\n" " # yaskkserv --google-japanese-input=dictionary --google-suggest --use-http DIC http://suggest.google.com http://www.google.com\n" #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST " # yaskkserv --google-japanese-input=dictionary DIC http://www.google.com\n" " # yaskkserv --google-japanese-input=dictionary --use-http DIC http://www.google.com\n" " # yaskkserv --google-japanese-input=notfound --use-http DIC\n" " --google-japanese-input-timeout=SECOND\n" " set enable google japanese input timeout (default 2.5)\n" #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST " --google-suggest\n" " enable google suggest\n" #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST #if defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) " --google-cache-file=filename\n" " save/load cache filename\n" #endif // defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT " -v, --version print version\n"); return EXIT_FAILURE; } int print_version() { SkkUtility::printf("yaskkserv_" SERVER_IDENTIFIER " version " YASKKSERV_VERSION "\n"); SkkUtility::printf("Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012, 2013, 2014 Tadashi Watanabe\n"); SkkUtility::printf("http://umiushi.org/~wac/yaskkserv/\n"); return EXIT_FAILURE; } enum { OPTION_TABLE_ADDRESS, OPTION_TABLE_CHECK_UPDATE, OPTION_TABLE_DEBUG, OPTION_TABLE_HELP, OPTION_TABLE_LOG_LEVEL, OPTION_TABLE_MAX_CONNECTION, OPTION_TABLE_PORT, OPTION_TABLE_NO_DAEMONIZE, OPTION_TABLE_SERVER_COMPLETION_MIDASI_LENGTH, OPTION_TABLE_SERVER_COMPLETION_MIDASI_STRING_SIZE, OPTION_TABLE_SERVER_COMPLETION_TEST, #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT #if defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) OPTION_TABLE_GOOGLE_CACHE, #endif // defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) OPTION_TABLE_USE_HTTP, OPTION_TABLE_USE_IPV6, OPTION_TABLE_GOOGLE_JAPANESE_INPUT, OPTION_TABLE_GOOGLE_JAPANESE_INPUT_TIMEOUT, #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST OPTION_TABLE_GOOGLE_SUGGEST, #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST #if defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) OPTION_TABLE_GOOGLE_CACHE_FILE, #endif // defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT OPTION_TABLE_VERSION, OPTION_TABLE_LENGTH }; const SkkCommandLine::Option option_table[] = { { "a", "address", SkkCommandLine::OPTION_ARGUMENT_STRING, }, { "c", "check-update", SkkCommandLine::OPTION_ARGUMENT_NONE, }, { "d", "debug", SkkCommandLine::OPTION_ARGUMENT_NONE, }, { "h", "help", SkkCommandLine::OPTION_ARGUMENT_NONE, }, { "l", "log-level", SkkCommandLine::OPTION_ARGUMENT_INTEGER, }, { "m", "max-connection", SkkCommandLine::OPTION_ARGUMENT_INTEGER, }, { "p", "port", SkkCommandLine::OPTION_ARGUMENT_INTEGER, }, { "f", "no-daemonize", SkkCommandLine::OPTION_ARGUMENT_NONE, }, { 0, "server-completion-midasi-length", SkkCommandLine::OPTION_ARGUMENT_INTEGER, }, { 0, "server-completion-midasi-string-size", SkkCommandLine::OPTION_ARGUMENT_INTEGER, }, { 0, "server-completion-test", SkkCommandLine::OPTION_ARGUMENT_INTEGER, }, #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT #if defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) { 0, "google-cache", SkkCommandLine::OPTION_ARGUMENT_INTEGER, }, #endif // defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) { 0, "use-http", SkkCommandLine::OPTION_ARGUMENT_NONE, }, { 0, "use-ipv6", SkkCommandLine::OPTION_ARGUMENT_NONE, }, { 0, "google-japanese-input", SkkCommandLine::OPTION_ARGUMENT_STRING, }, { 0, "google-japanese-input-timeout", SkkCommandLine::OPTION_ARGUMENT_FLOAT, }, #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST { 0, "google-suggest", SkkCommandLine::OPTION_ARGUMENT_NONE, }, #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST #if defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) { 0, "google-cache-file", SkkCommandLine::OPTION_ARGUMENT_STRING, }, #endif // defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT { "v", "version", SkkCommandLine::OPTION_ARGUMENT_NONE, }, { 0, 0, SkkCommandLine::OPTION_ARGUMENT_TERMINATOR, }, }; struct Option { const char *address; int log_level; int max_connection; int port; int server_completion_midasi_length; int server_completion_midasi_string_size; int server_completion_test; int google_cache; bool use_http_flag; bool use_ipv6_flag; #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT LocalSkkServer::GoogleJapaneseInputType google_japanese_input_type; float google_japanese_input_timeout; #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST bool google_suggest_flag; #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST const char *google_cache_file; #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT bool no_daemonize_flag; bool check_update_flag; bool debug_flag; } option = { "0.0.0.0", 1, 8, 1178, 2048, 262144, 1, false, false, #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT 0, LocalSkkServer::GOOGLE_JAPANESE_INPUT_TYPE_DISABLE, 2.5f, #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST false, #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST 0, #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT false, false, false, }; // ͤʤиƤӽФ¦ return ٤ǤΤȤ result ֤ͤޤͤξ result ˤϿޤ bool local_main_core_command_line(SkkCommandLine &command_line, int &result, int argc, char *argv[]) { if (command_line.parse(argc, argv, option_table)) { if (command_line.isOptionDefined(OPTION_TABLE_HELP)) { result = print_usage(); return true; } if (command_line.isOptionDefined(OPTION_TABLE_VERSION)) { result = print_version(); return true; } // ̵꤬ȡǰΤQ (64) ¿ϤƤ if ((command_line.getArgumentLength() < 1) || (command_line.getArgumentLength() > 64)) { result = print_usage(); return true; } if (command_line.isOptionDefined(OPTION_TABLE_CHECK_UPDATE)) { option.check_update_flag = true; } if (command_line.isOptionDefined(OPTION_TABLE_DEBUG)) { option.debug_flag = true; } if (command_line.isOptionDefined(OPTION_TABLE_ADDRESS)) { option.address = command_line.getOptionArgumentString(OPTION_TABLE_ADDRESS); } if (command_line.isOptionDefined(OPTION_TABLE_LOG_LEVEL)) { option.log_level = command_line.getOptionArgumentInteger(OPTION_TABLE_LOG_LEVEL); if ((option.log_level < 0) || (option.log_level > 9)) { SkkUtility::printf("Illegal log-level %d (0 - 9)\n\n", option.log_level); result = print_usage(); return true; } } if (command_line.isOptionDefined(OPTION_TABLE_MAX_CONNECTION)) { option.max_connection = command_line.getOptionArgumentInteger(OPTION_TABLE_MAX_CONNECTION); if ((option.max_connection < 1) || (option.max_connection > 1024)) { SkkUtility::printf("Illegal max-connection %d (1 - 1024)\n\n", option.max_connection); result = print_usage(); return true; } } if (command_line.isOptionDefined(OPTION_TABLE_PORT)) { option.port = command_line.getOptionArgumentInteger(OPTION_TABLE_PORT); if ((option.port < 1) || (option.port > 65535)) { SkkUtility::printf("Illegal port number %d (1 - 65535)\n\n", option.port); result = print_usage(); return true; } } if (command_line.isOptionDefined(OPTION_TABLE_NO_DAEMONIZE)) { option.no_daemonize_flag = true; } if (command_line.isOptionDefined(OPTION_TABLE_SERVER_COMPLETION_MIDASI_LENGTH)) { option.server_completion_midasi_length = command_line.getOptionArgumentInteger(OPTION_TABLE_SERVER_COMPLETION_MIDASI_LENGTH); if ((option.server_completion_midasi_length < 256) || (option.server_completion_midasi_length > 32768)) { SkkUtility::printf("Illegal midasi length %d (256 - 32768)\n\n", option.server_completion_midasi_length); result = print_usage(); return true; } } if (command_line.isOptionDefined(OPTION_TABLE_SERVER_COMPLETION_MIDASI_STRING_SIZE)) { option.server_completion_midasi_string_size = command_line.getOptionArgumentInteger(OPTION_TABLE_SERVER_COMPLETION_MIDASI_STRING_SIZE); if ((option.server_completion_midasi_string_size < 16 * 1024) || (option.server_completion_midasi_string_size > 1024 * 1024)) { SkkUtility::printf("Illegal string size %d (16384 - 1048576)\n\n", option.server_completion_midasi_string_size); result = print_usage(); return true; } } if (command_line.isOptionDefined(OPTION_TABLE_SERVER_COMPLETION_TEST)) { option.server_completion_test = command_line.getOptionArgumentInteger(OPTION_TABLE_SERVER_COMPLETION_TEST); if ((option.server_completion_test < 1) || (option.server_completion_test > 4)) { SkkUtility::printf("Illegal argument %d (1 - 4)\n\n", option.server_completion_test); result = print_usage(); return true; } } #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT #if defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) if (command_line.isOptionDefined(OPTION_TABLE_GOOGLE_CACHE)) { option.google_cache = command_line.getOptionArgumentInteger(OPTION_TABLE_GOOGLE_CACHE); if (option.google_cache > 32768) { SkkUtility::printf("Illegal google cache entry size %d (0 - 32768)\n\n", option.google_cache); result = print_usage(); return true; } } #endif // defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST if (command_line.isOptionDefined(OPTION_TABLE_GOOGLE_SUGGEST)) { option.google_suggest_flag = true; } #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST if (command_line.isOptionDefined(OPTION_TABLE_USE_HTTP)) { option.use_http_flag = true; } if (command_line.isOptionDefined(OPTION_TABLE_USE_IPV6)) { option.use_ipv6_flag = true; } if (command_line.isOptionDefined(OPTION_TABLE_GOOGLE_JAPANESE_INPUT)) { const char *p = command_line.getOptionArgumentString(OPTION_TABLE_GOOGLE_JAPANESE_INPUT); if (SkkSimpleString::compare("disable", p) == 0) { option.google_japanese_input_type = LocalSkkServer::GOOGLE_JAPANESE_INPUT_TYPE_DISABLE; } else if (SkkSimpleString::compare("notfound", p) == 0) { option.google_japanese_input_type = LocalSkkServer::GOOGLE_JAPANESE_INPUT_TYPE_NOTFOUND; } #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST else if (SkkSimpleString::compare("notfound-suggest-input", p) == 0) { if (!option.google_suggest_flag) { SkkUtility::printf("need --google-suggest\n\n"); result = print_usage(); return true; } option.google_japanese_input_type = LocalSkkServer::GOOGLE_JAPANESE_INPUT_TYPE_NOTFOUND_SUGGEST_INPUT; } else if (SkkSimpleString::compare("notfound-input-suggest", p) == 0) { if (!option.google_suggest_flag) { SkkUtility::printf("need --google-suggest\n\n"); result = print_usage(); return true; } option.google_japanese_input_type = LocalSkkServer::GOOGLE_JAPANESE_INPUT_TYPE_NOTFOUND_INPUT_SUGGEST; } #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST else if (SkkSimpleString::compare("dictionary", p) == 0) { option.google_japanese_input_type = LocalSkkServer::GOOGLE_JAPANESE_INPUT_TYPE_DICTIONARY; } else { SkkUtility::printf("Illegal argument %s (disable, notfound or dictionary)\n\n", p); result = print_usage(); return true; } } if (command_line.isOptionDefined(OPTION_TABLE_GOOGLE_JAPANESE_INPUT_TIMEOUT)) { option.google_japanese_input_timeout = command_line.getOptionArgumentFloat(OPTION_TABLE_GOOGLE_JAPANESE_INPUT_TIMEOUT); if ((option.google_japanese_input_timeout <= 0.0f) || (option.google_japanese_input_timeout > 60.0f)) { SkkUtility::printf("Illegal second %f (0.0 - 60.0)\n\n", option.google_japanese_input_timeout); result = print_usage(); return true; } } #if defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) if (command_line.isOptionDefined(OPTION_TABLE_GOOGLE_CACHE_FILE)) { option.google_cache_file = command_line.getOptionArgumentString(OPTION_TABLE_GOOGLE_CACHE_FILE); } #endif // defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT } else { SkkUtility::printf("error \"%s\"\n\n", command_line.getErrorString()); result = print_usage(); return true; } return false; } // ƤӽФ֤٤ EXIT_SUCCESS ޤ EXIT_FAILURE ֤ޤ int local_main_core_setup_dictionary(const SkkCommandLine &command_line, LocalSkkDictionary *skk_dictionary) { int result = EXIT_SUCCESS; int skk_dictionary_length = command_line.getArgumentLength(); #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT int google_japanese_input_count = 0; #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST int google_suggest_count = 0; #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT for (int i = 0; i != skk_dictionary_length; ++i) { #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT if (SkkSimpleString::compare("http://www.google.com", command_line.getArgumentPointer(i)) == 0) { if (option.google_japanese_input_type != LocalSkkServer::GOOGLE_JAPANESE_INPUT_TYPE_DICTIONARY) { SkkUtility::printf("google dictionary need --google-japanese-input=dictionary\n"); result = EXIT_FAILURE; break; } ++google_japanese_input_count; if (google_japanese_input_count >= 2) { SkkUtility::printf("google japanese input dictionary must less than 2\n", command_line.getArgumentPointer(i), i); result = EXIT_FAILURE; break; } (skk_dictionary + i)->setGoogleJapaneseInputFlag(true, false); } #if defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) else if (SkkSimpleString::compare("https://www.google.com", command_line.getArgumentPointer(i)) == 0) { if (option.google_japanese_input_type != LocalSkkServer::GOOGLE_JAPANESE_INPUT_TYPE_DICTIONARY) { SkkUtility::printf("google dictionary need --google-japanese-input=dictionary\n"); result = EXIT_FAILURE; break; } ++google_japanese_input_count; if (google_japanese_input_count >= 2) { SkkUtility::printf("google japanese input dictionary must less than 2\n", command_line.getArgumentPointer(i), i); result = EXIT_FAILURE; break; } (skk_dictionary + i)->setGoogleJapaneseInputFlag(true, true); } #endif // defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST else if (SkkSimpleString::compare("http://suggest.google.com", command_line.getArgumentPointer(i)) == 0) { if (option.google_japanese_input_type != LocalSkkServer::GOOGLE_JAPANESE_INPUT_TYPE_DICTIONARY) { SkkUtility::printf("google dictionary need --google-japanese-input=dictionary\n"); result = EXIT_FAILURE; break; } if (!option.google_suggest_flag) { SkkUtility::printf("need --google-suggest\n"); result = EXIT_FAILURE; break; } ++google_suggest_count; if (google_suggest_count >= 2) { SkkUtility::printf("google suggest dictionary must less than 2\n", command_line.getArgumentPointer(i), i); result = EXIT_FAILURE; break; } (skk_dictionary + i)->setGoogleSuggestFlag(true, false); } #if defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) else if (SkkSimpleString::compare("https://suggest.google.com", command_line.getArgumentPointer(i)) == 0) { if (option.google_japanese_input_type != LocalSkkServer::GOOGLE_JAPANESE_INPUT_TYPE_DICTIONARY) { SkkUtility::printf("google dictionary need --google-japanese-input=dictionary\n"); result = EXIT_FAILURE; break; } if (!option.google_suggest_flag) { SkkUtility::printf("need --google-suggest\n"); result = EXIT_FAILURE; break; } ++google_suggest_count; if (google_suggest_count >= 2) { SkkUtility::printf("google suggest dictionary must less than 2\n", command_line.getArgumentPointer(i), i); result = EXIT_FAILURE; break; } (skk_dictionary + i)->setGoogleSuggestFlag(true, true); } #endif // defined(YASKKSERV_CONFIG_HEADER_HAVE_GNUTLS_OPENSSL) || defined(YASKKSERV_CONFIG_HEADER_HAVE_OPENSSL) #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST else #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT { SkkUtility::DictionaryPermission dictionary_permission(command_line.getArgumentPointer(i)); if (!dictionary_permission.isExist()) { SkkUtility::printf("dictionary file \"%s\" (index = %d) not found\n", command_line.getArgumentPointer(i), i); result = EXIT_FAILURE; break; } if (!dictionary_permission.checkAndPrintPermission()) { result = EXIT_FAILURE; break; } if (!(skk_dictionary + i)->open(command_line.getArgumentPointer(i))) { SkkUtility::printf("dictionary file \"%s\" (index = %d) open failed\n", command_line.getArgumentPointer(i), i); result = EXIT_FAILURE; break; } } } return result; } int local_main_core(int argc, char *argv[]) { int result = EXIT_SUCCESS; SkkCommandLine command_line; if (local_main_core_command_line(command_line, result, argc, argv)) { return result; } int skk_dictionary_length = command_line.getArgumentLength(); LocalSkkDictionary *skk_dictionary = new LocalSkkDictionary[skk_dictionary_length]; result = local_main_core_setup_dictionary(command_line, skk_dictionary); if (result == EXIT_SUCCESS) { LocalSkkServer *skk_server = new LocalSkkServer(option.port, option.log_level, option.address); const int listen_queue = 5; skk_server->initialize(skk_dictionary, &argv[command_line.getArgumentArgvIndex()], skk_dictionary_length, option.max_connection, listen_queue, option.server_completion_midasi_length, option.server_completion_midasi_string_size, option.server_completion_test, option.google_cache, #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT option.google_cache_file, #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT option.check_update_flag, option.no_daemonize_flag, option.use_http_flag, option.use_ipv6_flag); #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT skk_server->setGoogleJapaneseInputParameter(option.google_japanese_input_type, option.google_japanese_input_timeout); #ifdef YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST skk_server->setGoogleSuggestParameter(option.google_suggest_flag); #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_SUGGEST #endif // YASKKSERV_CONFIG_ENABLE_GOOGLE_JAPANESE_INPUT if (!skk_server->mainLoop()) { result = EXIT_FAILURE; } delete skk_server; } delete[] skk_dictionary; return result; } #ifdef YASKKSERV_HAIRY_TEST int local_main_test(int argc, char *argv[]) { const int allocate_size = 16; SkkSimpleString string_a(allocate_size); printf("* try append char\n"); for (int i = 0; i != 8; ++i) { printf("i = %d\n", i); string_a.append('a'); printf(" A %s size=%d\n", string_a.getBuffer(), string_a.getSize()); } printf("* try appendFast char\n"); string_a.reset(); for (int i = 0; i != 8; ++i) { printf("i = %d\n", i); printf(" A %s\n", string_a.isAppendSize(1) ? "ok" : "ng"); if (string_a.isAppendSize(1)) { string_a.appendFast('a'); printf(" A %s size=%d\n", string_a.getBuffer(), string_a.getSize()); } } printf("* try append char pointer 1\n"); string_a.reset(); for (int i = 0; i != 8; ++i) { printf("i = %d\n", i); string_a.append("a", 1); printf(" A %s size=%d\n", string_a.getBuffer(), string_a.getSize()); } printf("* try append char pointer 2\n"); string_a.reset(); for (int i = 0; i != 8; ++i) { printf("i = %d\n", i); string_a.append("ab", 2); printf(" A %s size=%d\n", string_a.getBuffer(), string_a.getSize()); } printf("* try appendFast char pointer 1\n"); string_a.reset(); for (int i = 0; i != 8; ++i) { printf("i = %d\n", i); printf(" A %s\n", string_a.isAppendSize(1) ? "ok" : "ng"); if (string_a.isAppendSize(1)) { string_a.appendFast("A"); printf(" A %s size=%d\n", string_a.getBuffer(), string_a.getSize()); } } printf("* try appendFast char pointer 2\n"); string_a.reset(); for (int i = 0; i != 8; ++i) { printf("i = %d\n", i); printf(" A %s\n", string_a.isAppendSize(2) ? "ok" : "ng"); if (string_a.isAppendSize(2)) { string_a.appendFast("AB"); printf(" A %s size=%d\n", string_a.getBuffer(), string_a.getSize()); } } printf("* try terminate\n"); string_a.terminate(2); printf(" A %s size=%d\n", string_a.getBuffer(), string_a.getSize()); printf("* try reset\n"); string_a.reset(); printf(" A %s size=%d\n", string_a.getBuffer(), string_a.getSize()); printf("* try fillStringBuffer\n"); string_a.fillStringBuffer('x'); printf(" A %s size=%d\n", string_a.getBuffer(), string_a.getSize()); printf("* try setAppendIndex\n"); string_a.setAppendIndex(2); printf(" A %s size=%d\n", string_a.getBuffer(), string_a.getSize()); printf("* try terminator append\n"); string_a.append('\0'); printf(" A %s size=%d\n", string_a.getBuffer(), string_a.getSize()); printf("* try fillStringBuffer\n"); string_a.fillStringBuffer('X'); printf(" A %s size=%d\n", string_a.getBuffer(), string_a.getSize()); printf("* try setAppendIndex\n"); string_a.setAppendIndex(2); printf(" A %s size=%d\n", string_a.getBuffer(), string_a.getSize()); printf("* try terminator appendFast\n"); string_a.append('\0'); printf(" A %s size=%d\n", string_a.getBuffer(), string_a.getSize()); printf("* try fillStringBuffer\n"); string_a.fillStringBuffer('Y'); printf(" A %s size=%d\n", string_a.getBuffer(), string_a.getSize()); printf("* try setAppendIndex\n"); string_a.setAppendIndex(2); printf(" A %s size=%d\n", string_a.getBuffer(), string_a.getSize()); printf("* try string terminator append\n"); string_a.append("\0", 1); printf(" A %s size=%d\n", string_a.getBuffer(), string_a.getSize()); printf("* try fillStringBuffer\n"); string_a.fillStringBuffer('y'); printf(" A %s size=%d\n", string_a.getBuffer(), string_a.getSize()); printf("* try setAppendIndex\n"); string_a.setAppendIndex(2); printf(" A %s size=%d\n", string_a.getBuffer(), string_a.getSize()); printf("* try string terminator appendFast\n"); string_a.appendFast("\0"); printf(" A %s size=%d\n", string_a.getBuffer(), string_a.getSize()); } int local_main_test_3(int argc, char *argv[]) { const int allocate_size = 16; SimpleStringForHairy string_a(allocate_size); printf("allocate_size=%5d getValidBufferSize()=%5d\n", allocate_size, string_a.getValidBufferSize()); string_a.appendFast("0123456"); // for (int i = 0; i != 7; ++i) // { // string_a.appendFast('a' + i); // } printf("%s size=%d\n", string_a.getBuffer(), string_a.getSize()); return 0; } int local_main_test_2(int argc, char *argv[]) { const int allocate_size = 16; SimpleStringForHairy string_a(allocate_size); SimpleStringForHairy string_b(allocate_size); SimpleStringForHairy string_c(allocate_size); printf("allocate_size=%5d getValidBufferSize()=%5d\n", allocate_size, string_a.getValidBufferSize()); int length = 2; for (int i = 0; i != allocate_size; ++i) { printf("i=%3d\n", i); printf(" A getSize()=%5d getRemainSize()=%5d \"%s\"\n", string_a.getSize(), string_a.getRemainSize(), string_a.getBuffer()); printf(" isAppendSize(%d) %s\n", length, string_a.isAppendSize(length) ? "ok" : "NG"); for (int h = 1; h <= length; ++h) { printf(" append(char) %s\n", string_a.append('a') ? "ok" : "NG"); } printf(" B getSize()=%5d getRemainSize()=%5d \"%s\"\n", string_b.getSize(), string_b.getRemainSize(), string_b.getBuffer()); printf(" isAppendSize(%d) %s\n", length, string_b.isAppendSize(length) ? "ok" : "NG"); for (int h = 1; h <= length; ++h) { printf(" try appendFast(char)\n"); string_b.appendFast('a'); } printf(" C getSize()=%5d getRemainSize()=%5d \"%s\"\n", string_c.getSize(), string_c.getRemainSize(), string_c.getBuffer()); printf(" isAppendSize(%d) %s\n", length, string_c.isAppendSize(length) ? "ok" : "NG"); printf(" append(void *p, int size) %s\n", string_c.append("aaaa", length) ? "ok" : "NG"); } return 0; } #endif // YASKKSERV_HAIRY_TEST } int local_main(int argc, char *argv[]) { #ifdef YASKKSERV_HAIRY_TEST return local_main_test(argc, argv); #else // YASKKSERV_HAIRY_TEST return local_main_core(argc, argv); #endif // YASKKSERV_HAIRY_TEST } } yaskkserv-1.1.0/source/yaskkserv_make_dictionary/000077500000000000000000000000001262716711600223105ustar00rootroot00000000000000yaskkserv-1.1.0/source/yaskkserv_make_dictionary/Makefile.bsd_cygwin_linux_gcc000066400000000000000000000024631262716711600301370ustar00rootroot00000000000000# -*- Makefile -*- include ../Makefile.$(ARCHITECTURE_LOWER_CASE).common TARGET_BASE = yaskkserv_make_dictionary RUN_FLAGS = CXXFLAGS += $(CXXFLAGS_OPTIMIZE_TOOL) $(CXXFLAGS_WARNING_TOOL) SOURCES = ${wildcard *.cpp} OBJECTS = ${addprefix $(VAR_PATH)/$(TARGET_BASE)/,$(SOURCES:.cpp=.o)} OBJECTS_SKK = ${wildcard $(VAR_PATH)/skk/*.o} ${wildcard $(VAR_PATH)/skk/architecture/$(ARCHITECTURE_LOWER_CASE)/*.o} DEPEND_FILE = $(VAR_PATH)/depend.$(TARGET_BASE) TARGET = $(VAR_PATH)/$(TARGET_BASE)/$(TARGET_BASE) .SUFFIXES : .PHONY : all clean run makerun break makebreak kill makekill debugger vlist vhist vreport test depend cleandepend all : $(TARGET) $(TARGET) : $(OBJECTS_SKK) $(OBJECTS) $(LD) $(LDFLAGS) -o $@ $^ ifndef DEBUG $(STRIP) $@$(EXECUTE_FILE_SUFFIX) endif run : cd $(PROJECT_ROOT); export SEGFAULT_SIGNALS=all && export LD_PRELOAD=/lib/libSegFault.so && time $(TARGET) $(RUN_FLAGS) makerun : all run $(DEPEND_FILE) : $(MAKEDEPEND) $(VAR_PATH)/$(TARGET_BASE) $(DEPEND_FILE) '$(CXX) $(CXXFLAGS)' '$(CPP) -E -MM $(CPPFLAGS) $(SOURCES)' depend : $(MAKEDEPEND) $(VAR_PATH)/$(TARGET_BASE) $(DEPEND_FILE) '$(CXX) $(CXXFLAGS)' '$(CPP) -E -MM $(CPPFLAGS) $(SOURCES)' cleandepend : -$(RM) $(DEPEND_FILE) include $(DEPEND_FILE) clean : -$(RM) $(TARGET) $(TARGET).map -$(RM) $(OBJECTS) yaskkserv-1.1.0/source/yaskkserv_make_dictionary/yaskkserv_make_dictionary.cpp000066400000000000000000000223401262716711600302610ustar00rootroot00000000000000/* Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012, 2013, 2014 Tadashi Watanabe This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "skk_architecture.hpp" #include "skk_mmap.hpp" #include "skk_jisyo.hpp" #include "skk_dictionary.hpp" #include "skk_server.hpp" #include "skk_utility.hpp" #include "skk_command_line.hpp" namespace YaSkkServ { namespace { void print_debug_information(const char *destination) { SkkUtility::printf("DICTIONARY INFORMATION\n"); SkkJisyo::Information information; if (!SkkJisyo::getInformation(destination, information)) { DEBUG_PRINTF("getInformation() failed \n"); } else { for (int i = 0; i != SkkJisyo::Information::ID_LENGTH; ++i) { const char * const table[] = { "ID_BIT_FLAG", "ID_RESERVE_1", "ID_RESERVE_2", "ID_RESERVE_3", "ID_RESERVE_4", "ID_RESERVE_5", "ID_INDEX_DATA_OFFSET", "ID_INDEX_DATA_SIZE", "ID_SPECIAL_LINES", "ID_SPECIAL_SIZE", "ID_NORMAL_LINES", "ID_NORMAL_SIZE", "ID_BLOCK_ALIGNMENT_SIZE", "ID_VERSION", "ID_SIZE", "ID_IDENTIFIER", }; SkkUtility::printf("id = %s v = %d\n", table[i], information.get(static_cast(i))); } } SkkUtility::printf("INDEX DATA HEADER\n"); SkkJisyo::IndexDataHeader index_data_header; if (!SkkJisyo::getIndexDataHeader(destination, index_data_header)) { DEBUG_PRINTF("getIndexDataHeader() failed \n"); } else { for (int i = 0; i != SkkJisyo::IndexDataHeader::ID_LENGTH; ++i) { const char * const table[] = { "ID_BIT_FLAG", "ID_SIZE", "ID_BLOCK_SIZE", "ID_NORMAL_BLOCK_LENGTH", "ID_SPECIAL_BLOCK_LENGTH", "ID_NORMAL_STRING_SIZE", "ID_SPECIAL_STRING_SIZE", "ID_SPECIAL_ENTRY_OFFSET", }; SkkUtility::printf("id = %s v = %d\n", table[i], index_data_header.get(static_cast(i))); } } } int print_usage() { SkkUtility::printf("Usage: yaskkserv_make_dictionary [OPTION] skk-dictionary output-dictionary\n" " -a, --alignment enable alignment (default disable)\n" " -b, --block-size=SIZE set block size (default 8192)\n" " -d, --debug print debug information\n" " -h, --help print this help and exit\n" " -s, --short-block enable short block (must set --alignment) (default disable)\n" " -v, --version print version\n"); return -1; } int print_version() { SkkUtility::printf("yaskkserv_make_dictionary version " YASKKSERV_VERSION "\n"); SkkUtility::printf("Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012, 2013, 2014 Tadashi Watanabe\n"); SkkUtility::printf("http://umiushi.org/~wac/yaskkserv/\n"); return -1; } } int local_main(int argc, char *argv[]) { enum { OPTION_TABLE_ALIGNMENT, OPTION_TABLE_BLOCK_SIZE, OPTION_TABLE_DEBUG, OPTION_TABLE_HELP, OPTION_TABLE_SHORT_BLOCK, OPTION_TABLE_VERSION, OPTION_TABLE_LENGTH }; const SkkCommandLine::Option option_table[] = { { "a", "alignment", SkkCommandLine::OPTION_ARGUMENT_NONE, }, { "b", "block-size", SkkCommandLine::OPTION_ARGUMENT_INTEGER, }, { "d", "debug", SkkCommandLine::OPTION_ARGUMENT_NONE, }, { "h", "help", SkkCommandLine::OPTION_ARGUMENT_NONE, }, { "s", "short-block", SkkCommandLine::OPTION_ARGUMENT_NONE, }, { "v", "version", SkkCommandLine::OPTION_ARGUMENT_NONE, }, { 0, 0, SkkCommandLine::OPTION_ARGUMENT_TERMINATOR, }, }; struct Option { int block_size; bool alignment_flag; bool block_short_flag; bool debug_flag; } option = { 8 * 1024, false, false, false, }; const char *filename_input_skk_jisyo = 0; const char *filename_output_dictionary = 0; { SkkCommandLine command_line; if (command_line.parse(argc, argv, option_table)) { if (command_line.isOptionDefined(OPTION_TABLE_HELP)) { return print_usage(); } if (command_line.isOptionDefined(OPTION_TABLE_VERSION)) { return print_version(); } if (command_line.getArgumentLength() != 2) { return print_usage(); } filename_input_skk_jisyo = command_line.getArgumentPointer(0); filename_output_dictionary = command_line.getArgumentPointer(1); if (command_line.isOptionDefined(OPTION_TABLE_ALIGNMENT)) { option.alignment_flag = true; } if (command_line.isOptionDefined(OPTION_TABLE_BLOCK_SIZE)) { option.block_size = command_line.getOptionArgumentInteger(OPTION_TABLE_BLOCK_SIZE); } if (command_line.isOptionDefined(OPTION_TABLE_SHORT_BLOCK)) { if (!option.alignment_flag) { return print_usage(); } option.block_short_flag = true; } if (command_line.isOptionDefined(OPTION_TABLE_DEBUG)) { option.debug_flag = true; } } else { SkkUtility::printf("error \"%s\"\n\n", command_line.getErrorString()); return print_usage(); } } if (!SkkJisyo::createDictionaryForClassSkkDictionary(filename_input_skk_jisyo, filename_output_dictionary, option.block_size, option.alignment_flag, option.block_short_flag)) { SkkUtility::printf("createDictionary() failed\n"); } if (option.debug_flag) { print_debug_information(filename_output_dictionary); } return EXIT_SUCCESS; } } yaskkserv-1.1.0/source/yaskkserv_normal/000077500000000000000000000000001262716711600204365ustar00rootroot00000000000000yaskkserv-1.1.0/source/yaskkserv_normal/Makefile.bsd_cygwin_linux_gcc000066400000000000000000000026341262716711600262650ustar00rootroot00000000000000# -*- Makefile -*- include ../Makefile.$(ARCHITECTURE_LOWER_CASE).common TARGET_BASE = yaskkserv_normal RUN_FLAGS = --check-update --port=9999 /var/tmp/SKK-JISYO.total+zipcode.yaskkserv CXXFLAGS += $(CXXFLAGS_OPTIMIZE_SERVER_NORMAL) $(CXXFLAGS_WARNING_SERVER_NORMAL) SOURCES = ${wildcard *.cpp} OBJECTS = ${addprefix $(VAR_PATH)/$(TARGET_BASE)/,$(SOURCES:.cpp=.o)} OBJECTS_SKK = ${wildcard $(VAR_PATH)/skk/*.o} ${wildcard $(VAR_PATH)/skk/architecture/$(ARCHITECTURE_LOWER_CASE)/*.o} DEPEND_FILE = $(VAR_PATH)/depend.$(TARGET_BASE) TARGET = $(VAR_PATH)/$(TARGET_BASE)/$(TARGET_BASE) .SUFFIXES : .PHONY : all clean run makerun break makebreak kill makekill debugger vlist vhist vreport test depend cleandepend all : $(TARGET) $(TARGET) : $(OBJECTS_SKK) $(OBJECTS) $(LD) $(LDFLAGS) -o $@ $^ $(LDFLAGS_LIBRARY_NORMAL) ifndef DEBUG $(STRIP) $@$(EXECUTE_FILE_SUFFIX) endif run : cd $(PROJECT_ROOT); export SEGFAULT_SIGNALS=all && export LD_PRELOAD=/lib/libSegFault.so && time $(TARGET) $(RUN_FLAGS) makerun : all run $(DEPEND_FILE) : $(MAKEDEPEND) $(VAR_PATH)/$(TARGET_BASE) $(DEPEND_FILE) '$(CXX) $(CXXFLAGS)' '$(CPP) -E -MM $(CPPFLAGS) $(SOURCES)' depend : $(MAKEDEPEND) $(VAR_PATH)/$(TARGET_BASE) $(DEPEND_FILE) '$(CXX) $(CXXFLAGS)' '$(CPP) -E -MM $(CPPFLAGS) $(SOURCES)' cleandepend : -$(RM) $(DEPEND_FILE) include $(DEPEND_FILE) clean : -$(RM) $(TARGET) $(TARGET).map -$(RM) $(OBJECTS) yaskkserv-1.1.0/source/yaskkserv_normal/yaskkserv_normal.cpp000066400000000000000000000606421262716711600245440ustar00rootroot00000000000000/* Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012, 2013, 2014 Tadashi Watanabe This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "skk_dictionary.hpp" #include "skk_server.hpp" #include "skk_utility.hpp" #include "skk_command_line.hpp" #include "skk_simple_string.hpp" namespace YaSkkServ { namespace { #define SERVER_IDENTIFIER "normal" char version_string[] = YASKKSERV_VERSION ":yaskkserv_" SERVER_IDENTIFIER " "; class LocalSkkServer : private SkkServer { LocalSkkServer(LocalSkkServer &source); LocalSkkServer& operator=(LocalSkkServer &source); public: virtual ~LocalSkkServer() { } LocalSkkServer(int port = 1178, int log_level = 0, const char *address = "0.0.0.0") : SkkServer("yaskkserv_" SERVER_IDENTIFIER, port, log_level, address), skk_dictionary_(0), dictionary_filename_table_(0), skk_dictionary_length_(0), max_connection_(0), listen_queue_(0), dictionary_check_update_flag_(false), no_daemonize_flag_(false) { } void initialize(SkkDictionary *skk_dictionary, const char * const *dictionary_filename_table, int skk_dictionary_length, int max_connection, int listen_queue, bool dictionary_check_update_flag, bool no_daemonize_flag) { skk_dictionary_ = skk_dictionary; dictionary_filename_table_ = dictionary_filename_table; skk_dictionary_length_ = skk_dictionary_length; max_connection_ = max_connection; listen_queue_ = listen_queue; dictionary_check_update_flag_ = dictionary_check_update_flag; no_daemonize_flag_ = no_daemonize_flag; } bool mainLoop() { bool result = main_loop_initialize(max_connection_, listen_queue_); if (result) { #ifndef YASKKSERV_DEBUG if (!no_daemonize_flag_) { if (fork() != 0) { exit(0); } if (chdir("/") != 0) { // why? } close(2); close(1); close(0); printFirstSyslog(); } #endif // YASKKSERV_DEBUG result = local_main_loop(); if (result) { result = main_loop_finalize(); } } return result; } private: bool local_main_loop(); bool local_main_loop_1_search_single_dictionary(int work_index); void main_loop_get_plural_dictionary_information(int work_index, SkkDictionary *skk_dictionary, int skk_dictionary_length, int &found_times, int &candidate_length, int &total_henkanmojiretsu_size); bool local_main_loop_1_search_plural_dictionary(int work_index, int candidate_length, int total_henkanmojiretsu_size); bool local_main_loop_1_search(int work_index); /// ХåեꥻåȤ٤ʤп֤ޤ bool local_main_loop_1(int work_index, int recv_result); private: SkkDictionary *skk_dictionary_; const char * const *dictionary_filename_table_; int skk_dictionary_length_; int max_connection_; int listen_queue_; bool dictionary_check_update_flag_; bool no_daemonize_flag_; }; bool LocalSkkServer::local_main_loop_1_search_single_dictionary(int work_index) { if (skk_dictionary_->search((work_ + work_index)->read_buffer + 1)) { main_loop_send_found(work_index, skk_dictionary_); return true; } else { return false; } } void LocalSkkServer::main_loop_get_plural_dictionary_information(int work_index, SkkDictionary *skk_dictionary, int skk_dictionary_length, int &found_times, int &candidate_length, int &total_henkanmojiretsu_size) { found_times = 0; candidate_length = 0; total_henkanmojiretsu_size = 0; for (int h = 0; h != skk_dictionary_length; ++h) { if ((skk_dictionary + h)->search((work_ + work_index)->read_buffer + 1)) { const int cr_size = 1; total_henkanmojiretsu_size += (skk_dictionary + h)->getHenkanmojiretsuSize() + cr_size; candidate_length += SkkUtility::getCandidateLength((skk_dictionary + h)->getHenkanmojiretsuPointer()); ++found_times; } } } bool LocalSkkServer::local_main_loop_1_search_plural_dictionary(int work_index, int candidate_length, int total_henkanmojiretsu_size) { // candidate_length Ŭ hash_table_length Ѵޤ int hash_table_length = SkkUtility::Hash::getPrimeHashTableLength(candidate_length); if (hash_table_length == 0) { return false; } // դäʣμ candidate ʬ򡢹ޤ // ʸ string ɲäޤʣå hash Ǥʤޤ // Ѵʸ󥵥˥ޡäΤ temporary_buffer_size Ȥ // ޤ int temporary_buffer_size = total_henkanmojiretsu_size; { const int protocol_header_margin_size = 8; const int terminator_size = 1; const int margin_size = 8; temporary_buffer_size += protocol_header_margin_size; temporary_buffer_size += terminator_size; temporary_buffer_size += margin_size; } SkkSimpleString string(temporary_buffer_size); SkkUtility::Hash hash(hash_table_length); // protocol header + first slash string.appendFast("1/"); for (int h = 0; h != skk_dictionary_length_; ++h) { if ((skk_dictionary_ + h)->isSuccess()) { char *p = const_cast((skk_dictionary_ + h)->getHenkanmojiretsuPointer()); int length = SkkUtility::getCandidateLength(p); for (int g = 0; g != length; ++g) { const char *start; int size; if (SkkUtility::getCandidateInformation(p, g, start, size)) { if (!hash.contain(start, size)) { hash.add(start, size); const int tail_slash_size = 1; if (!string.append(start, size + tail_slash_size)) { return false; } } } else { return false; } } } } string.append('\n'); if (!send((work_ + work_index)->file_descriptor, string.getBuffer(), string.getSize())) { (work_ + work_index)->closeAndReset(); } return true; } bool LocalSkkServer::local_main_loop_1_search(int work_index) { // // õϡޤ˰ʲΤ褦ʬޤ // // - ꤵ줿 1 Ĥξ // // - ꤵ줿ʣξ // // = ȥ꤬ 1 ĤμǤդʤä // // = ȥ꤬ʣμǸդä // if (skk_dictionary_length_ == 1) { // ꤵ줿 1 ġ return local_main_loop_1_search_single_dictionary(work_index); } // ꤵ줿ʣ int found_times; int candidate_length; int total_henkanmojiretsu_size; main_loop_get_plural_dictionary_information(work_index, skk_dictionary_, skk_dictionary_length_, found_times, candidate_length, total_henkanmojiretsu_size); if (found_times == 0) { // դʤä return false; } if (found_times == 1) { // ȥ꤬ 1 ĤμǤդʤä for (int h = 0; h != skk_dictionary_length_; ++h) { if ((skk_dictionary_ + h)->isSuccess()) { main_loop_send_found(work_index, skk_dictionary_ + h); } } return true; } // ȥ꤬ʣμǸդä return local_main_loop_1_search_plural_dictionary(work_index, candidate_length, total_henkanmojiretsu_size); } bool LocalSkkServer::local_main_loop_1(int work_index, int recv_result) { bool illegal_protocol_flag; bool result = main_loop_check_buffer(work_index, recv_result, illegal_protocol_flag); if (result) { bool found_flag = false; if (!illegal_protocol_flag) { found_flag = local_main_loop_1_search(work_index); } if (!found_flag) { main_loop_send_not_found(work_index, recv_result); } } return result; } bool LocalSkkServer::local_main_loop() { bool result = true; for (;;) { fd_set fd_set_read; int select_result = main_loop_select(fd_set_read); main_loop_check_reload_dictionary(skk_dictionary_, skk_dictionary_length_, dictionary_filename_table_, dictionary_check_update_flag_); if (select_result == -1) { if (errno == EINTR) { continue; } } if (!main_loop_accept(fd_set_read, select_result)) { goto ERROR_BREAK; } for (int i = 0; i != max_connection_; ++i) { if (main_loop_is_recv(i, fd_set_read)) { int recv_result; bool error_break_flag; if (main_loop_recv(i, recv_result, error_break_flag)) { if (error_break_flag) { goto ERROR_BREAK; } } else { bool buffer_reset_flag; if ((work_ + i)->read_process_index == 0) { switch (*(work_ + i)->read_buffer) { default: buffer_reset_flag = true; main_loop_illegal_command(i); break; case '0': buffer_reset_flag = true; main_loop_0(i); break; case '1': buffer_reset_flag = local_main_loop_1(i, recv_result); break; case '2': buffer_reset_flag = true; main_loop_2(i, version_string, sizeof(version_string)); break; case '3': buffer_reset_flag = true; main_loop_3(i); break; } } else { buffer_reset_flag = local_main_loop_1(i, recv_result); } main_loop_check_buffer_reset(i, recv_result, buffer_reset_flag); } } } } ERROR_BREAK: result = false; //SUCCESS_BREAK: return result; } int print_usage() { SkkUtility::printf("Usage: yaskkserv [OPTION] dictionary [dictionary...]\n" " -a, --address listen address (default 0.0.0.0)\n" " -c, --check-update check update dictionary (default disable)\n" " -d, --debug enable debug mode (default disable)\n" " -h, --help print this help and exit\n" " -l, --log-level=LEVEL loglevel (range [0 - 9] default 1)\n" " -m, --max-connection=N max connection (default 8)\n" " -p, --port=PORT set port (default 1178)\n" " -f, --no-daemonize not daemonize\n" " -v, --version print version\n"); return EXIT_FAILURE; } int print_version() { SkkUtility::printf("yaskkserv_" SERVER_IDENTIFIER " version " YASKKSERV_VERSION "\n"); SkkUtility::printf("Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012, 2013, 2014 Tadashi Watanabe\n"); SkkUtility::printf("http://umiushi.org/~wac/yaskkserv/\n"); return EXIT_FAILURE; } enum { OPTION_TABLE_CHECK_UPDATE, OPTION_TABLE_DEBUG, OPTION_TABLE_HELP, OPTION_TABLE_ADDRESS, OPTION_TABLE_LOG_LEVEL, OPTION_TABLE_MAX_CONNECTION, OPTION_TABLE_PORT, OPTION_TABLE_NO_DAEMONIZE, OPTION_TABLE_VERSION, OPTION_TABLE_LENGTH }; const SkkCommandLine::Option option_table[] = { { "a", "address", SkkCommandLine::OPTION_ARGUMENT_STRING, }, { "c", "check-update", SkkCommandLine::OPTION_ARGUMENT_NONE, }, { "d", "debug", SkkCommandLine::OPTION_ARGUMENT_NONE, }, { "h", "help", SkkCommandLine::OPTION_ARGUMENT_NONE, }, { "l", "log-level", SkkCommandLine::OPTION_ARGUMENT_INTEGER, }, { "m", "max-connection", SkkCommandLine::OPTION_ARGUMENT_INTEGER, }, { "p", "port", SkkCommandLine::OPTION_ARGUMENT_INTEGER, }, { "f", "no-daemonize", SkkCommandLine::OPTION_ARGUMENT_NONE, }, { "v", "version", SkkCommandLine::OPTION_ARGUMENT_NONE, }, { 0, 0, SkkCommandLine::OPTION_ARGUMENT_TERMINATOR, }, }; struct Option { const char *address; int log_level; int max_connection; int port; bool no_daemonize_flag; bool check_update_flag; bool debug_flag; } option = { "0.0.0.0", 1, 8, 1178, false, false, false, }; // ͤʤиƤӽФ¦ return ٤ǤΤȤ result ֤ͤޤͤξ result ˤϿޤ bool local_main_core_command_line(SkkCommandLine &command_line, int &result, int argc, char *argv[]) { if (command_line.parse(argc, argv, option_table)) { if (command_line.isOptionDefined(OPTION_TABLE_HELP)) { result = print_usage(); return true; } if (command_line.isOptionDefined(OPTION_TABLE_VERSION)) { result = print_version(); return true; } // ̵꤬ȡǰΤQ (64) ¿ϤƤ if ((command_line.getArgumentLength() < 1) || (command_line.getArgumentLength() > 64)) { result = print_usage(); return true; } if (command_line.isOptionDefined(OPTION_TABLE_CHECK_UPDATE)) { option.check_update_flag = true; } if (command_line.isOptionDefined(OPTION_TABLE_DEBUG)) { option.debug_flag = true; } if (command_line.isOptionDefined(OPTION_TABLE_ADDRESS)) { option.address = command_line.getOptionArgumentString(OPTION_TABLE_ADDRESS); } if (command_line.isOptionDefined(OPTION_TABLE_LOG_LEVEL)) { option.log_level = command_line.getOptionArgumentInteger(OPTION_TABLE_LOG_LEVEL); if ((option.log_level < 0) || (option.log_level > 9)) { SkkUtility::printf("Illegal log-level %d (0 - 9)\n", option.log_level); result = print_usage(); return true; } } if (command_line.isOptionDefined(OPTION_TABLE_MAX_CONNECTION)) { option.max_connection = command_line.getOptionArgumentInteger(OPTION_TABLE_MAX_CONNECTION); if ((option.max_connection < 1) || (option.max_connection > 1024)) { SkkUtility::printf("Illegal max-connection %d (1 - 1024)\n", option.max_connection); result = print_usage(); return true; } } if (command_line.isOptionDefined(OPTION_TABLE_PORT)) { option.port = command_line.getOptionArgumentInteger(OPTION_TABLE_PORT); if ((option.port < 1) || (option.port > 65535)) { SkkUtility::printf("Illegal port number %d (1 - 65535)\n", option.port); result = print_usage(); return true; } } if (command_line.isOptionDefined(OPTION_TABLE_NO_DAEMONIZE)) { option.no_daemonize_flag = true; } } else { SkkUtility::printf("error \"%s\"\n\n", command_line.getErrorString()); result = print_usage(); return true; } return false; } // ƤӽФ֤٤ EXIT_SUCCESS ޤ EXIT_FAILURE ֤ޤ int local_main_core_setup_dictionary(const SkkCommandLine &command_line, SkkDictionary *skk_dictionary) { int result = EXIT_SUCCESS; int skk_dictionary_length = command_line.getArgumentLength(); for (int i = 0; i != skk_dictionary_length; ++i) { SkkUtility::DictionaryPermission dictionary_permission(command_line.getArgumentPointer(i)); if (!dictionary_permission.isExist()) { SkkUtility::printf("dictionary file \"%s\" (index = %d) not found\n", command_line.getArgumentPointer(i), i); result = EXIT_FAILURE; break; } if (!dictionary_permission.checkAndPrintPermission()) { result = EXIT_FAILURE; break; } if (!(skk_dictionary + i)->open(command_line.getArgumentPointer(i))) { SkkUtility::printf("dictionary file \"%s\" (index = %d) open failed\n", command_line.getArgumentPointer(i), i); result = EXIT_FAILURE; break; } } return result; } int local_main_core(int argc, char *argv[]) { int result = EXIT_SUCCESS; SkkCommandLine command_line; if (local_main_core_command_line(command_line, result, argc, argv)) { return result; } int skk_dictionary_length = command_line.getArgumentLength(); SkkDictionary *skk_dictionary = new SkkDictionary[skk_dictionary_length]; result = local_main_core_setup_dictionary(command_line, skk_dictionary); if (result == EXIT_SUCCESS) { LocalSkkServer *skk_server = new LocalSkkServer(option.port, option.log_level, option.address); const int listen_queue = 5; skk_server->initialize(skk_dictionary, &argv[command_line.getArgumentArgvIndex()], skk_dictionary_length, option.max_connection, listen_queue, option.check_update_flag, option.no_daemonize_flag); if (!skk_server->mainLoop()) { result = EXIT_FAILURE; } delete skk_server; } delete[] skk_dictionary; return result; } } int local_main(int argc, char *argv[]) { return local_main_core(argc, argv); } } yaskkserv-1.1.0/source/yaskkserv_simple/000077500000000000000000000000001262716711600204375ustar00rootroot00000000000000yaskkserv-1.1.0/source/yaskkserv_simple/Makefile.bsd_cygwin_linux_gcc000066400000000000000000000026151262716711600262650ustar00rootroot00000000000000# -*- Makefile -*- include ../Makefile.$(ARCHITECTURE_LOWER_CASE).common TARGET_BASE = yaskkserv_simple RUN_FLAGS = --port=9999 /var/tmp/SKK-JISYO.total+zipcode.yaskkserv CXXFLAGS += $(CXXFLAGS_OPTIMIZE_SERVER_SIMPLE) $(CXXFLAGS_WARNING_SERVER_SIMPLE) SOURCES = ${wildcard *.cpp} OBJECTS = ${addprefix $(VAR_PATH)/$(TARGET_BASE)/,$(SOURCES:.cpp=.o)} OBJECTS_SKK = ${wildcard $(VAR_PATH)/skk/*.o} ${wildcard $(VAR_PATH)/skk/architecture/$(ARCHITECTURE_LOWER_CASE)/*.o} DEPEND_FILE = $(VAR_PATH)/depend.$(TARGET_BASE) TARGET = $(VAR_PATH)/$(TARGET_BASE)/$(TARGET_BASE) .SUFFIXES : .PHONY : all clean run makerun break makebreak kill makekill debugger vlist vhist vreport test depend cleandepend all : $(TARGET) $(TARGET) : $(OBJECTS_SKK) $(OBJECTS) $(LD) $(LDFLAGS) -o $@ $^ $(LDFLAGS_LIBRARY_SIMPLE) ifndef DEBUG $(STRIP) $@$(EXECUTE_FILE_SUFFIX) endif run : cd $(PROJECT_ROOT); export SEGFAULT_SIGNALS=all && export LD_PRELOAD=/lib/libSegFault.so && time $(TARGET) $(RUN_FLAGS) makerun : all run $(DEPEND_FILE) : $(MAKEDEPEND) $(VAR_PATH)/$(TARGET_BASE) $(DEPEND_FILE) '$(CXX) $(CXXFLAGS)' '$(CPP) -E -MM $(CPPFLAGS) $(SOURCES)' depend : $(MAKEDEPEND) $(VAR_PATH)/$(TARGET_BASE) $(DEPEND_FILE) '$(CXX) $(CXXFLAGS)' '$(CPP) -E -MM $(CPPFLAGS) $(SOURCES)' cleandepend : -$(RM) $(DEPEND_FILE) include $(DEPEND_FILE) clean : -$(RM) $(TARGET) $(TARGET).map -$(RM) $(OBJECTS) yaskkserv-1.1.0/source/yaskkserv_simple/yaskkserv_simple.cpp000066400000000000000000000371431262716711600245460ustar00rootroot00000000000000/* Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012, 2013, 2014 Tadashi Watanabe This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "skk_dictionary.hpp" #include "skk_server.hpp" #include "skk_utility.hpp" #include "skk_command_line.hpp" namespace YaSkkServ { namespace { #define SERVER_IDENTIFIER "simple" char version_string[] = YASKKSERV_VERSION ":yaskkserv_" SERVER_IDENTIFIER " "; class LocalSkkServer : private SkkServer { LocalSkkServer(LocalSkkServer &source); LocalSkkServer& operator=(LocalSkkServer &source); public: virtual ~LocalSkkServer() { } LocalSkkServer(int port = 1178, int log_level = 0, const char *address = "0.0.0.0") : SkkServer("yaskkserv_" SERVER_IDENTIFIER, port, log_level, address), skk_dictionary_(0), max_connection_(0), listen_queue_(0) { } void initialize(SkkDictionary *skk_dictionary, int max_connection, int listen_queue) { skk_dictionary_ = skk_dictionary; max_connection_ = max_connection; listen_queue_ = listen_queue; } bool mainLoop() { bool result = main_loop_initialize(max_connection_, listen_queue_); if (result) { #ifndef YASKKSERV_DEBUG if (fork() != 0) { exit(0); } if (chdir("/") != 0) { // why? } close(2); close(1); close(0); printFirstSyslog(); #endif // YASKKSERV_DEBUG result = local_main_loop(); if (result) { result = main_loop_finalize(); } } return result; } private: bool local_main_loop(); bool local_main_loop_1_search(int work_index); /// ХåեꥻåȤ٤ʤп֤ޤ bool local_main_loop_1(int work_index, int recv_result); private: SkkDictionary *skk_dictionary_; int max_connection_; int listen_queue_; }; bool LocalSkkServer::local_main_loop_1_search(int work_index) { if (skk_dictionary_->search((work_ + work_index)->read_buffer + 1)) { main_loop_send_found(work_index, skk_dictionary_); return true; } else { return false; } } bool LocalSkkServer::local_main_loop_1(int work_index, int recv_result) { bool illegal_protocol_flag; bool result = main_loop_check_buffer(work_index, recv_result, illegal_protocol_flag); if (result) { bool found_flag = false; if (!illegal_protocol_flag) { found_flag = local_main_loop_1_search(work_index); } if (!found_flag) { main_loop_send_not_found(work_index, recv_result); } } return result; } bool LocalSkkServer::local_main_loop() { bool result = true; for (;;) { fd_set fd_set_read; int select_result = main_loop_select(fd_set_read); if (select_result == -1) { if (errno == EINTR) { continue; } } if (!main_loop_accept(fd_set_read, select_result)) { goto ERROR_BREAK; } for (int i = 0; i != max_connection_; ++i) { if (main_loop_is_recv(i, fd_set_read)) { int recv_result; bool error_break_flag; if (main_loop_recv(i, recv_result, error_break_flag)) { if (error_break_flag) { goto ERROR_BREAK; } } else { bool buffer_reset_flag; if ((work_ + i)->read_process_index == 0) { switch (*(work_ + i)->read_buffer) { default: buffer_reset_flag = true; main_loop_illegal_command(i); break; case '0': buffer_reset_flag = true; main_loop_0(i); break; case '1': buffer_reset_flag = local_main_loop_1(i, recv_result); break; case '2': buffer_reset_flag = true; main_loop_2(i, version_string, sizeof(version_string)); break; case '3': buffer_reset_flag = true; main_loop_3(i); break; } } else { buffer_reset_flag = local_main_loop_1(i, recv_result); } main_loop_check_buffer_reset(i, recv_result, buffer_reset_flag); } } } } ERROR_BREAK: result = false; //SUCCESS_BREAK: return result; } int print_usage() { SkkUtility::printf("Usage: yaskkserv [OPTION] dictionary\n" " -a, --address listen address (default 0.0.0.0)\n" " -d, --debug enable debug mode (default disable)\n" " -h, --help print this help and exit\n" " -l, --log-level=LEVEL loglevel (range [0 - 9] default 1)\n" " -m, --max-connection=N max connection (default 8)\n" " -p, --port=PORT set port (default 1178)\n" " -v, --version print version\n"); return EXIT_FAILURE; } int print_version() { SkkUtility::printf("yaskkserv_" SERVER_IDENTIFIER " version " YASKKSERV_VERSION "\n"); SkkUtility::printf("Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012, 2013, 2014 Tadashi Watanabe\n"); SkkUtility::printf("http://umiushi.org/~wac/yaskkserv/\n"); return EXIT_FAILURE; } enum { OPTION_TABLE_DEBUG, OPTION_TABLE_HELP, OPTION_TABLE_ADDRESS, OPTION_TABLE_LOG_LEVEL, OPTION_TABLE_MAX_CONNECTION, OPTION_TABLE_PORT, OPTION_TABLE_VERSION, OPTION_TABLE_LENGTH }; const SkkCommandLine::Option option_table[] = { { "a", "address", SkkCommandLine::OPTION_ARGUMENT_STRING, }, { "d", "debug", SkkCommandLine::OPTION_ARGUMENT_NONE, }, { "h", "help", SkkCommandLine::OPTION_ARGUMENT_NONE, }, { "l", "log-level", SkkCommandLine::OPTION_ARGUMENT_INTEGER, }, { "m", "max-connection", SkkCommandLine::OPTION_ARGUMENT_INTEGER, }, { "p", "port", SkkCommandLine::OPTION_ARGUMENT_INTEGER, }, { "v", "version", SkkCommandLine::OPTION_ARGUMENT_NONE, }, { 0, 0, SkkCommandLine::OPTION_ARGUMENT_TERMINATOR, }, }; struct Option { const char *address; int log_level; int max_connection; int port; bool debug_flag; } option = { "0.0.0.0", 1, 8, 1178, false, }; // ͤʤиƤӽФ¦ return ٤ǤΤȤ result ֤ͤޤͤξ result ˤϿޤ bool local_main_core_command_line(SkkCommandLine &command_line, int &result, int argc, char *argv[]) { if (command_line.parse(argc, argv, option_table)) { if (command_line.isOptionDefined(OPTION_TABLE_HELP)) { result = print_usage(); return true; } if (command_line.isOptionDefined(OPTION_TABLE_VERSION)) { result = print_version(); return true; } // ̵꤬ȡǰΤQ (64) ¿ϤƤ if ((command_line.getArgumentLength() < 1) || (command_line.getArgumentLength() > 64)) { result = print_usage(); return true; } if (command_line.isOptionDefined(OPTION_TABLE_DEBUG)) { option.debug_flag = true; } if (command_line.isOptionDefined(OPTION_TABLE_ADDRESS)) { option.address = command_line.getOptionArgumentString(OPTION_TABLE_ADDRESS); } if (command_line.isOptionDefined(OPTION_TABLE_LOG_LEVEL)) { option.log_level = command_line.getOptionArgumentInteger(OPTION_TABLE_LOG_LEVEL); if ((option.log_level < 0) || (option.log_level > 9)) { SkkUtility::printf("Illegal log-level %d (0 - 9)\n", option.log_level); result = print_usage(); return true; } } if (command_line.isOptionDefined(OPTION_TABLE_MAX_CONNECTION)) { option.max_connection = command_line.getOptionArgumentInteger(OPTION_TABLE_MAX_CONNECTION); if ((option.max_connection < 1) || (option.max_connection > 1024)) { SkkUtility::printf("Illegal max-connection %d (1 - 1024)\n", option.max_connection); result = print_usage(); return true; } } if (command_line.isOptionDefined(OPTION_TABLE_PORT)) { option.port = command_line.getOptionArgumentInteger(OPTION_TABLE_PORT); if ((option.port < 1) || (option.port > 65535)) { SkkUtility::printf("Illegal port number %d (1 - 65535)\n", option.port); result = print_usage(); return true; } } } else { SkkUtility::printf("error \"%s\"\n\n", command_line.getErrorString()); result = print_usage(); return true; } return false; } // ƤӽФ֤٤ EXIT_SUCCESS ޤ EXIT_FAILURE ֤ޤ int local_main_core_setup_dictionary(const SkkCommandLine &command_line, SkkDictionary *skk_dictionary) { int result = EXIT_SUCCESS; int skk_dictionary_length = command_line.getArgumentLength(); for (int i = 0; i != skk_dictionary_length; ++i) { SkkUtility::DictionaryPermission dictionary_permission(command_line.getArgumentPointer(i)); if (!dictionary_permission.isExist()) { SkkUtility::printf("dictionary file \"%s\" (index = %d) not found\n", command_line.getArgumentPointer(i), i); result = EXIT_FAILURE; break; } if (!dictionary_permission.checkAndPrintPermission()) { result = EXIT_FAILURE; break; } if (!(skk_dictionary + i)->open(command_line.getArgumentPointer(i))) { SkkUtility::printf("dictionary file \"%s\" (index = %d) open failed\n", command_line.getArgumentPointer(i), i); result = EXIT_FAILURE; break; } } return result; } int local_main_core(int argc, char *argv[]) { int result = EXIT_SUCCESS; SkkCommandLine command_line; if (local_main_core_command_line(command_line, result, argc, argv)) { return result; } int skk_dictionary_length = command_line.getArgumentLength(); if (skk_dictionary_length != 1) { return print_usage(); } SkkDictionary *skk_dictionary = new SkkDictionary[skk_dictionary_length]; result = local_main_core_setup_dictionary(command_line, skk_dictionary); if (result == EXIT_SUCCESS) { LocalSkkServer *skk_server = new LocalSkkServer(option.port, option.log_level, option.address); const int listen_queue = 5; skk_server->initialize(skk_dictionary, option.max_connection, listen_queue); if (!skk_server->mainLoop()) { result = EXIT_FAILURE; } delete skk_server; } delete[] skk_dictionary; return result; } } int local_main(int argc, char *argv[]) { return local_main_core(argc, argv); } } yaskkserv-1.1.0/tools/000077500000000000000000000000001262716711600147045ustar00rootroot00000000000000yaskkserv-1.1.0/tools/build/000077500000000000000000000000001262716711600160035ustar00rootroot00000000000000yaskkserv-1.1.0/tools/build/makedepend.bsd_cygwin_linux_gcc000077500000000000000000000024301262716711600242070ustar00rootroot00000000000000#!/usr/bin/perl -w use strict; use warnings; die if $#ARGV != 3; my $var_path = shift(@ARGV); my $write_file = shift(@ARGV); my $cxx_command_line = shift(@ARGV); my $cpp_command_line = shift(@ARGV); my @data; my $data = ''; my %mkdir; my $last_object; my $last_source; { open(my $fh, '-|', $cpp_command_line) or die; my $tmp = ''; while (<$fh>) { chomp; if (/\\[ \t]*$/) { s/\\+[ \t]*$//; $tmp .= $_; } else { if ($tmp ne '') { $_ = "$tmp $_"; $tmp = ''; } s/ +/ /g; s/ *: */:/; push(@data, "$_\n"); } } } foreach (@data) { if (m!^([^:]+):([^ ]+)( .+)!) { my $object = $1; my $source = $2; my $object_base = $object; my $source_base = $source; my $prefix = "$var_path/"; if ($source_base =~ s!^(.+/)!!) { $prefix .= $1; } $object_base =~ s!\.[^\.]+$!!; $source_base =~ s!\.[^\.]+$!!; die if $object_base ne $source_base; $data .= $prefix . $_; $object = $prefix . $object; $data .= "\t$cxx_command_line -c $source -o $object\n"; $data .= "\n\n"; my $tmp = ''; foreach (split(m!/!, $prefix)) { $tmp .= "$_/"; unless (defined($mkdir{$tmp})) { ++$mkdir{$tmp}; mkdir($tmp) unless (-d $tmp); } } } else { die; } } open(my $wfh, '>', $write_file) or die; print $wfh $data;