Tomotaka SUWA
t-suw****@users*****
2006年 2月 18日 (土) 02:20:38 JST
Index: AquaSKK/AquaSKKServer.h diff -u /dev/null AquaSKK/AquaSKKServer.h:1.1.2.1 --- /dev/null Sat Feb 18 02:20:38 2006 +++ AquaSKK/AquaSKKServer.h Sat Feb 18 02:20:38 2006 @@ -0,0 +1,31 @@ +/* + $Id: AquaSKKServer.h,v 1.1.2.1 2006/02/17 17:20:38 t-suwa Exp $ + + MacOS X implementation of the SKK input method. + + Copyright (C) 2002 phonohawk + Copyright (C) 2005 Tomotaka SUWA <t.suw****@mac*****> + + 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 + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#pragma once + + @ interface AquaSKKServer: NSObject +{ +} +- (void)applicationDidFinishLaunching:(NSNotification*)aNotification; +- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender; + @ end Index: AquaSKK/AquaSKKServer.mm diff -u /dev/null AquaSKK/AquaSKKServer.mm:1.1.2.1 --- /dev/null Sat Feb 18 02:20:38 2006 +++ AquaSKK/AquaSKKServer.mm Sat Feb 18 02:20:38 2006 @@ -0,0 +1,57 @@ +/* -*- objc -*- + $Id: AquaSKKServer.mm,v 1.1.2.1 2006/02/17 17:20:38 t-suwa Exp $ + + MacOS X implementation of the SKK input method. + + Copyright (C) 2002 phonohawk + Copyright (C) 2005-2006 Tomotaka SUWA <t.suw****@mac*****> + + 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 + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <AppKit/AppKit.h> +#include "AquaSKKServer.h" +#include "PreferencesController.h" +#include "DictionarySet.h" +#include "BIMClientServer.h" +#include "ServerMessageReceiver.h" +#include "skkserv.h" + + @ implementation AquaSKKServer + +- (void)applicationDidFinishLaunching:(NSNotification*)aNotification { + // vt@Xðæ¾ + PreferencesController* pref = [PreferencesController sharedController]; + + // «T[o[ðN®·é + DictionarySet::theInstance().initialize(); + + // bZ[WnhðN®·é + ServerMessageReceiver::start(kAquaSKKServerRunLoopMode); + + // skkserv G~ [VÌN® + if([pref isSkkservEnabled]) { + skkserv::theInstance().start([pref skkservPort], [pref isSkkservLocalOnly]); + } +} + +- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender { + // «T[o[ðÆ· + DictionarySet::theInstance().terminate(); + + return NSTerminateNow; +} + + @ end Index: AquaSKK/BS.mm diff -u AquaSKK/BS.mm:1.2.2.1 AquaSKK/BS.mm:1.2 --- AquaSKK/BS.mm:1.2.2.1 Mon Jan 9 11:11:05 2006 +++ AquaSKK/BS.mm Sat Oct 8 00:08:36 2005 @@ -1,29 +1,28 @@ -/* - $Id: BS.mm,v 1.2.2.1 2006/01/09 02:11:05 t-suwa Exp $ - - MacOS X implementation of the SKK input method. - - Copyright (C) 2002 phonohawk - Copyright (C) 2006 Tomotaka SUWA <t.suw****@mac*****> - - 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 - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/* -*- objc -*- + $Id: BS.mm,v 1.2 2005/10/07 15:08:36 t-suwa Exp $ + --------- + + MacOS X implementation of the SKK input method. + Copyright (C) 2002 phonohawk + + 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 + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #import <Cocoa/Cocoa.h> -// AquaSKKServer のエントリポイント -int main(int argc, const char *argv[]) { +int main(int argc, const char *argv[]) +{ return NSApplicationMain(argc, argv); } Index: AquaSKK/ChangeLog diff -u AquaSKK/ChangeLog:1.20.2.4 AquaSKK/ChangeLog:1.20.2.5 --- AquaSKK/ChangeLog:1.20.2.4 Sat Jan 14 20:01:58 2006 +++ AquaSKK/ChangeLog Sat Feb 18 02:20:38 2006 @@ -1,3 +1,31 @@ +2006-02-18 Tomotaka SUWA <t.suw****@mac*****> + + * skkserv.*: socketstream ðg¤æ¤ÉC³B + + * socketstream.h: VKÇÁB + + * Dictionary.h: «ÌC^tF[XðÏXB + + * t@C¼ðÏX + BS.mm ¨ main.m + DMDictionary.* ¨ KotoeriDictionary.* + Foundation.* ¨ AquaSKKServer.* + SKKServer.* ¨ DictionarySet.* + Skkserv.* ¨ skksev.* + +2006-02-15 Tomotaka SUWA <t.suw****@mac*****> + + * SKKServer.*: ¡«ÉÎB + + * PreferencesController.*: VKÉu«vðÇÁµAuSKK «vÆ + u±Æ¦è«vðíB + + * Foundation.mm: ú»ªðC³B + + * DictArrayController.*: VKÇÁBNSArrayController ÌTuNXB + + * DMDictionary.*: 1 NX 1 «ÌÖWÉC³B + 2006-01-14 Tomotaka SUWA <t.suw****@mac*****> * ½Ìt@C: SÌIÉRXeBbNÈC³B Index: AquaSKK/DMDictionary.cpp diff -u AquaSKK/DMDictionary.cpp:1.4.2.1 AquaSKK/DMDictionary.cpp:1.4 --- AquaSKK/DMDictionary.cpp:1.4.2.1 Wed Feb 15 00:12:44 2006 +++ AquaSKK/DMDictionary.cpp Tue Nov 15 00:37:13 2005 @@ -1,10 +1,10 @@ /* - $Id: DMDictionary.cpp,v 1.4.2.1 2006/02/14 15:12:44 t-suwa Exp $ + $Id: DMDictionary.cpp,v 1.4 2005/11/14 15:37:13 t-suwa Exp $ MacOS X implementation of the SKK input method. Copyright (C) 2002 phonohawk - Copyright (C) 2005-2006 Tomotaka SUWA <t.suw****@mac*****> + Copyright (C) 2005 Tomotaka SUWA <t.suw****@mac*****> 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 @@ -35,8 +35,9 @@ static OSErr FilePathToFSSpec(CFStringRef filePath, FSSpec* apSpec); -KotoeriDictionary::KotoeriDictionary(const std::string path) : path_(0), isRegistered_(false), id_(0) { - path_ = CFStringCreateWithCString(kCFAllocatorDefault, path.c_str(), kCFStringEncodingEUC_JP); +DMDictionary::KotoeriDictionary::KotoeriDictionary(const CFStringRef path) + : path_(0), isRegistered_(false), id_(0) { + path_ = CFStringCreateCopy(kCFAllocatorDefault, path); if(!path_) { std::cerr << "KotoeriDictionary: CFStringCreateCopy() failed" << std::endl; return; @@ -55,16 +56,9 @@ } isRegistered_ = true; } - - char buf[1024]; - CFStringGetCString(path_, buf, sizeof(buf), kCFStringEncodingUTF8); - std::cerr << "Kotoeri Dictionary(" << buf << ")" << std::endl - << " okuri-ari: 0 entries." << std::endl - << " okuri-nasi: " << countOkuriNasi() << " entries." - << std::endl << std::endl; } -KotoeriDictionary::~KotoeriDictionary() { +DMDictionary::KotoeriDictionary::~KotoeriDictionary() { if(isRegistered_) { DCMUnregisterDictionary(id_); } @@ -74,11 +68,38 @@ } } -int KotoeriDictionary::countOkuriAri() { - return 0; +bool DMDictionary::KotoeriDictionary::Find(const CFStringRef key, + DCMFoundRecordIterator* iterator) { + DCMDictionaryRef ref; + if(DCMOpenDictionary(id_, 0, NULL, &ref) != noErr) { + std::cerr << "DCMOpenDictionary() failed" << std::endl; + return false; + } + + // R[hðõ + OSStatus status; + DCMFieldTag dataFieldTagList[] = { kDCMJapaneseHyokiTag }; + ByteCount length = CFStringGetLength(key) * sizeof(UniChar); + status = DCMFindRecords(ref, // Dictionary reference + kDCMJapaneseYomiTag, // key field tag + length, // key data length + CFStringGetCharactersPtr(key), // key data + kDCMFindMethodExactMatch, // find method + 1, // number of data field + dataFieldTagList, // data field tag list + 0, 0, // search all records + iterator); // found result + + DCMCloseDictionary(ref); + + return (status == noErr); } -int KotoeriDictionary::countOkuriNasi() { +const bool DMDictionary::KotoeriDictionary::IsGood() const { + return (id_ != 0); +} + +const int DMDictionary::KotoeriDictionary::Count() const { ItemCount numItems; if(DCMCountRecord(id_, &numItems) == noErr) { return numItems; @@ -87,96 +108,145 @@ return 0; } -std::vector<OkuriganaEntry> KotoeriDictionary::findOkuriAri(const CppCFString& str) { - // ±Æ¦è«ÉÍuè èvͶݵȢ - return std::vector<OkuriganaEntry>(); +const void DMDictionary::KotoeriDictionary::Description() const { + char buf[1024]; + CFStringGetCString(path_, buf, sizeof(buf), kCFStringEncodingUTF8); + std::cerr << "Kotoeri Dictionary(" << buf << ")" << std::endl + << " okuri-ari: 0 entries." << std::endl + << " okuri-nasi: " << Count() << " entries." + << std::endl << std::endl; } -std::vector<CppCFString> KotoeriDictionary::findOkuriNasi(const CppCFString& str) { - OSStatus status; - std::vector<CppCFString> result; +// ------------------------------------------------------------------ + +DMDictionary::DMDictionary(const std::vector<CppCFString>& kotoeri_dic_file) { + load(kotoeri_dic_file); +} + +DMDictionary::~DMDictionary() { + unload(); +} - DCMFoundRecordIterator iterator; - if(!find(str.getString(), &iterator)) { - return result; - } - - while(true) { - ByteCount keySize; - char foundKeyStr[kMaxKanjiLengthInAppleJapaneseDictionary]; - DCMUniqueID uniqueID; - AERecord dataList; - - // Get one record from result list - status = DCMIterateFoundRecord(iterator, // found result - kMaxKanjiLengthInAppleJapaneseDictionary, // key buffer size - &keySize, // actual found key size - foundKeyStr, // found key data - &uniqueID, // j[NID - &dataList); // AERecordf[^ - - if(status != noErr) break; - - DescType actualType; - char dataBuffer[kMaxKanjiLengthInAppleJapaneseDictionary]; - Size actualSize; - - // Get one data from AERecord - status = AEGetKeyPtr(&dataList, - kDCMJapaneseHyokiTag, - 'utxt', - &actualType, - dataBuffer, - kMaxKanjiLengthInAppleJapaneseDictionary, - &actualSize); - - // Dispose data AERecord - AEDisposeDesc(&dataList); +int DMDictionary::countOkuriAri() { + return 0; +} - if(status != noErr) break; +int DMDictionary::countOkuriNasi() { + int result = 0; - // ÊÉÇÁ·é - result.push_back(CppCFData(dataBuffer, actualSize).getData()); + for(KotoeriDictionaryIterator i = dics_.begin(); i != dics_.end(); ++ i) { + result += (*i)->Count(); } - DCMDisposeRecordIterator(iterator); return result; } -bool KotoeriDictionary::find(const CFStringRef key, DCMFoundRecordIterator* iterator) { - DCMDictionaryRef ref; - if(DCMOpenDictionary(id_, 0, NULL, &ref) != noErr) { - std::cerr << "DCMOpenDictionary() failed" << std::endl; - return false; - } +std::vector<OkuriganaEntry> DMDictionary::findOkuriAri(const CppCFString& str) { + // ±Æ¦è«ÉÍuè èvͶݵȢ + return std::vector<OkuriganaEntry>(); +} - // R[hðõ +std::vector<CppCFString> DMDictionary::findOkuriNasi(const CppCFString& str) { OSStatus status; - DCMFieldTag dataFieldTagList[] = { kDCMJapaneseHyokiTag }; - ByteCount length = CFStringGetLength(key) * sizeof(UniChar); - status = DCMFindRecords(ref, // Dictionary reference - kDCMJapaneseYomiTag, // key field tag - length, // key data length - CFStringGetCharactersPtr(key), // key data - kDCMFindMethodExactMatch, // find method - 1, // number of data field - dataFieldTagList, // data field tag list - 0, 0, // search all records - iterator); // found result + std::vector<CppCFString> result; - DCMCloseDictionary(ref); + for(KotoeriDictionaryIterator i = dics_.begin(); i != dics_.end(); ++ i) { + DCMFoundRecordIterator iterator; + if(!(*i)->Find(str.getString(), &iterator)) continue; + + while(true) { + ByteCount keySize; + char foundKeyStr[kMaxKanjiLengthInAppleJapaneseDictionary]; + DCMUniqueID uniqueID; + AERecord dataList; + + // Get one record from result list + status = DCMIterateFoundRecord(iterator, // found result + kMaxKanjiLengthInAppleJapaneseDictionary, // key buffer size + &keySize, // actual found key size + foundKeyStr, // found key data + &uniqueID, // j[NID + &dataList); // AERecordf[^ + + if(status != noErr) break; + + DescType actualType; + char dataBuffer[kMaxKanjiLengthInAppleJapaneseDictionary]; + Size actualSize; + + // Get one data from AERecord + status = AEGetKeyPtr(&dataList, + kDCMJapaneseHyokiTag, + 'utxt', + &actualType, + dataBuffer, + kMaxKanjiLengthInAppleJapaneseDictionary, + &actualSize); + + // Dispose data AERecord + AEDisposeDesc(&dataList); + + if(status != noErr) break; + + // ÊÉÇÁ·é + result.push_back(CppCFData(dataBuffer, actualSize).getData()); + } + DCMDisposeRecordIterator(iterator); + } - return (status == noErr); + return result; +} + +void DMDictionary::changeDictionaryFile(const std::vector<CppCFString>& dics) { + unload(); + load(dics); +} + +bool DMDictionary::checkDictionary(const CFStringRef path) { + return KotoeriDictionary(path).IsGood(); +} + +// ------------------------------------------------------------------ + +void DMDictionary::load(const std::vector<CppCFString>& dics) { + for(std::vector<CppCFString>::const_iterator ite = dics.begin(); + ite != dics.end(); ++ ite) { + KotoeriDictionary* dic = new KotoeriDictionary(ite->getString()); + if(dic->IsGood()) { + dics_.push_back(dic); + dic->Description(); + } else { + delete dic; + } + } +} + +void DMDictionary::unload() { + struct local { + static void DeleteObject(const KotoeriDictionary* ptr) { + delete ptr; + } + }; + std::for_each(dics_.begin(), dics_.end(), local::DeleteObject); + dics_.clear(); } static OSErr FilePathToFSSpec(CFStringRef filePath, FSSpec* apSpec) { FSRef fileRef; OSErr err = !noErr; - CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, filePath, kCFURLPOSIXPathStyle, false); - if(CFURLGetFSRef(url, &fileRef)) { - err = FSGetCatalogInfo(&fileRef, kFSCatInfoNone, NULL, NULL, apSpec, NULL); + CFURLRef cfUrl = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, + filePath, + kCFURLPOSIXPathStyle, + false); + if(CFURLGetFSRef(cfUrl, &fileRef)) { + err = FSGetCatalogInfo(&fileRef, + kFSCatInfoNone, + NULL, + NULL, + apSpec, + NULL); } - if(url) CFRelease(url); + CFRelease(cfUrl); return err; } Index: AquaSKK/DMDictionary.h diff -u AquaSKK/DMDictionary.h:1.4.2.1 AquaSKK/DMDictionary.h:1.4 --- AquaSKK/DMDictionary.h:1.4.2.1 Wed Feb 15 00:12:44 2006 +++ AquaSKK/DMDictionary.h Tue Nov 15 00:37:13 2005 @@ -1,10 +1,10 @@ /* - $Id: DMDictionary.h,v 1.4.2.1 2006/02/14 15:12:44 t-suwa Exp $ + $Id: DMDictionary.h,v 1.4 2005/11/14 15:37:13 t-suwa Exp $ MacOS X implementation of the SKK input method. Copyright (C) 2002 phonohawk - Copyright (C) 2005-2006 Tomotaka SUWA <t.suw****@mac*****> + Copyright (C) 2005 Tomotaka SUWA <t.suw****@mac*****> 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 @@ -32,19 +32,37 @@ class OkuriganaEntry; class CppCFString; -class KotoeriDictionary: public Dictionary { - CFStringRef path_; - bool isRegistered_; - DCMDictionaryID id_; +class DMDictionary: public Dictionary { + class KotoeriDictionary { + CFStringRef path_; + bool isRegistered_; + DCMDictionaryID id_; + + public: + KotoeriDictionary(const CFStringRef path); + ~KotoeriDictionary(); + + bool Find(const CFStringRef key, DCMFoundRecordIterator* iterator); + const bool IsGood() const; + const int Count() const; + const void Description() const; + }; + typedef std::vector<KotoeriDictionary*> KotoeriDictionaryContainer; + typedef KotoeriDictionaryContainer::iterator KotoeriDictionaryIterator; + KotoeriDictionaryContainer dics_; - bool find(const CFStringRef key, DCMFoundRecordIterator* iterator); + void load(const std::vector<CppCFString>& dicFiles); + void unload(); public: - KotoeriDictionary(const std::string path); - virtual ~KotoeriDictionary(); + DMDictionary(const std::vector<CppCFString>& kotoeri_dic_file); + virtual ~DMDictionary(); virtual int countOkuriAri(); virtual int countOkuriNasi(); - virtual std::vector<OkuriganaEntry> findOkuriAri(const CppCFString& str); - virtual std::vector<CppCFString> findOkuriNasi(const CppCFString& str); + virtual std::vector<OkuriganaEntry> findOkuriAri(const CppCFString& root); + virtual std::vector<CppCFString> findOkuriNasi(const CppCFString& query); + + void changeDictionaryFile(const std::vector<CppCFString>& kotoeri_dic_file); + bool checkDictionary(const CFStringRef fpath); }; Index: AquaSKK/Dictionary.h diff -u AquaSKK/Dictionary.h:1.3.2.2 AquaSKK/Dictionary.h:1.3.2.3 --- AquaSKK/Dictionary.h:1.3.2.2 Wed Feb 15 00:12:44 2006 +++ AquaSKK/Dictionary.h Sat Feb 18 02:20:38 2006 @@ -1,5 +1,5 @@ /* - $Id: Dictionary.h,v 1.3.2.2 2006/02/14 15:12:44 t-suwa Exp $ + $Id: Dictionary.h,v 1.3.2.3 2006/02/17 17:20:38 t-suwa Exp $ MacOS X implementation of the SKK input method. @@ -35,6 +35,9 @@ public: virtual ~Dictionary() {}; + // ú»(øÍ EUC ¶ñ) + virtual void load(const std::string& location) = 0; + // «Ìîñ virtual int countOkuriAri() = 0; virtual int countOkuriNasi() = 0; Index: AquaSKK/DictionarySet.cpp diff -u /dev/null AquaSKK/DictionarySet.cpp:1.1.2.1 --- /dev/null Sat Feb 18 02:20:38 2006 +++ AquaSKK/DictionarySet.cpp Sat Feb 18 02:20:38 2006 @@ -0,0 +1,500 @@ +/* + $Id: DictionarySet.cpp,v 1.1.2.1 2006/02/17 17:20:38 t-suwa Exp $ + + MacOS X implementation of the SKK input method. + + Copyright (C) 2002-2004 phonohawk + Copyright (C) 2005-2006 Tomotaka SUWA <t.suw****@mac*****> + + 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 + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <iostream> +#include <sstream> +#include "CppCFString.h" +#include "OkuriganaEntry.h" +#include "Dictionary.h" +#include "SKKDictionary.h" +#include "KotoeriDictionary.h" +#include "DictionarySet.h" +#include "SkkConfig.h" + +#if 0 +# define D_PRINTF printf +#else +# define D_PRINTF if(0)printf +#endif + +// èÈÇ +const char* SKK_USER_DICT_PATH = "/Library/AquaSKK/skk-user-dic"; + +// [eBeB +static void removeRedundantItems(std::vector<CppCFString>& candidates); + +// Null « +class NullDictionary: public Dictionary { +public: + NullDictionary() { + // empty + } + virtual ~NullDictionary() { + // empty + } + virtual void load(const std::string& location) { + // empty + } + virtual int countOkuriAri() { + return 0; + } + virtual int countOkuriNasi() { + return 0; + } + virtual std::vector<OkuriganaEntry> findOkuriAri(const CppCFString& query) { + return std::vector<OkuriganaEntry>(); + } + virtual std::vector<CppCFString> findOkuriNasi(const CppCFString& query) { + return std::vector<CppCFString>(); + } +}; + +// t@Ng\bh +Dictionary* DictionarySet::createDictionary(const DictionaryPref& pref) const { + Dictionary* dict; + + // «Ì¶¬ + switch(pref.type) { + case SKKDictionaryType: + dict = new SKKDictionary(); + break; + case SKKAutoUpdateDictionaryType: // ¢À + dict = new NullDictionary(); + break; + case KotoeriDictionaryType: + dict = new KotoeriDictionary(); + break; + case ProxyDictionaryType: // ¢À + dict = new NullDictionary(); + break; + case GroupingDictionaryType: + dict = new NullDictionary(); + break; + default: + std::cerr << "DictionarySet::createDictionary(): unknown type[" << pref.type << "]" << std::endl; + dict = new NullDictionary(); + break; + } + + // ú» + dict->load(pref.location); + + return dict; +} + +// map L[¶¬ +std::string DictionarySet::generateID(const DictionaryPref& pref) const { + std::stringstream id; + + // «Ì ID 𶬷é + id << pref.type << ":" << pref.location; + + return id.str(); +} + +void DictionarySet::load() { + CFArrayRef arrayRef = (CFArrayRef)CFPreferencesCopyAppValue(CFSTR("DictionaryInfo"), + kCFPreferencesCurrentApplication); + if(arrayRef == NULL) { + return; + } + + // âîñðNA·é + prefs_.clear(); + + // Âl«ðæªÉüêé + DictionaryPref entry; + entry.active = true; + entry.type = SKKDictionaryType; + entry.location = SkkConfig::home() + SKK_USER_DICT_PATH; + prefs_.push_back(entry); + if(dicts_.find(generateID(entry)) == dicts_.end()) { + dicts_[generateID(entry)] = userdict_; + } + + // LøÈ«ðSÄ[h·é + for(CFIndex index = 0; index < CFArrayGetCount(arrayRef); ++ index) { + CFDictionaryRef dictRef = (CFDictionaryRef)CFRetain(CFArrayGetValueAtIndex(arrayRef, index)); + + // DictionaryPref ðìé + entry.active = ((CFBooleanRef)CFDictionaryGetValue(dictRef, CFSTR("active")) == kCFBooleanTrue); + CFNumberGetValue((CFNumberRef)CFDictionaryGetValue(dictRef, CFSTR("type")), kCFNumberIntType, &entry.type); + CFStringRef str = (CFStringRef)CFDictionaryGetValue(dictRef, CFSTR("location")); + if(str) { + char buf[2048]; + CFStringGetCString(str, buf, sizeof(buf), kCFStringEncodingEUC_JP); + entry.location = buf; + } else { + entry.location = ""; + } + + // ì¬ÏÝÌ«ª êÎA澵Ĩ + DictionaryIterator iter = dicts_.find(generateID(entry)); + + // Lø©H + if(entry.active) { + prefs_.push_back(entry); + + // ©Â©çȯêÎAÇÁµÄ¨ + if(iter == dicts_.end()) { + dicts_[generateID(entry)] = createDictionary(entry); + } + } else { + // ì¬ÏÝųøɳ꽫ÍÁ· + if(iter != dicts_.end()) { + delete iter->second; + dicts_.erase(generateID(entry)); + } + } + CFRelease(dictRef); + } + CFRelease(arrayRef); +} + +DictionarySet::DictionarySet() { + // [U[«ð[h·é + userdict_ = new SKKUserDictionary(); + userdict_->load(SkkConfig::home() + SKK_USER_DICT_PATH); +} + +DictionarySet::~DictionarySet() { + terminate(); +} + +DictionarySet& DictionarySet::theInstance() { + static DictionarySet obj; + return obj; +} + +void DictionarySet::initialize() { + // «ð[h·é + load(); +} + +void DictionarySet::terminate() { + struct local { + static void DeleteDictionary(std::pair<std::string, Dictionary*> entry) { + delete entry.second; + entry.second = NULL; + } + }; + + // SÄÌ«ðí·é + std::for_each(dicts_.begin(), dicts_.end(), local::DeleteDictionary); + dicts_.clear(); +} + +CppCFString DictionarySet::skkserv_style_search(const CppCFString& query) { + // skkservX^CÅÌûõðsÓB + // NGÌ`®ÍAu¹ñƤvu¯svÌâ¤ÈàÌBöÉó¶Ít¯È¢B + // vCÌ`®ÍAu/æª/í¬/K/vÌâ¤ÉAçÌ`®»ÌÜÜB³¯êÎó¶ñB + if(query.length() == 0) { + return CppCFString(); + } + + // èï¼ÍLé©H + if(query[0] > 0xff && query[query.length() - 1] >= 'a' && query[query.length() - 1] <= 'z') { + // OkuriganaEntry.kana => OkuriganaEntry + std::map<CppCFString, OkuriganaEntry> cands; + for(DictionaryPrefIterator iter = prefs_.begin(); iter != prefs_.end(); ++ iter) { + // O[v«ÌêAùÉó⪩©ÁÄ¢êÎõðâßé + if(iter->type == GroupingDictionaryType && !cands.empty()) { + break; + } + + Dictionary* dict = dicts_[generateID(*iter)]; + std::vector<OkuriganaEntry> okuriEntries = dict->findOkuriAri(query); + if(okuriEntries.empty()) { + continue; + } + + for(std::vector<OkuriganaEntry>::iterator e = okuriEntries.begin(); e != okuriEntries.end(); ++ e) { + OkuriganaEntry& entry = cands[e->getKana()]; + entry.setKana(e->getKana()); + entry.getCandidates().insert(entry.getCandidates().begin(), + e->getCandidates().begin(), e->getCandidates().end()); + } + } + + // SÄÌGgÉ¢ÄAd¡µÄîéàÌðíµÈªçAv + // Cðg§ÄéB + CppCFString reply; + for(std::map<CppCFString, OkuriganaEntry>::iterator e = cands.begin(); e != cands.end(); ++ e) { + OkuriganaEntry& entry = e->second; + entry.removeRedundantItems(); + if(entry.isWild()) { + reply.append(join('/', entry.getCandidates())).append('/'); + } else { + reply.append('[').append(entry.getKana()).append('/'). + append(join('/', entry.getCandidates())).append("/]/"); + } + } + if(reply.length() > 0) { + reply.insert(0, '/'); + } + return reply; + } else { + // èJ³¢B + std::vector<CppCFString> cands; + + for(DictionaryPrefIterator iter = prefs_.begin(); iter != prefs_.end(); ++ iter) { + // O[v«ÌêAùÉó⪩©ÁÄ¢êÎõðâßé + if(iter->type == GroupingDictionaryType && !cands.empty()) { + break; + } + + Dictionary* dict = dicts_[generateID(*iter)]; + std::vector<CppCFString> result = dict->findOkuriNasi(query); + if(!result.empty()) { + cands.insert(cands.end(), result.begin(), result.end()); + } + } + + // d¡µÄîéàÌðíB + removeRedundantItems(cands); + + if(cands.size() > 0) { + return CppCFString('/').append(join('/', cands)).append('/'); + } else { + return CppCFString(); + } + } +} + +CppCFString DictionarySet::search(const CppCFString& query) { + CppCFString space(" "); + CppCFString nbsp("[20]"); + bool has_okuri = query[0] == '+'; + CppCFString query_str(query.substring(1)); // æªÌ+,-ðÁ·B + + D_PRINTF("QUERY: %s\n",query_str.toCString(kCFStringEncodingEUC_JP)); + + if(has_okuri) { + int pos_space = query_str.indexOf(' '); + CppCFString root = query_str.substring(0,pos_space).replace(nbsp,space); // u+ÈÅr évÈçuÈÅrv + CppCFString okuri = query_str.substring(pos_space+1).replace(nbsp,space); // u+ÈÅr évÈçuév + + std::vector<CppCFString> cand_strictly_matched; + std::vector<CppCFString> cand_unstrictly_matched; + + for(DictionaryPrefIterator iter = prefs_.begin(); iter != prefs_.end(); ++ iter) { + // O[v«ÌêAùÉó⪩©ÁÄ¢êÎõðâßé + if(iter->type == GroupingDictionaryType && + (!cand_strictly_matched.empty() || !cand_unstrictly_matched.empty())) { + break; + } + + Dictionary* dict = dicts_[generateID(*iter)]; + std::vector<OkuriganaEntry> okuriEntries = dict->findOkuriAri(root); + if(okuriEntries.empty()) { + continue; + } + + for(std::vector<OkuriganaEntry>::iterator e = okuriEntries.begin(); e != okuriEntries.end(); ++ e) { + if(e->getKana() == okuri) { + cand_strictly_matched.insert(cand_strictly_matched.end(), + e->getCandidates().begin(), e->getCandidates().end()); + } else { + cand_unstrictly_matched.insert(cand_unstrictly_matched.end(), + e->getCandidates().begin(), e->getCandidates().end()); + } + } + } + + std::vector<CppCFString> candidates = cand_strictly_matched; + candidates.insert(candidates.end(), cand_unstrictly_matched.begin(), cand_unstrictly_matched.end()); + + // candidatesÌd¡ð`FbNBd¡µÄ¢½çãÉ éàÌðíB + removeRedundantItems(candidates); + + // ±Ì_ÅcandidatesÉüÁÄ¢éÌͿ̪¾¯ÈÌÅA + // SÄÌvfÉè¼¼ðt¯éB¯ÉXy[Xð[20]ÉÏ·B + // ߪt¢Ä¢êÎAí·éB(bè) + for(std::vector<CppCFString>::iterator ite = candidates.begin(); ite != candidates.end(); ++ ite) { + const int semicolon_pos = ite->indexOf(';'); + if(semicolon_pos != -1) { + ite->erase(semicolon_pos, ite->length()); + } + ite->append(okuri).replace(space,nbsp); + } + + D_PRINTF("REPLY: %s\n",join(' ',candidates).toCString(kCFStringEncodingEUC_JP)); + return join(' ', candidates); + } else { + std::vector<CppCFString> candidates; + + for(DictionaryPrefIterator iter = prefs_.begin(); iter != prefs_.end(); ++ iter) { + // O[v«ÌêAùÉó⪩©ÁÄ¢êÎõðâßé + if(iter->type == GroupingDictionaryType && !candidates.empty()) { + break; + } + + Dictionary* dict = dicts_[generateID(*iter)]; + std::vector<CppCFString> result = dict->findOkuriNasi(query_str); + if(result.empty()) { + continue; + } + + candidates.insert(candidates.end(), result.begin(), result.end()); + } + + // candidatesÌd¡ð`FbNBd¡µÄ¢½çãÉ éàÌðíB + removeRedundantItems(candidates); + + // candidatesÌSÄÌÚÌXy[Xð[20]ÉÏ·B + // ߪt¢Ä¢êÎAí·éB(bè) + for(std::vector<CppCFString>::iterator ite = candidates.begin(); ite != candidates.end(); ++ ite) { + const int semicolon_pos = ite->indexOf(';'); + if(semicolon_pos != -1) { + ite->erase(semicolon_pos, ite->length()); + } + ite->replace(space,nbsp); + } + + D_PRINTF("REPLY: %s\n",join(' ',candidates).toCString(kCFStringEncodingEUC_JP)); + return join(' ',candidates); + } +} + +void DictionarySet::registerToUserDic(const CppCFString& query) { + CppCFString space(" "); + CppCFString nbsp("[20]"); + + D_PRINTF("REGISTER: %s\n",query.toCString(kCFStringEncodingEUC_JP)); + + // è¼¼ èHu+¨r è v + if(query[0] == '+') { + int pos_first_space = query.indexOf(' '); + int pos_second_space = query.indexOf(' ',pos_first_space+1); + + CppCFString index(query.substring(1,pos_first_space)); + index.replace(nbsp,space); // ¨r + CppCFString okuri(query.substring(pos_first_space+1,pos_second_space)); + okuri.replace(nbsp,space); // è + CppCFString kanji(query.substring(pos_second_space+1)); + kanji.replace(nbsp,space); // + + if(index.length() == 0 || okuri.length() == 0 || kanji.length() == 0) { + std::cerr << "AquaSKK: Invalid registration received; index:" + << index.length() << " okuri:" << okuri.length() + << " kanji:" << kanji.length() << " (len)" << std::endl; + } else { + userdict_->registerOkuriAri(index, okuri, kanji); + } + } else { + // è¼¼³µBu-©È ¼¼v + int pos_space = query.indexOf(' '); + CppCFString index(query.substring(1,pos_space)); + index.replace(nbsp,space); + CppCFString kanji(query.substring(pos_space+1)); + kanji.replace(nbsp,space); + + if(index.length() == 0 || kanji.length() == 0) { + std::cerr << "AquaSKK: Invalid registration received; index:" + << index.length() << " kanji:" << kanji.length() + << " (len)" << std::endl; + } else { + userdict_->registerOkuriNasi(index, kanji); + } + } +} + +void DictionarySet::removeFromUserDic(const CppCFString& query) { + CppCFString space(" "); + CppCFString nbsp("[20]"); + + D_PRINTF("REMOVE: %s\n",query.toCString(kCFStringEncodingEUC_JP)); + + // è¼¼ èHu+¨r è v + if(query[0] == '+') { + int pos_first_space = query.indexOf(' '); + int pos_second_space = query.indexOf(' ',pos_first_space+1); + + CppCFString index(query.substring(1,pos_first_space)); + index.replace(nbsp,space); // ¨r + CppCFString okuri(query.substring(pos_first_space+1,pos_second_space)); + okuri.replace(nbsp,space); // è + CppCFString kanji(query.substring(pos_second_space+1)); + kanji.replace(nbsp,space); // + + if(index.length() == 0 || okuri.length() == 0 || kanji.length() == 0) { + std::cerr << "AquaSKK: Invalid removal received; index:" + << index.length() << " okuri:" << okuri.length() + << " kanji:" << kanji.length() << " (len)" << std::endl; + } else { + userdict_->removeOkuriAri(index, kanji); + } + } else { + // è¼¼³µBu-©È ¼¼v + int pos_space = query.indexOf(' '); + CppCFString index(query.substring(1,pos_space)); + index.replace(nbsp,space); + CppCFString kanji(query.substring(pos_space+1)); + kanji.replace(nbsp,space); + + if(index.length() == 0 || kanji.length() == 0) { + std::cerr << "AquaSKK: Invalid removal received; index:" + << index.length() << " kanji:" << kanji.length() + << " (len)" << std::endl; + } else { + userdict_->removeOkuriNasi(index, kanji); + } + } +} + +CppCFString DictionarySet::searchCompletions(const CppCFString& query) { + CppCFString space(" "); + CppCFString nbsp("[20]"); + + D_PRINTF("COMPLETE: %s\n", query.toCString(kCFStringEncodingEUC_JP)); + + CppCFString head = query.replaceClone(nbsp, space); + std::vector<CppCFString> result = userdict_->findCompletions(head); + + D_PRINTF("REPLY: %s\n", + join(' ',result).toCString(kCFStringEncodingEUC_JP)); + + return join(' ', result); +} + +static void removeRedundantItems(std::vector<CppCFString>& candidates) { + // ±ÌÍcandidates̪¦éÙÇÔª©©èÜ·B + // dûȢ̾뤯ÇB + int size = candidates.size(); + for(int i = 0; i < size; ++ i) { + CppCFString& cand_i = candidates[i]; + bool is_redundant = false; + for(int j = 0; j < i; ++ j) { + if(cand_i == candidates[j]) { + is_redundant = true; + break; + } + } + + if(is_redundant) { + candidates.erase(candidates.begin() + i); + -- i; // êÂÁµ½ÌÅA»Ìãɱڪê¸êéB + -- size; // êÂÁµ½ÌÅB + } + } +} Index: AquaSKK/DictionarySet.h diff -u /dev/null AquaSKK/DictionarySet.h:1.1.2.1 --- /dev/null Sat Feb 18 02:20:38 2006 +++ AquaSKK/DictionarySet.h Sat Feb 18 02:20:38 2006 @@ -0,0 +1,79 @@ +/* -*- c++ -*- + $Id: DictionarySet.h,v 1.1.2.1 2006/02/17 17:20:38 t-suwa Exp $ + + MacOS X implementation of the SKK input method. + + Copyright (C) 2002 phonohawk + Copyright (C) 2005-2006 Tomotaka SUWA <t.suw****@mac*****> + + 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 + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#pragma once + +#include <string> +#include <vector> +#include <map> + +class CppCFString; +class Dictionary; +class UserDictionary; + +class DictionarySet { + // «ÌíÞ + enum DictionaryTypes { + SKKDictionaryType = 10, + SKKAutoUpdateDictionaryType = 11, + KotoeriDictionaryType = 20, + ProxyDictionaryType = 30, + GroupingDictionaryType = 90, + }; + + // «ÌÝè + struct DictionaryPref { + bool active; + int type; + std::string location; + }; + typedef std::vector<DictionaryPref> DictionaryPrefContainer; + typedef DictionaryPrefContainer::iterator DictionaryPrefIterator; + typedef std::map<std::string, Dictionary*> DictionaryContainer; + typedef DictionaryContainer::iterator DictionaryIterator; + + // [U[« + UserDictionary* userdict_; + + DictionaryPrefContainer prefs_; + DictionaryContainer dicts_; + + Dictionary* createDictionary(const DictionaryPref& pref) const; + std::string generateID(const DictionaryPref& pref) const; + void load(); + + DictionarySet(); + ~DictionarySet(); + +public: + static DictionarySet& theInstance(); + + void initialize(); + void terminate(); + + CppCFString skkserv_style_search(const CppCFString& query); + CppCFString search(const CppCFString& query); + void registerToUserDic(const CppCFString& query); + void removeFromUserDic(const CppCFString& query); + CppCFString searchCompletions(const CppCFString& query); +}; Index: AquaSKK/Foundation.mm diff -u AquaSKK/Foundation.mm:1.3.2.2 AquaSKK/Foundation.mm:1.3 --- AquaSKK/Foundation.mm:1.3.2.2 Wed Feb 15 00:12:44 2006 +++ AquaSKK/Foundation.mm Wed Nov 9 00:02:24 2005 @@ -1,10 +1,10 @@ /* -*- objc -*- - $Id: Foundation.mm,v 1.3.2.2 2006/02/14 15:12:44 t-suwa Exp $ + $Id: Foundation.mm,v 1.3 2005/11/08 15:02:24 t-suwa Exp $ MacOS X implementation of the SKK input method. Copyright (C) 2002 phonohawk - Copyright (C) 2005-2006 Tomotaka SUWA <t.suw****@mac*****> + Copyright (C) 2005 Tomotaka SUWA <t.suw****@mac*****> 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 @@ -21,22 +21,37 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <AppKit/AppKit.h> -#include "Foundation.h" -#include "PreferencesController.h" -#include "SKKServer.h" +#import <AppKit/AppKit.h> +#import "Foundation.h" +#import "PreferencesController.h" + +#include <Carbon/Carbon.h> +#include <vector> #include "BIMClientServer.h" +#include "CppCFString.h" +#include "CppCFData.h" +#include "PrivateRunLoop.h" +#include "CppMessagePortServer.h" #include "ServerMessageReceiver.h" +#include "SKKServer.h" +#include "net/Socket.h" #include "Skkserv.h" @implementation Foundation - (void)applicationDidFinishLaunching:(NSNotification*)aNotification { - // vt@Xðæ¾ + // ±Æ¦è«ÌpXðæ¾ PreferencesController* pref = [PreferencesController sharedController]; + std::vector<CppCFString> vec; + for(unsigned i = 0 ; i < [[pref path] count] ; ++ i) { + vec.push_back((CFStringRef)[[pref path] objectAtIndex:i]); + } // «T[o[ðN®·é - SKKServer::sharedServer(); + SKKServer::sharedServer([[pref getPathToMainDic] cString], + [[pref getPathToSubDic] cString], + [[pref getPathToUserDic] cString], + vec); // bZ[WnhðN®·é ServerMessageReceiver::start(kAquaSKKServerRunLoopMode); Index: AquaSKK/KotoeriDictionary.cpp diff -u /dev/null AquaSKK/KotoeriDictionary.cpp:1.1.2.1 --- /dev/null Sat Feb 18 02:20:38 2006 +++ AquaSKK/KotoeriDictionary.cpp Sat Feb 18 02:20:38 2006 @@ -0,0 +1,179 @@ +/* + $Id: KotoeriDictionary.cpp,v 1.1.2.1 2006/02/17 17:20:38 t-suwa Exp $ + + MacOS X implementation of the SKK input method. + + Copyright (C) 2002 phonohawk + Copyright (C) 2005-2006 Tomotaka SUWA <t.suw****@mac*****> + + 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 + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/* + Directory ManegerÎ@2002.09.25 Shin_ichi Abe. +*/ + +#include <Carbon/Carbon.h> +#include <iostream> +#include <vector> +#include <algorithm> +#include "CppCFData.h" +#include "CppCFString.h" +#include "OkuriganaEntry.h" +#include "KotoeriDictionary.h" + +KotoeriDictionary::KotoeriDictionary() : path_(0), isRegistered_(false), id_(0) { + // empty +} + +KotoeriDictionary::~KotoeriDictionary() { + if(isRegistered_) { + DCMUnregisterDictionary(id_); + } + + if(path_) { + CFRelease(path_); + } +} + +void KotoeriDictionary::load(const std::string& path) { + path_ = CFStringCreateWithCString(kCFAllocatorDefault, path.c_str(), kCFStringEncodingEUC_JP); + if(!path_) { + std::cerr << "KotoeriDictionary: CFStringCreateCopy() failed" << std::endl; + return; + } + + FSSpec spec; + FSRef fileRef; + CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path_, kCFURLPOSIXPathStyle, false); + OSErr err = !noErr; + if(CFURLGetFSRef(url, &fileRef)) { + err = FSGetCatalogInfo(&fileRef, kFSCatInfoNone, NULL, NULL, &spec, NULL); + } + if(url) CFRelease(url); + if(err != noErr) { + return; + } + + if(DCMGetDictionaryIDFromFile(&spec, &id_) != noErr) { + std::cerr << "DCMGetDictionaryIDFromFile() failed" << std::endl; + if(DCMRegisterDictionaryFile(&spec, &id_) != noErr) { + std::cerr << "DCMRegisterDictionaryFile() failed" << std::endl; + return; + } + isRegistered_ = true; + } + + char buf[1024]; + CFStringGetCString(path_, buf, sizeof(buf), kCFStringEncodingUTF8); + std::cerr << "Kotoeri Dictionary(" << buf << ")" << std::endl + << " okuri-ari: 0 entries." << std::endl + << " okuri-nasi: " << countOkuriNasi() << " entries." + << std::endl << std::endl; +} + +int KotoeriDictionary::countOkuriAri() { + return 0; +} + +int KotoeriDictionary::countOkuriNasi() { + ItemCount numItems; + if(DCMCountRecord(id_, &numItems) == noErr) { + return numItems; + } + + return 0; +} + +std::vector<OkuriganaEntry> KotoeriDictionary::findOkuriAri(const CppCFString& str) { + // ±Æ¦è«ÉÍuè èvͶݵȢ + return std::vector<OkuriganaEntry>(); +} + +std::vector<CppCFString> KotoeriDictionary::findOkuriNasi(const CppCFString& str) { + OSStatus status; + std::vector<CppCFString> result; + + DCMFoundRecordIterator iterator; + if(!find(str.getString(), &iterator)) { + return result; + } + + while(true) { + ByteCount keySize; + char foundKeyStr[kMaxKanjiLengthInAppleJapaneseDictionary]; + DCMUniqueID uniqueID; + AERecord dataList; + + // Get one record from result list + status = DCMIterateFoundRecord(iterator, // found result + kMaxKanjiLengthInAppleJapaneseDictionary, // key buffer size + &keySize, // actual found key size + foundKeyStr, // found key data + &uniqueID, // j[NID + &dataList); // AERecordf[^ + + if(status != noErr) break; + + DescType actualType; + char dataBuffer[kMaxKanjiLengthInAppleJapaneseDictionary]; + Size actualSize; + + // Get one data from AERecord + status = AEGetKeyPtr(&dataList, + kDCMJapaneseHyokiTag, + 'utxt', + &actualType, + dataBuffer, + kMaxKanjiLengthInAppleJapaneseDictionary, + &actualSize); + + // Dispose data AERecord + AEDisposeDesc(&dataList); + + if(status != noErr) break; + + // ÊÉÇÁ·é + result.push_back(CppCFData(dataBuffer, actualSize).getData()); + } + DCMDisposeRecordIterator(iterator); + + return result; +} + +bool KotoeriDictionary::find(const CFStringRef key, DCMFoundRecordIterator* iterator) { + DCMDictionaryRef ref; + if(DCMOpenDictionary(id_, 0, NULL, &ref) != noErr) { + std::cerr << "DCMOpenDictionary() failed" << std::endl; + return false; + } + + // R[hðõ + OSStatus status; + DCMFieldTag dataFieldTagList[] = { kDCMJapaneseHyokiTag }; + ByteCount length = CFStringGetLength(key) * sizeof(UniChar); + status = DCMFindRecords(ref, // Dictionary reference + kDCMJapaneseYomiTag, // key field tag + length, // key data length + CFStringGetCharactersPtr(key), // key data + kDCMFindMethodExactMatch, // find method + 1, // number of data field + dataFieldTagList, // data field tag list + 0, 0, // search all records + iterator); // found result + + DCMCloseDictionary(ref); + + return (status == noErr); +} Index: AquaSKK/KotoeriDictionary.h diff -u /dev/null AquaSKK/KotoeriDictionary.h:1.1.2.1 --- /dev/null Sat Feb 18 02:20:38 2006 +++ AquaSKK/KotoeriDictionary.h Sat Feb 18 02:20:38 2006 @@ -0,0 +1,52 @@ +/* + $Id: KotoeriDictionary.h,v 1.1.2.1 2006/02/17 17:20:38 t-suwa Exp $ + + MacOS X implementation of the SKK input method. + + Copyright (C) 2002 phonohawk + Copyright (C) 2005-2006 Tomotaka SUWA <t.suw****@mac*****> + + 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 + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/* + Directory ManegerÎ@2002.09.25 Shin_ichi Abe. +*/ + +#pragma once + +#include "Dictionary.h" + +class OkuriganaEntry; +class CppCFString; + +class KotoeriDictionary: public Dictionary { + CFStringRef path_; + bool isRegistered_; + DCMDictionaryID id_; + + bool find(const CFStringRef key, DCMFoundRecordIterator* iterator); + +public: + KotoeriDictionary(); + virtual ~KotoeriDictionary(); + + virtual void load(const std::string& path); + + virtual int countOkuriAri(); + virtual int countOkuriNasi(); + + virtual std::vector<OkuriganaEntry> findOkuriAri(const CppCFString& str); + virtual std::vector<CppCFString> findOkuriNasi(const CppCFString& str); +}; Index: AquaSKK/PreferencesController.h diff -u AquaSKK/PreferencesController.h:1.6.2.3 AquaSKK/PreferencesController.h:1.6.2.4 --- AquaSKK/PreferencesController.h:1.6.2.3 Wed Feb 15 00:12:44 2006 +++ AquaSKK/PreferencesController.h Sat Feb 18 02:20:38 2006 @@ -1,5 +1,5 @@ /* -*- objc -*- - $Id: PreferencesController.h,v 1.6.2.3 2006/02/14 15:12:44 t-suwa Exp $ + $Id: PreferencesController.h,v 1.6.2.4 2006/02/17 17:20:38 t-suwa Exp $ MacOS X implementation of the SKK input method. @@ -71,7 +71,7 @@ - (IBAction)saveUserDefault:(id)sender; - (BOOL)isSkkservEnabled; -- (int)skkservPort; +- (unsigned short)skkservPort; - (BOOL)isSkkservLocalOnly; @end Index: AquaSKK/PreferencesController.mm diff -u AquaSKK/PreferencesController.mm:1.6.2.5 AquaSKK/PreferencesController.mm:1.6.2.6 --- AquaSKK/PreferencesController.mm:1.6.2.5 Wed Feb 15 00:12:44 2006 +++ AquaSKK/PreferencesController.mm Sat Feb 18 02:20:38 2006 @@ -1,5 +1,5 @@ /* -*- objc -*- - $Id: PreferencesController.mm,v 1.6.2.5 2006/02/14 15:12:44 t-suwa Exp $ + $Id: PreferencesController.mm,v 1.6.2.6 2006/02/17 17:20:38 t-suwa Exp $ MacOS X implementation of the SKK input method. @@ -21,18 +21,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#import <AppKit/AppKit.h> -#import "PreferencesController.h" +#include <AppKit/AppKit.h> +#include "PreferencesController.h" -#include <Carbon/Carbon.h> -#include <vector> #include "BIMClientServer.h" #include "CppCFString.h" #include "CppCFData.h" -#include "DMDictionary.h" -#include "SKKDictionary.h" -#include "SKKServer.h" -#include "Skkserv.h" +#include "DictionarySet.h" +#include "skkserv.h" #include "ClientConnectionFactory.h" // [U[ftHgp @@ -294,31 +290,16 @@ } - (BOOL)windowShouldClose:(NSNotification *)aNotification { - NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; - - // «T[o[ðÄú»·é - SKKServer::sharedServer().reload(); + // ÄxA«T[o[ðú»·é + DictionarySet::theInstance().initialize(); - Skkserv& skkserv = Skkserv::sharedServer(); - skkserv.setLocalOnly([skkserv_local_only state] == YES ? true : false); - if(skkserv.isRunning()) { - if([skkserv_enabled state] == NO) { - // â~ - skkserv.stop(); - } else { - if([skkserv_port intValue] != skkserv.port()) { - // |[gÌX - skkserv.stop(); - skkserv.start([skkserv_port intValue]); - } - } - } else { - if([skkserv_enabled state] == YES) { - // Jn - skkserv.start([skkserv_port intValue]); - } + // skkserv G~ [VÌÄN® + skkserv& skkserv = skkserv::theInstance(); + skkserv.stop(); + if([self isSkkservEnabled]) { + skkserv.start([self skkservPort], [self isSkkservLocalOnly]); } - + [fontPanel close]; [self saveUserDefault:self]; @@ -330,7 +311,7 @@ return [skkserv_enabled state]; } -- (int)skkservPort { +- (unsigned short)skkservPort { return [skkserv_port intValue]; } Index: AquaSKK/SKKDictionary.cpp diff -u AquaSKK/SKKDictionary.cpp:1.6.2.1 AquaSKK/SKKDictionary.cpp:1.6.2.2 --- AquaSKK/SKKDictionary.cpp:1.6.2.1 Sun Jan 8 16:15:30 2006 +++ AquaSKK/SKKDictionary.cpp Sat Feb 18 02:20:38 2006 @@ -1,5 +1,5 @@ /* - $Id: SKKDictionary.cpp,v 1.6.2.1 2006/01/08 07:15:30 t-suwa Exp $ + $Id: SKKDictionary.cpp,v 1.6.2.2 2006/02/17 17:20:38 t-suwa Exp $ MacOS X implementation of the SKK input method. @@ -150,14 +150,56 @@ #pragma mark --- SKKDictionary --- -SKKDictionary::SKKDictionary(const std::string& path) : path_(path) { - load(); +SKKDictionary::SKKDictionary() { + // empty } SKKDictionary::~SKKDictionary() { // empty } +void SKKDictionary::load(const std::string& path) { + std::string line; + std::string index; + std::string entry; + std::ifstream dic; + + path_ = path; + + if(!skkdic::OpenAndSeek(path_, dic)) { + return; + } + + while(1) { + dic >> index; + if(dic.eof()) break; + dic.ignore(1, ' '); + std::getline(dic, line); + if(skkdic::OkuriNasiMark.find(line) != std::string::npos) break; + + // èȵGgÍ~Å\[g³êÄ¢é͸ + okuriAri_.push_front(SKKPair(index, line)); + } + + while(1) { + dic >> index; + if(dic.eof()) break; + dic.ignore(1, ' '); + std::getline(dic, line); + + // è èGg͸Å\[g³êÄ¢é͸ + okuriNasi_.push_back(SKKPair(index, line)); + } + + // Ggð\[g·é + std::sort(okuriAri_.begin(), okuriAri_.end(), skkdic::EntryCompare()); + std::sort(okuriNasi_.begin(), okuriNasi_.end(), skkdic::EntryCompare()); + + std::cerr << "SKK Dictionary(" << path_ << ")" << std::endl + << " okuri-ari: " << countOkuriAri() << " entries." << std::endl + << " okuri-nasi: " << countOkuriNasi() << " entries." << std::endl << std::endl; +} + int SKKDictionary::countOkuriAri() { return okuriAri_.size(); } @@ -192,21 +234,25 @@ return skkdic::ConvertOkuriNasi(SKKEntry::ParseOkuriNasi(i->first, i->second)); } -void SKKDictionary::changeDictionaryFile(const std::string& path) { - EntryContainer().swap(okuriAri_); - EntryContainer().swap(okuriNasi_); +#pragma mark --- SKKUserDictionary --- - path_ = path; +SKKUserDictionary::SKKUserDictionary() { + // empty +} - load(); +SKKUserDictionary::~SKKUserDictionary() { + // §IÉ«ðÛ¶·é + save(true); } -void SKKDictionary::load() { +void SKKUserDictionary::load(const std::string& path) { std::string line; std::string index; std::string entry; std::ifstream dic; + path_ = path; + if(!skkdic::OpenAndSeek(path_, dic)) { return; } @@ -217,9 +263,7 @@ dic.ignore(1, ' '); std::getline(dic, line); if(skkdic::OkuriNasiMark.find(line) != std::string::npos) break; - - // èȵGgÍ~Å\[g³êÄ¢é͸ - okuriAri_.push_front(SKKPair(index, line)); + okuriAri_.push_back(SKKPair(index, line)); } while(1) { @@ -227,31 +271,14 @@ if(dic.eof()) break; dic.ignore(1, ' '); std::getline(dic, line); - - // è èGg͸Å\[g³êÄ¢é͸ okuriNasi_.push_back(SKKPair(index, line)); } - // Ggð\[g·é - std::sort(okuriAri_.begin(), okuriAri_.end(), skkdic::EntryCompare()); - std::sort(okuriNasi_.begin(), okuriNasi_.end(), skkdic::EntryCompare()); - - std::cerr << "SKK Dictionary(" << path_ << ")" << std::endl + std::cerr << "SKK User Dictionary(" << path_ << ")" << std::endl << " okuri-ari: " << countOkuriAri() << " entries." << std::endl << " okuri-nasi: " << countOkuriNasi() << " entries." << std::endl << std::endl; } -#pragma mark --- SKKUserDictionary --- - -SKKUserDictionary::SKKUserDictionary(const std::string& path) : path_(path) { - load(); -} - -SKKUserDictionary::~SKKUserDictionary() { - // §IÉ«ðÛ¶·é - save(true); -} - int SKKUserDictionary::countOkuriAri() { return okuriAri_.size(); } @@ -380,38 +407,6 @@ // ------------------------------------------------------------------ -void SKKUserDictionary::load() { - std::string line; - std::string index; - std::string entry; - std::ifstream dic; - - if(!skkdic::OpenAndSeek(path_, dic)) { - return; - } - - while(1) { - dic >> index; - if(dic.eof()) break; - dic.ignore(1, ' '); - std::getline(dic, line); - if(skkdic::OkuriNasiMark.find(line) != std::string::npos) break; - okuriAri_.push_back(SKKPair(index, line)); - } - - while(1) { - dic >> index; - if(dic.eof()) break; - dic.ignore(1, ' '); - std::getline(dic, line); - okuriNasi_.push_back(SKKPair(index, line)); - } - - std::cerr << "SKK User Dictionary(" << path_ << ")" << std::endl - << " okuri-ari: " << countOkuriAri() << " entries." << std::endl - << " okuri-nasi: " << countOkuriNasi() << " entries." << std::endl << std::endl; -} - void SKKUserDictionary::save(bool force) { static int updateCount = 0; static std::time_t startOfUpdate = std::time(0); Index: AquaSKK/SKKDictionary.h diff -u AquaSKK/SKKDictionary.h:1.5.2.1 AquaSKK/SKKDictionary.h:1.5.2.2 --- AquaSKK/SKKDictionary.h:1.5.2.1 Sun Jan 8 16:15:30 2006 +++ AquaSKK/SKKDictionary.h Sat Feb 18 02:20:38 2006 @@ -1,5 +1,5 @@ /* - $Id: SKKDictionary.h,v 1.5.2.1 2006/01/08 07:15:30 t-suwa Exp $ + $Id: SKKDictionary.h,v 1.5.2.2 2006/02/17 17:20:38 t-suwa Exp $ MacOS X implementation of the SKK input method. @@ -23,9 +23,6 @@ #pragma once -#include <iostream> -#include <string> -#include <vector> #include <deque> #include "Dictionary.h" @@ -45,12 +42,12 @@ EntryContainer okuriAri_; EntryContainer okuriNasi_; - void load(); - public: - SKKDictionary(const std::string& path); + SKKDictionary(); virtual ~SKKDictionary(); + virtual void load(const std::string& path); + virtual int countOkuriAri(); virtual int countOkuriNasi(); @@ -66,13 +63,14 @@ EntryContainer okuriAri_; EntryContainer okuriNasi_; - void load(); void save(bool force = false); public: - SKKUserDictionary(const std::string& path); + SKKUserDictionary(); virtual ~SKKUserDictionary(); + virtual void load(const std::string& path); + virtual int countOkuriAri(); virtual int countOkuriNasi(); Index: AquaSKK/SKKServer.cpp diff -u AquaSKK/SKKServer.cpp:1.4.2.2 AquaSKK/SKKServer.cpp:1.4 --- AquaSKK/SKKServer.cpp:1.4.2.2 Wed Feb 15 00:12:44 2006 +++ AquaSKK/SKKServer.cpp Wed Nov 9 00:02:24 2005 @@ -1,10 +1,10 @@ /* - $Id: SKKServer.cpp,v 1.4.2.2 2006/02/14 15:12:44 t-suwa Exp $ + $Id: SKKServer.cpp,v 1.4 2005/11/08 15:02:24 t-suwa Exp $ MacOS X implementation of the SKK input method. Copyright (C) 2002-2004 phonohawk - Copyright (C) 2005-2006 Tomotaka SUWA <t.suw****@mac*****> + Copyright (C) 2005 Tomotaka SUWA <t.suw****@mac*****> 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 @@ -21,15 +21,17 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <Carbon/Carbon.h> #include <iostream> -#include <sstream> +#include <string> +#include <vector> +#include <map> #include "CppCFString.h" #include "OkuriganaEntry.h" #include "Dictionary.h" -#include "SKKDictionary.h" #include "DMDictionary.h" +#include "SKKDictionary.h" #include "SKKServer.h" -#include "SkkConfig.h" #if 0 # define D_PRINTF printf @@ -37,160 +39,69 @@ # define D_PRINTF if(0)printf #endif -// èÈÇ -const char* SKK_USER_DICT_PATH = "/Library/AquaSKK/skk-user-dic"; - -// [eBeB static void removeRedundantItems(std::vector<CppCFString>& candidates); -// Null « -class NullDictionary: public Dictionary { -public: - NullDictionary(const std::string& location) { - // empty - } - virtual ~NullDictionary() { - // empty - } - virtual int countOkuriAri() { - return 0; - } - virtual int countOkuriNasi() { - return 0; - } - virtual std::vector<OkuriganaEntry> findOkuriAri(const CppCFString& query) { - return std::vector<OkuriganaEntry>(); - } - virtual std::vector<CppCFString> findOkuriNasi(const CppCFString& query) { - return std::vector<CppCFString>(); - } -}; - -// t@Ng\bh -Dictionary* SKKServer::createDictionary(const DictionaryPref& pref) const { - switch(pref.type) { - case SKKDictionaryType: - return new SKKDictionary(pref.location); - break; - case SKKAutoUpdateDictionaryType: - return new NullDictionary(pref.location); - break; - case KotoeriDictionaryType: - return new KotoeriDictionary(pref.location); - break; - case ProxyDictionaryType: - return new NullDictionary(pref.location); - break; - case GroupingDictionaryType: - return new NullDictionary(pref.location); - break; - default: - std::cerr << "SKKServer::createDictionary(): unknown type[" << pref.type << "]" << std::endl; - break; - } - - return new NullDictionary(pref.location); -} - -// map L[¶¬ -std::string SKKServer::generateID(const DictionaryPref& pref) const { - std::stringstream id; - - // «Ì ID 𶬷é - id << pref.type << ":" << pref.location; - - return id.str(); -} +static SKKServer* _shared_instance = NULL; -void SKKServer::load() { - CFArrayRef arrayRef = (CFArrayRef)CFPreferencesCopyAppValue(CFSTR("DictionaryInfo"), - kCFPreferencesCurrentApplication); - if(arrayRef == NULL) { - return; - } - - // âîñðNA·é - prefs_.clear(); - - // Âl«ðæªÉüêé - DictionaryPref entry; - entry.active = true; - entry.type = SKKDictionaryType; - entry.location = SkkConfig::home() + SKK_USER_DICT_PATH; - prefs_.push_back(entry); - if(dicts_.find(generateID(entry)) == dicts_.end()) { - dicts_[generateID(entry)] = userdict_; - } - - // LøÈ«ðSÄ[h·é - for(CFIndex index = 0; index < CFArrayGetCount(arrayRef); ++ index) { - CFDictionaryRef dictRef = (CFDictionaryRef)CFRetain(CFArrayGetValueAtIndex(arrayRef, index)); - - // DictionaryPref ðìé - entry.active = ((CFBooleanRef)CFDictionaryGetValue(dictRef, CFSTR("active")) == kCFBooleanTrue); - CFNumberGetValue((CFNumberRef)CFDictionaryGetValue(dictRef, CFSTR("type")), kCFNumberIntType, &entry.type); - CFStringRef str = (CFStringRef)CFDictionaryGetValue(dictRef, CFSTR("location")); - if(str) { - char buf[2048]; - CFStringGetCString(str, buf, sizeof(buf), kCFStringEncodingEUC_JP); - entry.location = buf; - } else { - entry.location = ""; - } - - // ì¬ÏÝÌ«ª êÎA澵Ĩ - DictionaryIterator iter = dicts_.find(generateID(entry)); - - // Lø©H - if(entry.active) { - prefs_.push_back(entry); - - // ©Â©çȯêÎAÇÁµÄ¨ - if(iter == dicts_.end()) { - dicts_[generateID(entry)] = createDictionary(entry); - } - } else { - // ì¬ÏÝųøɳ꽫ÍÁ· - if(iter != dicts_.end()) { - delete iter->second; - dicts_.erase(generateID(entry)); - } - } - CFRelease(dictRef); - } - CFRelease(arrayRef); +SKKServer& SKKServer::sharedServer() { + return *_shared_instance; } -SKKServer::SKKServer() { - userdict_ = new SKKUserDictionary(SkkConfig::home() + SKK_USER_DICT_PATH); - load(); +SKKServer& +SKKServer::sharedServer(const std::string& base_dic_file, + const std::string& sub_dic_file, + const std::string& user_dic_file, + const std::vector<CppCFString>& kotoeri_dic_file) { + if(_shared_instance == NULL) { + _shared_instance = new SKKServer(base_dic_file, sub_dic_file, + user_dic_file, kotoeri_dic_file); + } + + return *_shared_instance; +} + +SKKServer::SKKServer(const std::string& base_dic_file, + const std::string& sub_dic_file, + const std::string& user_dic_file, + const std::vector<CppCFString>& kotoeri_dic_file) { + base_dic = new SKKDictionary(base_dic_file); + sub_dic = new SKKDictionary(sub_dic_file); + user_dic = new SKKUserDictionary(user_dic_file); + kotoeri_dic = new DMDictionary(kotoeri_dic_file); + + all_dics.push_back(user_dic); + all_dics.push_back(sub_dic); + all_dics.push_back(base_dic); + all_dics.push_back(kotoeri_dic); } SKKServer::~SKKServer() { terminate(); } -SKKServer& SKKServer::sharedServer() { - static SKKServer obj; - return obj; -} - -void SKKServer::reload() { - // «ð[hµ¼· - load(); -} - void SKKServer::terminate() { struct local { - static void DeleteDictionary(std::pair<std::string, Dictionary*> entry) { - delete entry.second; - entry.second = NULL; + static void DeleteDictionary(Dictionary* ptr) { + delete ptr; + ptr = NULL; } }; // SÄÌ«ðí·é - std::for_each(dicts_.begin(), dicts_.end(), local::DeleteDictionary); - dicts_.clear(); + std::for_each(all_dics.begin(), all_dics.end(), local::DeleteDictionary); + all_dics.clear(); +} + +SKKDictionary& SKKServer::getBaseDic() { + return *dynamic_cast<SKKDictionary*>(base_dic); +} + +SKKDictionary& SKKServer::getSubDic() { + return *dynamic_cast<SKKDictionary*>(sub_dic); +} + +DMDictionary& SKKServer::getKotoeriDic() { + return *dynamic_cast<DMDictionary*>(kotoeri_dic); } CppCFString SKKServer::skkserv_style_search(const CppCFString& query) { @@ -202,33 +113,34 @@ } // èï¼ÍLé©H - if(query[0] > 0xff && query[query.length() - 1] >= 'a' && query[query.length() - 1] <= 'z') { + if(query[0] > 0xff && + query[query.length()-1] >= 'a' && query[query.length()-1] <= 'z') { // OkuriganaEntry.kana => OkuriganaEntry std::map<CppCFString, OkuriganaEntry> cands; - for(DictionaryPrefIterator iter = prefs_.begin(); iter != prefs_.end(); ++ iter) { - // O[v«ÌêAùÉó⪩©ÁÄ¢êÎõðâßé - if(iter->type == GroupingDictionaryType && !cands.empty()) { - break; - } + for(std::vector<Dictionary*>::const_iterator dic = all_dics.begin(); + dic != all_dics.end(); ++ dic) { - Dictionary* dict = dicts_[generateID(*iter)]; - std::vector<OkuriganaEntry> okuriEntries = dict->findOkuriAri(query); - if(okuriEntries.empty()) { + std::vector<OkuriganaEntry> vec_okuri = (*dic)->findOkuriAri(query); + if(vec_okuri.empty()) { continue; } - for(std::vector<OkuriganaEntry>::iterator e = okuriEntries.begin(); e != okuriEntries.end(); ++ e) { + for(std::vector<OkuriganaEntry>::iterator e = vec_okuri.begin(); + e != vec_okuri.end(); ++ e) { OkuriganaEntry& entry = cands[e->getKana()]; entry.setKana(e->getKana()); - entry.getCandidates().insert(entry.getCandidates().begin(), - e->getCandidates().begin(), e->getCandidates().end()); + entry.getCandidates().insert( + entry.getCandidates().begin(), + e->getCandidates().begin(), + e->getCandidates().end()); } } // SÄÌGgÉ¢ÄAd¡µÄîéàÌðíµÈªçAv // Cðg§ÄéB CppCFString reply; - for(std::map<CppCFString, OkuriganaEntry>::iterator e = cands.begin(); e != cands.end(); ++ e) { + for(std::map<CppCFString, OkuriganaEntry>::iterator e = cands.begin(); + e != cands.end(); ++ e) { OkuriganaEntry& entry = e->second; entry.removeRedundantItems(); if(entry.isWild()) { @@ -246,16 +158,14 @@ // èJ³¢B std::vector<CppCFString> cands; - for(DictionaryPrefIterator iter = prefs_.begin(); iter != prefs_.end(); ++ iter) { - // O[v«ÌêAùÉó⪩©ÁÄ¢êÎõðâßé - if(iter->type == GroupingDictionaryType && !cands.empty()) { - break; - } + for(std::vector<Dictionary*>::const_iterator ite = all_dics.begin(); + ite != all_dics.end(); ++ ite) { - Dictionary* dict = dicts_[generateID(*iter)]; - std::vector<CppCFString> result = dict->findOkuriNasi(query); - if(!result.empty()) { - cands.insert(cands.end(), result.begin(), result.end()); + std::vector<CppCFString> cand_for_one = (*ite)->findOkuriNasi(query); + if(cand_for_one.size() > 0) { + cands.insert(cands.end(), + cand_for_one.begin(), + cand_for_one.end()); } } @@ -285,33 +195,36 @@ std::vector<CppCFString> cand_strictly_matched; std::vector<CppCFString> cand_unstrictly_matched; - - for(DictionaryPrefIterator iter = prefs_.begin(); iter != prefs_.end(); ++ iter) { - // O[v«ÌêAùÉó⪩©ÁÄ¢êÎõðâßé - if(iter->type == GroupingDictionaryType && - (!cand_strictly_matched.empty() || !cand_unstrictly_matched.empty())) { - break; - } - - Dictionary* dict = dicts_[generateID(*iter)]; - std::vector<OkuriganaEntry> okuriEntries = dict->findOkuriAri(root); - if(okuriEntries.empty()) { - continue; - } - - for(std::vector<OkuriganaEntry>::iterator e = okuriEntries.begin(); e != okuriEntries.end(); ++ e) { - if(e->getKana() == okuri) { - cand_strictly_matched.insert(cand_strictly_matched.end(), - e->getCandidates().begin(), e->getCandidates().end()); + for(std::vector<Dictionary*>::const_iterator dic = all_dics.begin(); + dic != all_dics.end(); ++ dic) { + std::vector<OkuriganaEntry> vec_okuri = (*dic)->findOkuriAri(root); + if(vec_okuri.empty()) continue; + + for(std::vector<OkuriganaEntry>::const_iterator + okuri_entry = vec_okuri.begin(); + okuri_entry != vec_okuri.end(); ++ okuri_entry) { + // ±ÌOkuriganaEntryÌ©oµÆokuriªêvµÄ¢½ç + // cand_strictly_matchedÉüêAêvµÄ¢È¯êÎ + // cand_unstrictly_matchedÉüêéB + if(okuri_entry->getKana() == okuri) { + cand_strictly_matched.insert( + cand_strictly_matched.end(), + okuri_entry->getCandidates().begin(), + okuri_entry->getCandidates().end()); } else { - cand_unstrictly_matched.insert(cand_unstrictly_matched.end(), - e->getCandidates().begin(), e->getCandidates().end()); + cand_unstrictly_matched.insert( + cand_unstrictly_matched.end(), + okuri_entry->getCandidates().begin(), + okuri_entry->getCandidates().end()); } } } std::vector<CppCFString> candidates = cand_strictly_matched; - candidates.insert(candidates.end(), cand_unstrictly_matched.begin(), cand_unstrictly_matched.end()); + candidates.insert( + candidates.end(), + cand_unstrictly_matched.begin(), + cand_unstrictly_matched.end()); // candidatesÌd¡ð`FbNBd¡µÄ¢½çãÉ éàÌðíB removeRedundantItems(candidates); @@ -319,7 +232,8 @@ // ±Ì_ÅcandidatesÉüÁÄ¢éÌͿ̪¾¯ÈÌÅA // SÄÌvfÉè¼¼ðt¯éB¯ÉXy[Xð[20]ÉÏ·B // ߪt¢Ä¢êÎAí·éB(bè) - for(std::vector<CppCFString>::iterator ite = candidates.begin(); ite != candidates.end(); ++ ite) { + for(std::vector<CppCFString>::iterator ite = candidates.begin(); + ite != candidates.end(); ++ ite) { const int semicolon_pos = ite->indexOf(';'); if(semicolon_pos != -1) { ite->erase(semicolon_pos, ite->length()); @@ -331,20 +245,12 @@ return join(' ', candidates); } else { std::vector<CppCFString> candidates; - - for(DictionaryPrefIterator iter = prefs_.begin(); iter != prefs_.end(); ++ iter) { - // O[v«ÌêAùÉó⪩©ÁÄ¢êÎõðâßé - if(iter->type == GroupingDictionaryType && !candidates.empty()) { - break; - } - - Dictionary* dict = dicts_[generateID(*iter)]; - std::vector<CppCFString> result = dict->findOkuriNasi(query_str); - if(result.empty()) { - continue; - } - - candidates.insert(candidates.end(), result.begin(), result.end()); + for(std::vector<Dictionary*>::const_iterator ite = all_dics.begin(); + ite != all_dics.end(); ++ ite) { + std::vector<CppCFString> cand_for_one = (*ite)->findOkuriNasi(query_str); + if(cand_for_one.size() > 0) + candidates.insert(candidates.end(), + cand_for_one.begin(), cand_for_one.end()); } // candidatesÌd¡ð`FbNBd¡µÄ¢½çãÉ éàÌðíB @@ -352,7 +258,8 @@ // candidatesÌSÄÌÚÌXy[Xð[20]ÉÏ·B // ߪt¢Ä¢êÎAí·éB(bè) - for(std::vector<CppCFString>::iterator ite = candidates.begin(); ite != candidates.end(); ++ ite) { + for(std::vector<CppCFString>::iterator ite = candidates.begin(); + ite != candidates.end(); ++ ite) { const int semicolon_pos = ite->indexOf(';'); if(semicolon_pos != -1) { ite->erase(semicolon_pos, ite->length()); @@ -388,7 +295,7 @@ << index.length() << " okuri:" << okuri.length() << " kanji:" << kanji.length() << " (len)" << std::endl; } else { - userdict_->registerOkuriAri(index, okuri, kanji); + user_dic->registerOkuriAri(index, okuri, kanji); } } else { // è¼¼³µBu-©È ¼¼v @@ -403,7 +310,7 @@ << index.length() << " kanji:" << kanji.length() << " (len)" << std::endl; } else { - userdict_->registerOkuriNasi(index, kanji); + user_dic->registerOkuriNasi(index, kanji); } } } @@ -431,7 +338,7 @@ << index.length() << " okuri:" << okuri.length() << " kanji:" << kanji.length() << " (len)" << std::endl; } else { - userdict_->removeOkuriAri(index, kanji); + user_dic->removeOkuriAri(index, kanji); } } else { // è¼¼³µBu-©È ¼¼v @@ -446,19 +353,24 @@ << index.length() << " kanji:" << kanji.length() << " (len)" << std::endl; } else { - userdict_->removeOkuriNasi(index, kanji); + user_dic->removeOkuriNasi(index, kanji); } } } CppCFString SKKServer::searchCompletions(const CppCFString& query) { + // bèÎ(#7387) + if(query.length() < 1) { + return CppCFString(); + } + CppCFString space(" "); CppCFString nbsp("[20]"); D_PRINTF("COMPLETE: %s\n", query.toCString(kCFStringEncodingEUC_JP)); CppCFString head = query.replaceClone(nbsp, space); - std::vector<CppCFString> result = userdict_->findCompletions(head); + std::vector<CppCFString> result = user_dic->findCompletions(head); D_PRINTF("REPLY: %s\n", join(' ',result).toCString(kCFStringEncodingEUC_JP)); Index: AquaSKK/SKKServer.h diff -u AquaSKK/SKKServer.h:1.3.2.1 AquaSKK/SKKServer.h:1.3 --- AquaSKK/SKKServer.h:1.3.2.1 Wed Feb 15 00:12:44 2006 +++ AquaSKK/SKKServer.h Wed Nov 9 00:02:24 2005 @@ -1,10 +1,11 @@ /* -*- c++ -*- - $Id: SKKServer.h,v 1.3.2.1 2006/02/14 15:12:44 t-suwa Exp $ - + $Id: SKKServer.h,v 1.3 2005/11/08 15:02:24 t-suwa Exp $ + --------- + MacOS X implementation of the SKK input method. Copyright (C) 2002 phonohawk - Copyright (C) 2005-2006 Tomotaka SUWA <t.suw****@mac*****> + Copyright (C) 2005 Tomotaka SUWA <t.suw****@mac*****> 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 @@ -25,52 +26,45 @@ #include <string> #include <vector> -#include <map> class CppCFString; class Dictionary; class UserDictionary; +class SKKDictionary; +class DMDictionary; -class SKKServer { - // «ÌíÞ - enum DictionaryTypes { - SKKDictionaryType = 10, - SKKAutoUpdateDictionaryType = 11, - KotoeriDictionaryType = 20, - ProxyDictionaryType = 30, - GroupingDictionaryType = 90, - }; - - // «ÌÝè - struct DictionaryPref { - bool active; - int type; - std::string location; - }; - typedef std::vector<DictionaryPref> DictionaryPrefContainer; - typedef DictionaryPrefContainer::iterator DictionaryPrefIterator; - typedef std::map<std::string, Dictionary*> DictionaryContainer; - typedef DictionaryContainer::iterator DictionaryIterator; - - // [U[« - UserDictionary* userdict_; - - DictionaryPrefContainer prefs_; - DictionaryContainer dicts_; - - Dictionary* createDictionary(const DictionaryPref& pref) const; - std::string generateID(const DictionaryPref& pref) const; - void load(); +/* + ú»ðKvÆ·éSingletonÅ éB + gp·éOÉsharedServer(string,string,string)ðÄÎÈÄÍÈçÈ¢B + + c»Ì¤¿C³µÜ·B©ÍÅ«Ìêðæ¾·é̪³µ¢Æv¤c +*/ - SKKServer(); - ~SKKServer(); +class SKKServer { + Dictionary* base_dic; + Dictionary* sub_dic; + UserDictionary* user_dic; + Dictionary* kotoeri_dic; + std::vector<Dictionary*> all_dics; + + SKKServer(const std::string& base_dic_file, + const std::string& sub_dic_file, + const std::string& user_dic_file, + const std::vector<CppCFString>& kotoeri_dic_file); + virtual ~SKKServer(); public: + static SKKServer& sharedServer(const std::string& base_dic_file, + const std::string& sub_dic_file, + const std::string& user_dic_file, + const std::vector<CppCFString>& kotoeri_dic_file); static SKKServer& sharedServer(); - - void reload(); void terminate(); + SKKDictionary& getBaseDic(); + SKKDictionary& getSubDic(); + DMDictionary& getKotoeriDic(); + CppCFString skkserv_style_search(const CppCFString& query); // NOT FOUNDÈçó̶ñðÔ·B CppCFString search(const CppCFString& query); // NOT FOUNDÈçó̶ñðÔ·B void registerToUserDic(const CppCFString& query); Index: AquaSKK/ServerMessageReceiver.mm diff -u AquaSKK/ServerMessageReceiver.mm:1.4.2.1 AquaSKK/ServerMessageReceiver.mm:1.4.2.2 --- AquaSKK/ServerMessageReceiver.mm:1.4.2.1 Sat Jan 7 16:22:29 2006 +++ AquaSKK/ServerMessageReceiver.mm Sat Feb 18 02:20:38 2006 @@ -1,10 +1,10 @@ /* -*- objc -*- - $Id: ServerMessageReceiver.mm,v 1.4.2.1 2006/01/07 07:22:29 t-suwa Exp $ + $Id: ServerMessageReceiver.mm,v 1.4.2.2 2006/02/17 17:20:38 t-suwa Exp $ MacOS X implementation of the SKK input method. Copyright (C) 2002 phonohawk - Copyright (C) 2005 Tomotaka SUWA <t.suw****@mac*****> + Copyright (C) 2005-2006 Tomotaka SUWA <t.suw****@mac*****> 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 @@ -21,19 +21,17 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#import <AppKit/AppKit.h> -#import "CandidatesView.h" -#import "CandidatesWindowController.h" -#import "PreferencesController.h" -#import "AboutBoxController.h" - -#include <Carbon/Carbon.h> +#include <AppKit/AppKit.h> +#include "CandidatesView.h" +#include "CandidatesWindowController.h" +#include "PreferencesController.h" +#include "AboutBoxController.h" #include "BIMClientServer.h" #include "CppCFString.h" #include "CppCFData.h" #include "ServerMessageReceiver.h" #include "ClientConnectionFactory.h" -#include "SKKServer.h" +#include "DictionarySet.h" #include "CandidatesManager.h" static ServerMessageReceiver* _shared_instance = NULL; @@ -131,7 +129,7 @@ CppCFData ServerMessageReceiver::searchWord(const CppCFData& attachment) { // ÇÁf[^ƵÄUniCharÌzñðæéB CppCFString query(attachment.getData()); - CppCFString reply(SKKServer::sharedServer().search(query)); + CppCFString reply(DictionarySet::theInstance().search(query)); return CppCFData().own(reply.toCFData()); } @@ -193,13 +191,13 @@ void ServerMessageReceiver::registerThisToUserDic(const CppCFData& attachment) { CppCFString query(attachment.getData()); - SKKServer::sharedServer().registerToUserDic(query); + DictionarySet::theInstance().registerToUserDic(query); } void ServerMessageReceiver::removeThisFromUserDic(const CppCFData& attachment) { CppCFString query(attachment.getData()); - SKKServer::sharedServer().removeFromUserDic(query); + DictionarySet::theInstance().removeFromUserDic(query); } void ServerMessageReceiver::showAboutBox() { @@ -212,7 +210,7 @@ CppCFData ServerMessageReceiver::fetchCompletions(const CppCFData& attachment) { CppCFString query(attachment.getData()); - CppCFString reply(SKKServer::sharedServer().searchCompletions(query)); + CppCFString reply(DictionarySet::theInstance().searchCompletions(query)); return CppCFData().own(reply.toCFData()); } Index: AquaSKK/Skkserv.cpp diff -u AquaSKK/Skkserv.cpp:1.2.2.1 AquaSKK/Skkserv.cpp:1.2 --- AquaSKK/Skkserv.cpp:1.2.2.1 Sat Jan 14 20:01:58 2006 +++ AquaSKK/Skkserv.cpp Sat Oct 8 00:08:36 2005 @@ -1,74 +1,80 @@ /* -*- c++ -*- - $Id: Skkserv.cpp,v 1.2.2.1 2006/01/14 11:01:58 t-suwa Exp $ - - MacOS X implementation of the SKK input method. - - Copyright (C) 2002-2004 phonohawk - Copyright (C) 2006 Tomotaka SUWA <t.suw****@mac*****> + $Id: Skkserv.cpp,v 1.2 2005/10/07 15:08:36 t-suwa Exp $ + + MacOS X implementation of the SKK input method. + Copyright (C) 2002-2004 phonohawk - 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 - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + 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 + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <Carbon/Carbon.h> #include <iostream> #include <string> #include <vector> +#include <map> #include <pthread.h> #include <unistd.h> #include "CppCFString.h" +#include "OkuriganaEntry.h" +#include "Dictionary.h" +#include "DMDictionary.h" +#include "SKKDictionary.h" #include "SKKServer.h" #include "net/Socket.h" #include "Skkserv.h" +//using namespace std; static Skkserv* _shared = NULL; static void listening_thread_begin(Skkserv* serv); // ño -static void client_thread_begin(net::Socket* sock); // ño +static void client_thread_begin(Socket* sock); // ño Skkserv& Skkserv::sharedServer() { - if(_shared == NULL) { - _shared = new Skkserv(); - } - return *_shared; + if (_shared == NULL) { + _shared = new Skkserv(); + } + return *_shared; } -Skkserv::Skkserv() :listening(NULL), local_only(false), flag_term(false) { - // empty +Skkserv::Skkserv() + :listening(NULL),local_only(false),flag_term(false) { + } Skkserv::~Skkserv() { - stop(); + stop(); } Skkserv& Skkserv::setLocalOnly(bool b) { - local_only = b; - return *this; + local_only = b; + return *this; } -Skkserv& Skkserv::start(int newPort) { - if(listening != NULL) { +Skkserv& Skkserv::start(int port) { + if (listening != NULL) { stop(); } try { - listening = new net::Socket("", newPort, true, true, 20); + listening = new Socket("", port, true, true, 20); pthread_t pth; - pthread_create(&pth, NULL, (void*(*)(void*))listening_thread_begin, this); + pthread_create(&pth,NULL,(void*(*)(void*))listening_thread_begin,this); pthread_detach(pth); - } catch(std::string& exception) { - std::cerr << exception << std::endl; + } + catch (string& exception) { + cerr << exception << endl; listening = NULL; } @@ -77,17 +83,17 @@ } Skkserv& Skkserv::stop() { - if(listening != NULL) { - flag_term = true; - while(flag_term) { - usleep(300); - } - - delete listening; - listening = NULL; + if (listening != NULL) { + flag_term = true; + while (flag_term) { + usleep(300); } + + delete listening; + listening = NULL; + } - return *this; + return *this; } bool Skkserv::isRunning() const { @@ -104,40 +110,39 @@ } static void listening_thread_begin(Skkserv* obj) { - obj->listening_thread_routine(); + obj->listening_thread_routine(); } void Skkserv::listening_thread_routine() { - while(!flag_term) { - bool ready_to_accept; - listening->poll(&ready_to_accept, NULL, NULL, 500); - if(ready_to_accept) { - net::Socket* client = listening->accept(); - - if (local_only && client->getpeername() != "127.0.0.1") { - // ÚãÛ - delete client; - } - else { - pthread_t pth; - pthread_create(&pth,NULL,(void*(*)(void*))client_thread_begin,client); - pthread_detach(pth); - } - } + while (!flag_term) { + bool ready_to_accept; + listening->poll(&ready_to_accept, NULL, NULL, 500); + if (ready_to_accept) { + Socket* client = listening->accept(); + + if (local_only && client->getpeername() != "127.0.0.1") { + // ÚãÛ + delete client; + } + else { + pthread_t pth; + pthread_create(&pth,NULL,(void*(*)(void*))client_thread_begin,client); + pthread_detach(pth); + } } - flag_term = false; + } + flag_term = false; } -static void client_thread_begin(net::Socket* sock) { - SkkservSession session(sock); - session.run(); +static void client_thread_begin(Socket* sock) { + SkkservSession session(sock); + session.run(); } -SkkservSession::SkkservSession(net::Socket* src) : sock(src) { - // empty -} +SkkservSession::SkkservSession(Socket* sock) + : sock(sock) {} SkkservSession::~SkkservSession() { - delete sock; + delete sock; } void SkkservSession::run() { @@ -154,8 +159,8 @@ } else if (command == '1') { // ûõ - std::string word = sock->readUntil(' '); - CppCFString query(word.c_str(), kCFStringEncodingEUC_JP); + string word = sock->readUntil(' '); + CppCFString query(word.c_str(),kCFStringEncodingEUC_JP); CppCFString reply(SKKServer::sharedServer().skkserv_style_search(query.trim())); if (reply.length() == 0) { Index: AquaSKK/Skkserv.h diff -u AquaSKK/Skkserv.h:1.2.2.1 AquaSKK/Skkserv.h:1.2 --- AquaSKK/Skkserv.h:1.2.2.1 Sat Jan 14 20:01:58 2006 +++ AquaSKK/Skkserv.h Sat Oct 8 00:08:36 2005 @@ -1,40 +1,38 @@ /* -*- c++ -*- - $Id: Skkserv.h,v 1.2.2.1 2006/01/14 11:01:58 t-suwa Exp $ - - MacOS X implementation of the SKK input method. - - Copyright (C) 2002 phonohawk - Copyright (C) 2006 Tomotaka SUWA <t.suw****@mac*****> - - 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 - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + $Id: Skkserv.h,v 1.2 2005/10/07 15:08:36 t-suwa Exp $ + --------- + + MacOS X implementation of the SKK input method. + Copyright (C) 2002 phonohawk + + 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 + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #pragma once - -namespace net { - class Socket; -}; +using namespace net; +using namespace std; class Skkserv { - net::Socket* listening; +private: + Socket* listening; bool local_only; bool flag_term; - + Skkserv(); virtual ~Skkserv(); - + public: static Skkserv& sharedServer(); virtual Skkserv& setLocalOnly(bool b); @@ -42,14 +40,17 @@ virtual Skkserv& stop(); virtual bool isRunning() const; virtual int port() const; + virtual void listening_thread_routine(); }; class SkkservSession { - net::Socket* sock; +private: + Socket* sock; public: - SkkservSession(net::Socket* sock); + SkkservSession(Socket* sock); virtual ~SkkservSession(); + virtual void run(); }; Index: AquaSKK/main.m diff -u /dev/null AquaSKK/main.m:1.1.2.1 --- /dev/null Sat Feb 18 02:20:38 2006 +++ AquaSKK/main.m Sat Feb 18 02:20:38 2006 @@ -0,0 +1,29 @@ +/* + $Id: main.m,v 1.1.2.1 2006/02/17 17:20:38 t-suwa Exp $ + + MacOS X implementation of the SKK input method. + + Copyright (C) 2002 phonohawk + Copyright (C) 2006 Tomotaka SUWA <t.suw****@mac*****> + + 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 + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#import <Cocoa/Cocoa.h> + +// AquaSKKServer ÌGg|Cg +int main(int argc, const char* argv[]) { + return NSApplicationMain(argc, argv); +} Index: AquaSKK/socketstream.h diff -u /dev/null AquaSKK/socketstream.h:1.1.2.1 --- /dev/null Sat Feb 18 02:20:38 2006 +++ AquaSKK/socketstream.h Sat Feb 18 02:20:38 2006 @@ -0,0 +1,470 @@ +/* -*- c++ -*- + $Id: socketstream.h,v 1.1.2.1 2006/02/17 17:20:38 t-suwa Exp $ + + MacOS X implementation of the SKK input method. + + Copyright (C) 2006 Tomotaka SUWA <t.suw****@mac*****> + + 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 + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <iostream> +#include <ios> +#include <streambuf> +#include <string> +#include <vector> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <unistd.h> + +/* + +このソースは、http://gimite.ddo.jp/gimite/cppmess.htm で提供されている +socket14 を改変したものです。 + +*/ + +// IP アドレス +class ip_address { + in_addr addr_; + + friend bool operator<(const ip_address& lhs, const ip_address& rhs) { + return (unsigned int)lhs < (unsigned int)rhs; + } + friend bool operator>(const ip_address& lhs, const ip_address& rhs) { + return rhs < lhs; + } + friend bool operator<=(const ip_address& lhs, const ip_address& rhs) { + return !(lhs > rhs); + } + friend bool operator>=(const ip_address& lhs, const ip_address& rhs) { + return !(lhs < rhs); + } + friend bool operator==(const ip_address& lhs, const ip_address& rhs) { + return lhs >= rhs && lhs <= rhs; + } + friend bool operator!=(const ip_address& lhs, const ip_address& rhs) { + return !(lhs == rhs); + } + + friend std::ostream& operator<<(std::ostream& os, const ip_address& addr) { + return os << inet_ntoa(addr); + } + +public: + explicit ip_address(in_addr_t addr = INADDR_NONE) { + addr_.s_addr= addr; + } + explicit ip_address(const in_addr& addr) : addr_(addr) { + // empty + } + ip_address(const char* host) { + in_addr_t uaddr = inet_addr(host); + if(uaddr == INADDR_NONE) { + hostent* ent= gethostbyname(host); + if(ent && ent->h_addr_list[0]) { + uaddr= *(in_addr_t*)ent->h_addr_list[0]; + } + } + addr_.s_addr= uaddr; + } + operator in_addr() const { + return addr_; + } + operator unsigned int() const { + return addr_.s_addr; + } + static ip_address getpeername(int fd) { + struct sockaddr_in sa; + socklen_t length = sizeof(sa); + ::getpeername(fd, (struct sockaddr*)&sa, &length); + return ip_address(sa.sin_addr); + } + static ip_address getsockname(int fd) { + struct sockaddr_in sa; + socklen_t length = sizeof(sa); + ::getsockname(fd, (struct sockaddr*)&sa, &length); + return ip_address(sa.sin_addr); + } +}; + +// ソケットアドレス +struct socket_address { + ip_address ip; + unsigned short port; + + explicit socket_address(const ip_address& i = ip_address(), unsigned short p = 0) : ip(i), port(p) { + // empty + } + + friend bool operator<(const socket_address& lhs, const socket_address& rhs) { + if(lhs.ip < rhs.ip) return true; + if(lhs.ip > rhs.ip) return false; + return lhs.port < rhs.port; + } + friend bool operator>(const socket_address& lhs, const socket_address& rhs) { + return rhs < lhs; + } + friend bool operator<=(const socket_address& lhs, const socket_address& rhs) { + return !(lhs > rhs); + } + friend bool operator>=(const socket_address& lhs, const socket_address& rhs) { + return !(lhs < rhs); + } + friend bool operator==(const socket_address& lhs, const socket_address& rhs) { + return lhs >= rhs && lhs <= rhs; + } + friend bool operator!=(const socket_address& lhs, const socket_address& rhs) { + return !(lhs == rhs); + } + + friend std::ostream& operator<<(std::ostream& os, const socket_address& saddr) { + os << saddr.ip << ":" << saddr.port; + return os; + } +}; + +// ソケットストリームバッファ +class socket_streambuf : public std::streambuf { + typedef std::streambuf::int_type int_type; + typedef std::streambuf::traits_type traits_type; + int sock_; + char* egbuf_; + + inline char* egbuf() { + return egbuf_; + } + + inline void initialize(int bufsize = 4096) { + char* buf; + buf = new char[bufsize]; + setg(buf, buf, buf); + egbuf_ = buf + bufsize; + buf = new char[bufsize]; + setp(buf, buf + bufsize); + } + +protected: + virtual int_type overflow(int_type c = traits_type::eof()) { + if(traits_type::eq_int_type(traits_type::eof(), c)) + return traits_type::not_eof(c); + + // バッファに溜まったデータを流す + if(sync() == -1) + return traits_type::eof(); + + if(pptr() < epptr()) { + *pptr() = traits_type::to_char_type(c); + pbump(1); + } else { + if(send((void*)&c, 1) != 1) { + return traits_type::eof(); + } + } + return c; + } + + virtual int_type pbackfail(int_type c = traits_type::eof()) { + if(eback() < gptr()) { + gbump(-1); + if(!traits_type::eq_int_type(traits_type::eof(), c)) { + *gptr() = c; + } + return traits_type::not_eof(c); + } + return traits_type::eof(); + } + + virtual int_type underflow() { + if(gptr() < egptr()) { + return traits_type::to_int_type(*gptr()); + } + + setg(eback(), eback(), eback()); + int r = recv((void*)gptr(), egbuf() - gptr()); + if(r == 0) { + return traits_type::eof(); + } else { + if(r <0) { + r = 0; + } + } + setg(eback(), gptr(), gptr() + r); + return *gptr(); + } + + virtual int sync() { + int len = pptr() - pbase(); + if(send((void*)pbase(), len) != len) { + return -1; + } + + setp(pbase(), epptr()); + return 0; + } + +public: + explicit socket_streambuf(int sock = -1) : sock_(sock) { + initialize(); + } + socket_streambuf(const ip_address& host, unsigned short port) : sock_(-1) { + initialize(); + open(host, port); + } + virtual ~socket_streambuf() { + close(); + } + + bool open(const ip_address& host, unsigned short port) { + if(is_open()) { + close(); + } + if(host == INADDR_NONE) { + return false; + } + sock_ = ::socket(AF_INET, SOCK_STREAM, 0); + if(sock_ == -1) { + return false; + } + sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr = host; + if(connect(sock_, (const sockaddr*)&addr, sizeof(sockaddr_in)) == -1) { + close(); + } + return is_open(); + } + void close() { + if(sock_ == -1) { + return; + } + ::close(sock_); + sock_= -1; + } + int release() { + int sock = sock_; + sock_ = -1; + return sock; + } + int send(const void* buffer, int size) { + return ::send(sock_, (const char*)buffer, size, 0); + } + int recv(void* buffer, int size) { + return ::recv(sock_, (char*)buffer, size, 0); + } + bool is_open() const { + return sock_ != -1; + } + int socket() const { + return sock_; + } +}; + +// ソケットストリーム +class socket_stream: public std::iostream { + socket_streambuf sbuf_; + +public: + socket_stream() : std::iostream(0) { + rdbuf(&sbuf_); + setstate(std::ios::badbit); + } + socket_stream(const ip_address& host, unsigned short port) : std::iostream(0), sbuf_(host, port) { + rdbuf(&sbuf_); + if(!sbuf_.is_open()) { + setstate(std::ios::badbit); + } + } + explicit socket_stream(int sock) : std::iostream(0), sbuf_(sock) { + rdbuf(&sbuf_); + if(!sbuf_.is_open()) { + setstate(std::ios::badbit); + } + } + virtual ~socket_stream() { + rdbuf(0); + } + void open(const ip_address& host, unsigned short port) { + clear(); + sbuf_.open(host, port); + if(!sbuf_.is_open()) { + setstate(std::ios::badbit); + } + } + void close() { + setstate(std::ios::badbit); + sbuf_.close(); + } + int release() { + setstate(std::ios::badbit); + return sbuf_.release(); + } + int send(const void* buffer, int size) { + return sbuf_.send(buffer, size); + } + int recv(void* buffer, int size) { + return sbuf_.recv(buffer, size); + } + int socket() const { + return sbuf_.socket(); + } +}; + +// バインドされたソケット +class bound_socket { + const int type_; + int sock_; + bool is_bound_; + +protected: + bool bind(unsigned short port) { + if(is_bound_) { + return false; + } + if(sock_ == -1) { + sock_ = ::socket(AF_INET, type_, 0); + if(sock_ == -1) { + return false; + } + } + sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr = ip_address(INADDR_ANY); + if(::bind(sock_, (const sockaddr*)&addr, sizeof(addr)) == -1) { + return false; + } + is_bound_ = true; + return true; + } + +public: + explicit bound_socket(int type) : type_(type), sock_(-1), is_bound_(false) { + // empty + } + bound_socket(int type, int sock, bool is_bound) : type_(type), sock_(sock), is_bound_(is_bound) { + // empty + } + virtual ~bound_socket() { + close(); + } + void close() { + is_bound_ = false; + if(sock_ == -1) { + return; + } + ::close(sock_); + sock_ = -1; + } + int release() { + int sock = sock_; + sock_ = -1; + is_bound_ = false; + return sock; + } + void socket(int sock, bool is_bound) { + close(); + sock_ = sock; + is_bound_ = is_bound; + } + int socket() const { + return sock_; + } + operator const void*() const { + return is_bound_? this : NULL; + } + bool operator!() const { + return !is_bound_; + } +}; + +// サーバーソケット +class server_stream_socket: public bound_socket { + bool ready(int timeout_ms) { + fd_set rfds; + timeval tv; + tv.tv_sec = 0; + tv.tv_usec = timeout_ms; + + FD_ZERO(&rfds); + FD_SET(socket(), &rfds); + + return (select(socket() + 1, &rfds, NULL, NULL, (timeout_ms == -1 ? NULL : &tv)) > 0); + } + +public: + server_stream_socket() : bound_socket(SOCK_STREAM) { + // empty + } + explicit server_stream_socket(int port, int backlog = 5) : bound_socket(SOCK_STREAM) { + bind(port, backlog); + } + server_stream_socket(int sock, bool is_bound) : bound_socket(SOCK_STREAM, sock, is_bound) { + // empty + } + bool bind(int port, int backlog = 5) { + if(!bound_socket::bind(port)) { + return false; + } + if(listen(socket(), backlog) != -1) { + return true; + } + close(); + return false; + } + int accept(int timeout_ms = 1000) { + if(ready(timeout_ms)) { + return ::accept(socket(), 0, 0); + } + return -1; + } +}; + +// データグラムソケット +class datagram_socket: public bound_socket { +public: + datagram_socket() : bound_socket(SOCK_DGRAM) { + // empty + } + explicit datagram_socket(int port) : bound_socket(SOCK_DGRAM) { + bind(port); + } + datagram_socket(int sock, bool is_bound) : bound_socket(SOCK_DGRAM, sock, is_bound) { + // empty + } + bool bind(int port) { + return bound_socket::bind(port); + } + int recvfrom(void* buffer, int size, socket_address* addr = 0, int flags = 0) { + sockaddr_in saddr; + socklen_t addr_len = sizeof(saddr); + int result = ::recvfrom(socket(), (char*)buffer, size, flags, (sockaddr*)&saddr, &addr_len); + if(addr) { + addr->ip = ip_address(saddr.sin_addr); + addr->port = ntohs(saddr.sin_port); + } + return result; + } + int sendto(const void* buffer, int size, const socket_address* addr, int flags = 0) { + sockaddr_in saddr; + saddr.sin_family = AF_INET; + saddr.sin_addr = addr->ip; + saddr.sin_port = htons(addr->port); + return ::sendto(socket(), (const char*)buffer, size, flags, (const sockaddr*)&saddr, sizeof(saddr)); + } +};