Logo Search packages:      
Sourcecode: yaskkserv version File versions  Download package

yaskkserv_hairy.cpp

/*
  Copyright (C) 2005, 2006, 2007, 2008 Tadashi Watanabe <wac@umiushi.org>

  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 SERVER_IDENTIFIER "hairy"
static char version_string[] = YASKKSERV_VERSION ":yaskkserv_" SERVER_IDENTIFIER " ";




class LocalSkkServer : SkkServer
{
        LocalSkkServer(LocalSkkServer &source);
        LocalSkkServer& operator=(LocalSkkServer &source);




public:
        virtual ~LocalSkkServer()
        {
        }


        LocalSkkServer(int port = 1178,
                       int log_level = 0) :
                SkkServer("yaskkserv_" SERVER_IDENTIFIER,
                          port,
                          log_level),

                skk_dictionary_(0),
                dictionary_filename_table_(0),

                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)
        {
        }


        void initialize(SkkDictionary *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,
                        bool dictionary_check_update_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;
                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;
        }


        bool mainLoop()
        {
                bool result;

                result = main_loop_initialize(max_connection_,
                                              listen_queue_);
                if (result)
                {
#ifndef YASKKSERV_DEBUG
                        if (fork() != 0)
                        {
                                exit(0);
                        }
                        chdir("/");
                        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);
        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);


        bool local_main_loop_4_search_core(int work_index,
                                           int recv_result,
                                           SkkUtility::Hash<SkkUtility::HASH_TYPE_CANDIDATE> *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);




private:
        SkkDictionary *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_;
        char server_completion_test_protocol_;

        bool dictionary_check_update_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;
        }
}




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<SkkUtility::HASH_TYPE_CANDIDATE>::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<SkkUtility::HASH_TYPE_CANDIDATE> hash(hash_table_length);

// protocol header + first slash
        string.append("1/");

        for (int h = 0; h != skk_dictionary_length_; ++h)
        {
                if ((skk_dictionary_ + h)->isSuccess())
                {
                        char *p = const_cast<char*>((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;
                                                string.append(start,
                                                              size + tail_slash_size);
                                        }
                                }
                                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_4_search_core(int work_index,
                                                   int recv_result,
                                                   SkkUtility::Hash<SkkUtility::HASH_TYPE_CANDIDATE> *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.append("1/");
                break;

        case 3:
                string.append("1 ");
                break;

        case 4:
                if (server_completion_test_protocol_ == '4')
                {
                        string.append("1/");
                }
                else
                {
                        string.append("1 ");
                }
                break;
        }

        int add_counter = 0;
        for (int h = 0; h != skk_dictionary_length_; ++h)
        {
                if ((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.append('/'); // + separator_size
                                                                break;

                                                        case 3:
                                                                string.append(' '); // + separator_size
                                                                break;

                                                        case 4:
                                                                if (server_completion_test_protocol_ == '4')
                                                                {
                                                                        string.append('/'); // + separator_size
                                                                }
                                                                else
                                                                {
                                                                        string.append(' '); // + 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;
        }


        string.append("\n");


        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)->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<SkkUtility::HASH_TYPE_CANDIDATE> *hash = 0;

                if (found_times > 1)
                {
// 重複チェックが必要なのは複数の辞書を操作する場合だけです。
                        int prime_length = SkkUtility::Hash<SkkUtility::HASH_TYPE_CANDIDATE>::getPrimeHashTableLength(server_completion_midasi_length_);
                        hash = new SkkUtility::Hash<SkkUtility::HASH_TYPE_CANDIDATE>(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(server_completion_midasi_string_size_)))
        {
                (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;
}




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)
                                        {
                                                server_completion_test_protocol_ = *(work_ + i)->read_buffer;
                                                switch (*(work_ + i)->read_buffer)
                                                {
                                                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;

                                                default:
                                                        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);
                                }
                        }
                }
        }
ERROR_BREAK:
        result = false;

//SUCCESS_BREAK:

        return result;
}




static int print_usage()
{
        SkkUtility::printf("Usage: yaskkserv [OPTION] dictionary [dictionary...]\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"
                           "      --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"
                           "  -v, --version            print version\n");

        return EXIT_FAILURE;
}




static int print_version()
{
        SkkUtility::printf("yaskkserv_" SERVER_IDENTIFIER " version " YASKKSERV_VERSION "\n");
        SkkUtility::printf("Copyright (C) 2005, 2006, 2007, 2008 Tadashi Watanabe\n");
        SkkUtility::printf("http://umiushi.org/~wac/yaskkserv/\n");

        return EXIT_FAILURE;
}




int local_main(int argc,
               char *argv[])
{
        enum
        {
                OPTION_TABLE_CHECK_UPDATE,
                OPTION_TABLE_DEBUG,
                OPTION_TABLE_HELP,
                OPTION_TABLE_LOG_LEVEL,
                OPTION_TABLE_MAX_CONNECTION,
                OPTION_TABLE_PORT,
                OPTION_TABLE_SERVER_COMPLETION_MIDASI_LENGTH,
                OPTION_TABLE_SERVER_COMPLETION_MIDASI_STRING_SIZE,
                OPTION_TABLE_SERVER_COMPLETION_TEST,
                OPTION_TABLE_VERSION,

                OPTION_TABLE_LENGTH
        };


        const SkkCommandLine::Option option_table[] =
        {
                {
                        "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,
                },

                {
                        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,
                },

                {
                        "v", "version",
                        SkkCommandLine::OPTION_ARGUMENT_NONE,
                },

                {
                        0, 0,
                        SkkCommandLine::OPTION_ARGUMENT_TERMINATOR,
                },
        };


        struct Option
        {
                int log_level;
                int max_connection;
                int port;
                int server_completion_midasi_length;
                int server_completion_midasi_string_size;
                int server_completion_test;
                bool check_update_flag;
                bool debug_flag;
        }
        option =
        {
                1,
                8,
                1178,
                2048,
                262144,
                1,
                false,
                false,
        };




        int result = EXIT_SUCCESS;
        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();
                }
// 辞書指定が無い場合と、念のため非常識な値 (64) より多い指定をはじいておく。
                if ((command_line.getArgumentLength() < 1) ||
                    (command_line.getArgumentLength() > 64))
                {
                        return print_usage();
                }

                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_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);
                                return print_usage();
                        }
                }
                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);
                                return print_usage();
                        }
                }
                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);
                                return print_usage();
                        }
                }
                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",
                                                   option.server_completion_midasi_length);
                                return print_usage();
                        }
                }
                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",
                                                   option.server_completion_midasi_string_size);
                                return print_usage();
                        }
                }
                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",
                                                   option.server_completion_test);
                                return print_usage();
                        }
                }
        }
        else
        {
                SkkUtility::printf("error \"%s\"\n\n",
                                   command_line.getErrorString());
                return print_usage();
        }




        int skk_dictionary_length = command_line.getArgumentLength();
        SkkDictionary *skk_dictionary = new SkkDictionary[skk_dictionary_length];
        uid_t euid = geteuid();
        for (int i = 0; i != skk_dictionary_length; ++i)
        {
                struct stat stat_work;
                if (stat(command_line.getArgumentPointer(i),
                         &stat_work) == -1)
                {
                        SkkUtility::printf("dictionary file \"%s\" (index = %d) not found\n",
                                           command_line.getArgumentPointer(i),
                                           i);
                        result = EXIT_FAILURE;
                        break;
                }


                // 辞書のパーミッションは正当か?
                if ((stat_work.st_uid == 0) ||
                    (stat_work.st_uid == euid))
                {
                        if (stat_work.st_mode & 0022)
                        {
                                SkkUtility::printf("illegal permission 0%o \"%s\"\n"
                                                   "Try chmod go-w %s\n"
                                                   ,
                                                   stat_work.st_mode & 0777,
                                                   command_line.getArgumentPointer(i),
                                                   command_line.getArgumentPointer(i));
                                result = EXIT_FAILURE;
                                break;
                        }
                }
                else
                {
                        SkkUtility::printf("illegal owner \"%s\"\n"
                                           "file owner must be root or same euid\n"
                                           ,
                                           command_line.getArgumentPointer(i));
                        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;
                }
        }


        if (result == EXIT_SUCCESS)
        {
                LocalSkkServer *skk_server = new LocalSkkServer(option.port,
                                                                option.log_level);
                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.check_update_flag);
                if (!skk_server->mainLoop())
                {
                        result = EXIT_FAILURE;
                }
                delete skk_server;
        }

        delete[] skk_dictionary;

        return result;
}

Generated by  Doxygen 1.6.0   Back to index