SHA1 Hash: | dcdd144598475b1ac49d34f9836cd34dab86c606 |
---|---|
Date: | 2011-02-23 08:12:34 |
User: | kinaba |
Comment: | Copied from private svn repository. |
Timelines: | family | ancestors | descendants | both | trunk |
Downloads: | Tarball | ZIP archive |
Other Links: | files | file ages | manifest |
- branch=trunk inherited from [4fecaabbc8]
- sym-trunk inherited from [4fecaabbc8]
Added ConfigManager.cpp version [122ddf24e552b592]
1 + 2 +#include "stdafx.h" 3 +#include "ConfigManager.h" 4 +#include "rsrc/resource.h" 5 +#include "RSearch.h" 6 +using namespace ki; 7 +using namespace editwing; 8 + 9 + 10 + 11 +void BootNewProcess( const TCHAR* cmd ); // in GpMain.cpp 12 + 13 +//------------------------------------------------------------------------- 14 +// 設定項目管理。 15 +// SetDocTypeで切り替えると、文書タイプ依存の項目を自動で 16 +// 入れ替えたり色々。 17 +//------------------------------------------------------------------------- 18 + 19 +ConfigManager::ConfigManager() 20 +{ 21 + // デフォルトのレイアウト設定は何よりも先に読んでおく 22 + DocType d; 23 + d.name.Load( IDS_DEFAULT ); 24 + d.layfile = TEXT("default.lay"); 25 + LoadLayout( &d ); 26 + dtList_.Add( d ); 27 + curDt_ = dtList_.begin(); 28 + 29 + // ini読み込み 30 + LoadIni(); 31 + SetDocTypeByName( newfileDoctype_ ); 32 +} 33 + 34 +ConfigManager::~ConfigManager() 35 +{ 36 + // ini保存 37 + SaveIni(); 38 +} 39 + 40 +void ConfigManager::SetDocTypeByName( const ki::String& nam ) 41 +{ 42 + curDt_ = dtList_.begin(); 43 + DtList::iterator b = dtList_.begin(); 44 + DtList::iterator e = dtList_.end(); 45 + for( ; b!=e; ++b ) 46 + if( b->name == nam ) 47 + { 48 + curDt_ = b; 49 + break; 50 + } 51 + LoadLayout( &*curDt_ ); 52 +} 53 + 54 +int ConfigManager::SetDocType( const Path& fname ) 55 +{ 56 + const unicode* uname = fname.ConvToWChar(); 57 + 58 + int ct = 1; 59 + DtList::iterator i=dtList_.begin(), e=dtList_.end(); 60 + if( fname.len() > 0 ) 61 + { 62 + for( ++i; i!=e; ++i, ++ct ) 63 + if( i->pattern.len() > 0 ) 64 + { 65 + const unicode* upat = i->pattern.ConvToWChar(); 66 + bool b = MatchDocType( uname, upat ); 67 + i->pattern.FreeWCMem( upat ); 68 + if( b ) break; 69 + } 70 + if( i == e ) 71 + ct=0, i=dtList_.begin(); // 適切なのが見つからなければ[標準]。 72 + } 73 + else 74 + { 75 + ct = 0; 76 + } 77 + 78 + SetDocTypeByName( i->name ); 79 + 80 + fname.FreeWCMem( uname ); 81 + return ct; 82 +} 83 + 84 +bool ConfigManager::MatchDocType 85 + ( const unicode* fname, const unicode* pat ) 86 +{ 87 + // pattern と fname とのマッチをとって判定… 88 + return reg_match( pat, fname, false ); 89 +} 90 + 91 + 92 + 93 +//------------------------------------------------------------------------- 94 +// 設定ダイアログ関連 95 +//------------------------------------------------------------------------- 96 + 97 +struct ConfigDlg : public ki::DlgImpl 98 +{ 99 +private: 100 + typedef ConfigManager::DtList::iterator DTI; 101 + ulong curSel_; 102 + void SaveDt() 103 + { 104 + DTI p=myDtl_.begin(), e=myDtl_.end(); 105 + for( ulong ct=0; p!=e && ct!=curSel_; ++ct,++p ); 106 + if( p==e ) return; 107 + 108 + TCHAR buf[256]; 109 + SendMsgToItem(IDC_DT_PAT, WM_GETTEXT, 110 + countof(buf),reinterpret_cast<LPARAM>(buf)); 111 + p->pattern = buf; 112 + 113 + SendMsgToItem(IDC_PAT_KWD, CB_GETLBTEXT, 114 + SendMsgToItem(IDC_PAT_KWD, CB_GETCURSEL), 115 + reinterpret_cast<LPARAM>(buf) ); 116 + p->kwdfile = buf; 117 + 118 + SendMsgToItem(IDC_PAT_LAY, CB_GETLBTEXT, 119 + SendMsgToItem(IDC_PAT_LAY, CB_GETCURSEL), 120 + reinterpret_cast<LPARAM>(buf) ); 121 + p->layfile = buf; 122 + } 123 + void SelDt(ulong i) 124 + { 125 + DTI p=myDtl_.begin(), e=myDtl_.end(); 126 + for( ulong ct=0; p!=e && ct!=i; ++ct,++p ); 127 + if( p==e ) return; 128 + 129 + curSel_ = i; 130 + SendMsgToItem(IDC_DT_PAT, WM_SETTEXT, p->pattern.c_str()); 131 + if( p->kwdfile.len()==0 ) 132 + SendMsgToItem(IDC_PAT_KWD, CB_SETCURSEL); 133 + else 134 + SendMsgToItem(IDC_PAT_KWD,CB_SELECTSTRING,p->kwdfile.c_str()); 135 + SendMsgToItem(IDC_PAT_LAY,CB_SELECTSTRING,p->layfile.c_str()); 136 + } 137 + void on_deldoctype() 138 + { 139 + ulong ct; 140 + DTI p=myDtl_.begin(), e=myDtl_.end(); 141 + for( ct=0; p!=e && ct!=curSel_; ++ct,++p ); 142 + if( p==e ) return; 143 + 144 + String msg = TEXT("["); 145 + msg += p->name, msg += TEXT("]"), msg += String(IDS_OKTODEL); 146 + if( IDNO == 147 + MsgBox( msg.c_str(), String(IDS_APPNAME).c_str(), MB_YESNO ) ) 148 + return; 149 + 150 + myDtl_.Del(p); 151 + SendMsgToItem( IDC_DOCTYPELIST, LB_DELETESTRING, ct ); 152 + SelDt(0); 153 + if( ct+1 == (ulong)SendMsgToItem(IDC_NEWDT,CB_GETCURSEL) ) 154 + SendMsgToItem( IDC_NEWDT, CB_SETCURSEL ); 155 + SendMsgToItem( IDC_NEWDT, CB_DELETESTRING, ct+1 ); 156 + } 157 + void on_newdoctype() 158 + { 159 + struct NewDocTypeDlg : public DlgImpl 160 + { 161 + NewDocTypeDlg(HWND wnd) 162 + : DlgImpl(IDD_ADDDOCTYPE) { GoModal(wnd); } 163 + virtual bool on_ok() 164 + { 165 + TCHAR buf[MAX_PATH]; 166 + SendMsgToItem(IDC_NAME, WM_GETTEXT, 167 + countof(buf),reinterpret_cast<LPARAM>(buf)); 168 + name = buf; 169 + SendMsgToItem(IDC_EXT, WM_GETTEXT, 170 + countof(buf),reinterpret_cast<LPARAM>(buf)); 171 + ext=buf; 172 + return true; 173 + } 174 + String name; 175 + String ext; 176 + } dlg( hwnd() ); 177 + if( IDOK == dlg.endcode() ) 178 + { 179 + ConfigManager::DocType ndt; 180 + TCHAR buf[200]; 181 + SendMsgToItem(IDC_PAT_KWD, CB_GETLBTEXT, 182 + SendMsgToItem(IDC_PAT_KWD, CB_GETCURSEL), 183 + reinterpret_cast<LPARAM>(buf) ); 184 + ndt.kwdfile = buf; 185 + SendMsgToItem(IDC_PAT_LAY, CB_GETLBTEXT, 186 + SendMsgToItem(IDC_PAT_LAY, CB_GETCURSEL), 187 + reinterpret_cast<LPARAM>(buf) ); 188 + ndt.layfile = buf; 189 + ndt.name = dlg.name; 190 + ndt.pattern = TEXT(".*\\.")+dlg.ext+TEXT("$"); 191 + myDtl_.Add(ndt); 192 + SendMsgToItem( IDC_DOCTYPELIST, LB_ADDSTRING, 193 + ndt.name.c_str() ); 194 + SendMsgToItem( IDC_NEWDT, CB_ADDSTRING, 195 + ndt.name.c_str() ); 196 + } 197 + } 198 + 199 +public: 200 + ConfigDlg( ConfigManager& cfg, HWND wnd ) 201 + : cfg_( cfg ) 202 + , DlgImpl( IDD_CONFIG ) 203 + , curSel_( 0xffffffff ) 204 + { 205 + for( DTI i=++cfg_.dtList_.begin(); i!=cfg_.dtList_.end(); ++i ) 206 + myDtl_.Add( *i ); 207 + GoModal( wnd ); 208 + } 209 + 210 +private: 211 + void on_init() 212 + { 213 + SendMsgToItem(IDC_LATEST_NUM, WM_SETTEXT, 214 + String().SetInt(cfg_.mrus_).c_str() ); 215 + if( cfg_.undoLimit() == -1 ) 216 + { 217 + SendMsgToItem(IDC_UNDOLIM1, BM_SETCHECK, BST_CHECKED); 218 + SendMsgToItem(IDC_UNDO_CT, WM_SETTEXT, TEXT("20") ); 219 + } 220 + else 221 + { 222 + SendMsgToItem(IDC_UNDOLIM2, BM_SETCHECK, BST_CHECKED); 223 + SendMsgToItem(IDC_UNDO_CT, WM_SETTEXT, 224 + String().SetInt(cfg_.undoLimit()).c_str() ); 225 + } 226 + if( cfg_.countByUnicode() ) 227 + { 228 + SendMsgToItem(IDC_COUNTBYLETTER, BM_SETCHECK, BST_CHECKED); 229 + SendMsgToItem(IDC_COUNTBYLETTER2, BM_SETCHECK); 230 + } 231 + else 232 + { 233 + SendMsgToItem(IDC_COUNTBYLETTER, BM_SETCHECK); 234 + SendMsgToItem(IDC_COUNTBYLETTER2, BM_SETCHECK, BST_CHECKED); 235 + } 236 + 237 + SendMsgToItem(IDC_TXTFILT, WM_SETTEXT, 238 + cfg_.txtFileFilter().c_str() ); 239 + SendMsgToItem(IDC_EXTGREP, WM_SETTEXT, 240 + cfg_.grepExe().c_str() ); 241 + 242 + if( cfg_.openSame() ) 243 + SendMsgToItem(IDC_OPENSAME, BM_SETCHECK, BST_CHECKED); 244 + if( cfg_.rememberWindowSize_ ) 245 + SendMsgToItem(IDC_REMSIZE, BM_SETCHECK, BST_CHECKED); 246 + if( cfg_.rememberWindowPlace_ ) 247 + SendMsgToItem(IDC_REMPLACE, BM_SETCHECK, BST_CHECKED); 248 + 249 + CharSetList& csl = cfg_.GetCharSetList(); 250 + for(ulong i=1; i<csl.size(); ++i) 251 + SendMsgToItem( IDC_NEWCS, CB_ADDSTRING, csl[i].longName ); 252 + SendMsgToItem( IDC_NEWCS, CB_SETCURSEL, csl.findCsi(cfg_.newfileCharset_)-1 ); 253 + SendMsgToItem( IDC_NEWLB, CB_ADDSTRING, TEXT("CR") ); 254 + SendMsgToItem( IDC_NEWLB, CB_ADDSTRING, TEXT("LF") ); 255 + SendMsgToItem( IDC_NEWLB, CB_ADDSTRING, TEXT("CRLF") ); 256 + SendMsgToItem( IDC_NEWLB, CB_SETCURSEL, cfg_.newfileLB_ ); 257 + 258 + ulong nfd_idx=0, nfd_cnt=1; 259 + SendMsgToItem( IDC_NEWDT, CB_ADDSTRING, 260 + cfg_.dtList_.begin()->name.c_str() ); 261 + for( DTI i=myDtl_.begin(), e=myDtl_.end(); i!=e; ++i,++nfd_cnt ) 262 + { 263 + SendMsgToItem( IDC_DOCTYPELIST, LB_ADDSTRING, 264 + i->name.c_str() ); 265 + SendMsgToItem( IDC_NEWDT, CB_ADDSTRING, 266 + i->name.c_str() ); 267 + if( i->name == cfg_.newfileDoctype_ ) 268 + nfd_idx = nfd_cnt; 269 + } 270 + SendMsgToItem( IDC_NEWDT, CB_SETCURSEL, nfd_idx ); 271 + 272 + FindFile f; 273 + WIN32_FIND_DATA fd; 274 + f.Begin( (Path(Path::Exe)+=TEXT("type\\*.kwd")).c_str() ); 275 + SendMsgToItem( IDC_PAT_KWD, CB_ADDSTRING, TEXT("") ); 276 + while( f.Next(&fd) ) 277 + SendMsgToItem( IDC_PAT_KWD, CB_ADDSTRING, fd.cFileName ); 278 + f.Begin( (Path(Path::Exe)+=TEXT("type\\*.lay")).c_str() ); 279 + while( f.Next(&fd) ) 280 + SendMsgToItem( IDC_PAT_LAY, CB_ADDSTRING, fd.cFileName ); 281 + 282 + SelDt(0); 283 + 284 + SetCenter( hwnd(), ::GetParent(hwnd()) ); 285 + } 286 + 287 + bool on_command( UINT cmd, UINT id, HWND ctrl ) 288 + { 289 + switch( cmd ) 290 + { 291 + case LBN_SELCHANGE: 292 + SaveDt(); 293 + SelDt( (ulong)SendMsgToItem( IDC_DOCTYPELIST, LB_GETCURSEL ) ); 294 + break; 295 + default: 296 + TCHAR buf[256]; 297 + switch( id ) 298 + { 299 + case IDC_EDITKWD: 300 + SendMsgToItem(IDC_PAT_KWD, CB_GETLBTEXT, 301 + SendMsgToItem(IDC_PAT_KWD, CB_GETCURSEL), 302 + reinterpret_cast<LPARAM>(buf) ); 303 + if( buf[0] != TEXT('\0') ) 304 + BootNewProcess( (TEXT("\"")+Path(Path::Exe)+ 305 + TEXT("type\\")+buf+TEXT("\"") ).c_str()); 306 + break; 307 + case IDC_EDITLAY: 308 + SendMsgToItem(IDC_PAT_LAY, CB_GETLBTEXT, 309 + SendMsgToItem(IDC_PAT_LAY, CB_GETCURSEL), 310 + reinterpret_cast<LPARAM>(buf) ); 311 + BootNewProcess( (TEXT("\"")+Path(Path::Exe)+ 312 + TEXT("type\\")+buf+TEXT("\"") ).c_str()); 313 + break; 314 + case IDC_NEWDOCTYPE: 315 + on_newdoctype(); 316 + break; 317 + case IDC_DELDOCTYPE: 318 + on_deldoctype(); 319 + break; 320 + default: 321 + return false; 322 + } 323 + break; 324 + } 325 + return true; 326 + } 327 + 328 + bool on_ok() 329 + { 330 + TCHAR buf[100]; 331 + SendMsgToItem(IDC_LATEST_NUM, WM_GETTEXT, 332 + countof(buf),reinterpret_cast<LPARAM>(buf)); 333 + cfg_.mrus_ = String::GetInt(buf); 334 + cfg_.mrus_ = Min(Max(0, cfg_.mrus_), 20); 335 + 336 + if( BST_CHECKED == SendMsgToItem(IDC_UNDOLIM1, BM_GETCHECK) ) 337 + { 338 + cfg_.undoLimit_ = -1; 339 + } 340 + else 341 + { 342 + SendMsgToItem(IDC_UNDO_CT, WM_GETTEXT, 343 + countof(buf),reinterpret_cast<LPARAM>(buf)); 344 + cfg_.undoLimit_ = String::GetInt(buf); 345 + } 346 + 347 + SendMsgToItem(IDC_TXTFILT, WM_GETTEXT, 348 + countof(buf),reinterpret_cast<LPARAM>(buf)); 349 + cfg_.txtFilter_ = buf; 350 + 351 + SendMsgToItem(IDC_EXTGREP, WM_GETTEXT, 352 + countof(buf),reinterpret_cast<LPARAM>(buf)); 353 + cfg_.grepExe_ = buf; 354 + 355 + cfg_.openSame_ = 356 + ( BST_CHECKED==SendMsgToItem(IDC_OPENSAME, BM_GETCHECK) ); 357 + cfg_.rememberWindowSize_ = 358 + ( BST_CHECKED==SendMsgToItem(IDC_REMSIZE, BM_GETCHECK) ); 359 + cfg_.rememberWindowPlace_ = 360 + ( BST_CHECKED==SendMsgToItem(IDC_REMPLACE, BM_GETCHECK) ); 361 + 362 + cfg_.countbyunicode_ = 363 + ( BST_CHECKED==SendMsgToItem(IDC_COUNTBYLETTER, BM_GETCHECK) ); 364 + 365 + cfg_.newfileCharset_ = cfg_.GetCharSetList()[1+SendMsgToItem(IDC_NEWCS, CB_GETCURSEL)].ID; 366 + cfg_.newfileLB_ = (lbcode) SendMsgToItem(IDC_NEWLB, CB_GETCURSEL); 367 + size_t nfd_idx=SendMsgToItem(IDC_NEWDT, CB_GETCURSEL), nfd_cnt=1; 368 + cfg_.newfileDoctype_ = String(); 369 + 370 + SaveDt(); 371 + cfg_.dtList_.DelAfter( ++cfg_.dtList_.begin() ); 372 + for( DTI i=myDtl_.begin(), e=myDtl_.end(); i!=e; ++i, ++nfd_cnt ) 373 + { 374 + cfg_.dtList_.Add( *i ); 375 + if( nfd_idx == nfd_cnt ) 376 + cfg_.newfileDoctype_ = i->name; 377 + } 378 + return true; 379 + } 380 + 381 +private: 382 + ConfigManager& cfg_; 383 + ConfigManager::DtList myDtl_; 384 +}; 385 + 386 +bool ConfigManager::DoDialog( const ki::Window& parent ) 387 +{ 388 + LoadIni(); 389 + { 390 + ConfigDlg dlg(*this, parent.hwnd()); 391 + if( IDOK != dlg.endcode() ) 392 + return false; 393 + curDt_ = dtList_.begin(); // とりあえず 394 + } 395 + SaveIni(); 396 + return true; 397 +} 398 + 399 + 400 + 401 +//------------------------------------------------------------------------- 402 +// *.lay ファイルからの読み込み処理 403 +//------------------------------------------------------------------------- 404 + 405 +namespace { 406 + static ulong ToByte( unicode* str ) 407 + { 408 + ulong c = str[0]; 409 + if( L'a' <= str[0] ) c -= (L'a' - 10); 410 + else if( L'A' <= str[0] ) c -= (L'A' - 10); 411 + else c -= L'0'; 412 + c = c*16 + str[1]; 413 + if( L'a' <= str[1] ) c -= (L'a' - 10); 414 + else if( L'A' <= str[1] ) c -= (L'A' - 10); 415 + else c -= L'0'; 416 + return c; 417 + } 418 + static ulong GetColor( unicode* str ) 419 + { 420 + return ToByte(str) + (ToByte(str+2)<<8) + (ToByte(str+4)<<16); 421 + } 422 + static int GetInt( unicode* str ) 423 + { 424 + int c = 0; 425 + int s = 1; 426 + if( *str == L'-' ) 427 + s=-1, ++str; 428 + for( ; *str!=L'\0'; ++str ) 429 + c = c * 10 + *str - L'0'; 430 + return c*s; 431 + } 432 +} 433 + 434 +void ConfigManager::LoadLayout( ConfigManager::DocType* dt ) 435 +{ 436 + // 1.省略値として… 437 + 438 + DtList::iterator ref = dtList_.begin(); 439 + if( ref != dtList_.end() ) 440 + { 441 + // default.layがロードされていればそれを使う 442 + dt->vc = ref->vc; 443 + dt->wrapWidth = ref->wrapWidth; 444 + dt->wrapType = ref->wrapType; 445 + dt->showLN = ref->showLN; 446 + } 447 + else 448 + { 449 + // 組み込みのデフォルト設定をロード 450 + dt->vc.SetFont( TEXT("FixedSys"), 14 ); 451 + dt->vc.SetTabStep( 4 ); 452 + dt->vc.color[TXT] = RGB(0,0,0); 453 + dt->vc.color[KWD] = RGB(0,90,230); 454 + dt->vc.color[CMT] = RGB(0,0,0); 455 + dt->vc.color[BG] = RGB(255,255,255); 456 + dt->vc.color[CTL] = RGB(240,200,240); 457 + dt->vc.color[LN] = RGB(0,0,0); 458 + dt->vc.sc[scEOF] = dt->vc.sc[scEOL]=true; 459 + dt->vc.sc[scHSP] = dt->vc.sc[scZSP]=dt->vc.sc[scTAB]=false; 460 + dt->wrapWidth = 80; 461 + dt->wrapType = -1; 462 + dt->showLN = false; 463 + } 464 + 465 + // 2.*.layファイルからの読み込み 466 + 467 + TextFileR tf( UTF16LE ); 468 + if( tf.Open( (Path(Path::Exe)+TEXT("type\\")+dt->layfile).c_str() ) ) 469 + { 470 + String fontname; 471 + int fontsize=0; 472 + int x; 473 + bool clfound = false; 474 + 475 + unicode buf[1024], *ptr=buf+3; 476 + while( tf.state() != 0 ) // !EOF 477 + { 478 + size_t len = tf.ReadLine( buf, countof(buf)-1 ); 479 + if( len<=3 || buf[2]!=L'=' ) 480 + continue; 481 + buf[len] = L'\0'; 482 + 483 + switch( (buf[0]<<16)|buf[1] ) 484 + { 485 + case 0x00630074: // ct: COLOR-TEXT 486 + dt->vc.color[TXT] = GetColor(ptr); 487 + break; 488 + case 0x0063006B: // ck: COLOR-KEYWORD 489 + dt->vc.color[KWD] = GetColor(ptr); 490 + break; 491 + case 0x00630062: // cb: COLOR-BACKGROUND 492 + dt->vc.color[BG ] = GetColor(ptr); 493 + break; 494 + case 0x00630063: // cc: COLOR-COMMENT 495 + dt->vc.color[CMT] = GetColor(ptr); 496 + break; 497 + case 0x0063006E: // cn: COLOR-CONTROL 498 + dt->vc.color[CTL] = GetColor(ptr); 499 + break; 500 + case 0x0063006C: // cl: COLOR-LINE 501 + clfound = true; 502 + dt->vc.color[LN] = GetColor(ptr); 503 + break; 504 + case 0x00660074: // ft: FONT 505 + fontname = ptr; 506 + break; 507 + case 0x0073007A: // sz: SIZE 508 + fontsize = GetInt(ptr); 509 + break; 510 + case 0x00740062: // tb: TAB 511 + dt->vc.SetTabStep( GetInt(ptr) ); 512 + break; 513 + case 0x00730063: // sc: SPECIAL-CHAR 514 + x = GetInt(ptr); 515 + dt->vc.sc[scZSP] = (0!=x%10); x/=10; 516 + dt->vc.sc[scHSP] = (0!=x%10); x/=10; 517 + dt->vc.sc[scTAB] = (0!=x%10); x/=10; 518 + dt->vc.sc[scEOL] = (0!=x%10); x/=10; 519 + dt->vc.sc[scEOF] = (0!=x%10); 520 + break; 521 + case 0x00770070: // wp: WRAP-TYPE 522 + dt->wrapType = GetInt(ptr); 523 + break; 524 + case 0x00770077: // ww: WRAP-WIDTH 525 + dt->wrapWidth = GetInt(ptr); 526 + break; 527 + case 0x006C006E: // ln: LINE-NO 528 + dt->showLN = (0!=GetInt(ptr)); 529 + break; 530 + } 531 + } 532 + 533 + if( !clfound ) 534 + dt->vc.color[LN] = dt->vc.color[TXT]; 535 + if( fontname.len()!=0 && fontsize!=0 ) 536 + dt->vc.SetFont( fontname.c_str(), fontsize ); 537 + } 538 +} 539 + 540 + 541 + 542 +//------------------------------------------------------------------------- 543 +// *.ini ファイルからの読み込み/書き込み処理 544 +//------------------------------------------------------------------------- 545 + 546 +static const TCHAR s_sharedConfigSection[] = TEXT("SharedConfig"); 547 + 548 +void ConfigManager::LoadIni() 549 +{ 550 + { 551 + FileW fp; 552 + Path inipath(Path::Exe); 553 + inipath+=Path(Path::ExeName).body(); 554 + inipath+=TEXT(".ini"); 555 + if( !inipath.exist() && fp.Open(inipath.c_str()) ) 556 + { 557 + static const char s_defaultIni[] = 558 + "[DocType]\r\n" 559 + "1=C/C++\r\n" 560 + "2=C#\r\n" 561 + "3=D\r\n" 562 + "4=Java\r\n" 563 + "5=HTML\r\n" 564 + "6=CSS\r\n" 565 + "7=Perl\r\n" 566 + "8=Ruby\r\n" 567 + "9=PHP\r\n" 568 + "10=Python\r\n" 569 + "11=Haskell\r\n" 570 + "12=OCaml\r\n" 571 + "13=INI\r\n" 572 + "14=UnicodeText\r\n" 573 + "\r\n" 574 + "[C/C++]\r\n" 575 + "Pattern=.*(\\.(c|cpp|cxx|cc|h|hpp)|include\\\\[^\\.]+)$\r\n" 576 + "Keyword=C.kwd\r\n" 577 + "Layout=program.lay\r\n" 578 + "\r\n" 579 + "[Java]\r\n" 580 + "Pattern=.*\\.java$\r\n" 581 + "Keyword=Java.kwd\r\n" 582 + "Layout=program.lay\r\n" 583 + "\r\n" 584 + "[HTML]\r\n" 585 + "Pattern=.*(\\.html|\\.htm|temporary internet files\\\\.+)$\r\n" 586 + "Keyword=HTML.kwd\r\n" 587 + "Layout=html.lay\r\n" 588 + "\r\n" 589 + "[CSS]\r\n" 590 + "Pattern=.*\\.css$\r\n" 591 + "Keyword=CSS.kwd\r\n" 592 + "Layout=program.lay\r\n" 593 + "\r\n" 594 + "[PHP]\r\n" 595 + "Pattern=.*\\.(php|php3|php4)$\r\n" 596 + "Keyword=PHP.kwd\r\n" 597 + "Layout=program.lay\r\n" 598 + "\r\n" 599 + "[Python]\r\n" 600 + "Pattern=.*\\.py$\r\n" 601 + "Keyword=Python.kwd\r\n" 602 + "Layout=program.lay\r\n" 603 + "\r\n" 604 + "[Ruby]\r\n" 605 + "Pattern=.*\\.rb$\r\n" 606 + "Keyword=Ruby.kwd\r\n" 607 + "Layout=program.lay\r\n" 608 + "\r\n" 609 + "[D]\r\n" 610 + "Pattern=.*\\.d$\r\n" 611 + "Keyword=D.kwd\r\n" 612 + "Layout=program.lay\r\n" 613 + "\r\n" 614 + "[Haskell]\r\n" 615 + "Pattern=.*\\.l?hs$\r\n" 616 + "Keyword=Haskell.kwd\r\n" 617 + "Layout=program.lay\r\n" 618 + "\r\n" 619 + "[OCaml]\r\n" 620 + "Pattern=.*\\.mli?$\r\n" 621 + "Keyword=OCaml.kwd\r\n" 622 + "Layout=program.lay\r\n" 623 + "\r\n" 624 + "[C#]\r\n" 625 + "Pattern=.*\\.cs$\r\n" 626 + "Keyword=C#.kwd\r\n" 627 + "Layout=program.lay\r\n" 628 + "\r\n" 629 + "[INI]\r\n" 630 + "Pattern=.*\\.ini$\r\n" 631 + "Keyword=ini.kwd\r\n" 632 + "\r\n" 633 + "[Perl]\r\n" 634 + "Pattern=.*\\.(pl|pm|cgi)$\r\n" 635 + "Keyword=perl.kwd\r\n" 636 + "Layout=program.lay\r\n" 637 + "\r\n" 638 + "[UnicodeText]\r\n" 639 + "Layout=unitext.lay\r\n" 640 + "\r\n"; 641 + fp.Write( s_defaultIni, sizeof(s_defaultIni)-1 ); 642 + } 643 + } 644 + 645 + // 共通の設定の読み取りセクション 646 + sharedConfigMode_ = ini_.HasSectionEnabled( s_sharedConfigSection ); 647 + if( sharedConfigMode_ ) 648 + ini_.SetSection( s_sharedConfigSection ); 649 + else 650 + ini_.SetSectionAsUserName(); 651 + 652 + // 共通の設定 653 + undoLimit_ = ini_.GetInt( TEXT("UndoLimit"), -1 ); 654 + txtFilter_ = ini_.GetStr( TEXT("TxtFilter"), 655 + TEXT("*.txt;*.htm;*.html;*.css;*.js;*.d;*.c;*.cpp;*.cc;*.cxx;*.h;*.hpp;*.php;*.php3;*.ini") ); 656 + grepExe_ = ini_.GetStr( TEXT("GrepExe"), TEXT("") ); 657 + openSame_ = ini_.GetBool( TEXT("OpenSame"), false ); 658 + countbyunicode_ = ini_.GetBool( TEXT("CountUni"), false ); 659 + showStatusBar_ = ini_.GetBool( TEXT("StatusBar"), true ); 660 + 661 + // wnd 662 + rememberWindowSize_ = ini_.GetBool( TEXT("RememberWindowSize"), false ); 663 + rememberWindowPlace_ = ini_.GetBool( TEXT("RememberWindowPos"), false ); 664 + wndX_ = ini_.GetInt( TEXT("WndX"), CW_USEDEFAULT ); 665 + wndY_ = ini_.GetInt( TEXT("WndY"), CW_USEDEFAULT ); 666 + wndW_ = ini_.GetInt( TEXT("WndW"), CW_USEDEFAULT ); 667 + wndH_ = ini_.GetInt( TEXT("WndH"), CW_USEDEFAULT ); 668 + wndM_ = ini_.GetBool( TEXT("WndM"), false ); 669 + 670 + // TODO: MRU 671 + mrus_ = ini_.GetInt( TEXT("MRU"), 4 ); 672 + mrus_ = Min(Max(0, mrus_), 20); 673 + 674 + // 新規ファイル関係 675 + newfileCharset_ = ini_.GetInt( TEXT("NewfileCharset"), charSets_.defaultCs() ); 676 + if(newfileCharset_ == -1) newfileCharset_ = 1252; // 1.07.4 bugfix 677 + newfileDoctype_ = ini_.GetStr( TEXT("NewfileDoctype"), String() ); 678 + newfileLB_ = (lbcode) ini_.GetInt( TEXT("NewfileLB"), CRLF ); 679 + 680 + // 文書タイプリストの0番以外のクリア 681 + dtList_.DelAfter( ++dtList_.begin() ); 682 + 683 + String s, r; 684 + for( int i=1; true; ++i ) 685 + { 686 + // 文書タイプ名を読み込み 687 + ini_.SetSection( TEXT("DocType") ); 688 + s.SetInt(i); 689 + r = ini_.GetStr( s.c_str(), String() ); 690 + if( r.len() == 0 ) 691 + break; 692 + 693 + // その文書タイプを実際に読み込み 694 + ini_.SetSection( r.c_str() ); 695 + { 696 + DocType d; 697 + d.name = r; 698 + d.layfile = ini_.GetStr( TEXT("Layout"),TEXT("default.lay")); 699 + d.kwdfile = ini_.GetStr( TEXT("Keyword"), String() ); 700 + d.pattern = ini_.GetStr( TEXT("Pattern"), String() ); 701 + dtList_.Add( d ); 702 + } 703 + } 704 +} 705 + 706 +void ConfigManager::SaveIni() 707 +{ 708 + { 709 + Path inipath(Path::Exe); 710 + inipath+=Path(Path::ExeName).body(); 711 + inipath+=TEXT(".ini"); 712 + if( inipath.isReadOnly() ) 713 + return; 714 + } 715 + 716 + // 共通の設定の書き込みセクション 717 + if( sharedConfigMode_ ) 718 + ini_.SetSection( s_sharedConfigSection ); 719 + else 720 + ini_.SetSectionAsUserName(); 721 + 722 + // 共通の設定 723 + ini_.PutInt( TEXT("UndoLimit"), undoLimit_ ); 724 + ini_.PutStr( TEXT("TxtFilter"), txtFilter_.c_str() ); 725 + ini_.PutStr( TEXT("GrepExe"), grepExe_.c_str() ); 726 + ini_.PutBool( TEXT("OpenSame"), openSame_ ); 727 + ini_.PutBool( TEXT("CountUni"), countbyunicode_ ); 728 + ini_.PutBool( TEXT("StatusBar"), showStatusBar_ ); 729 + 730 + // Wnd 731 + ini_.PutBool( TEXT("RememberWindowSize"), rememberWindowSize_ ); 732 + ini_.PutBool( TEXT("RememberWindowPos"), rememberWindowPlace_ ); 733 + ini_.PutInt( TEXT("WndX"), wndX_ ); 734 + ini_.PutInt( TEXT("WndY"), wndY_ ); 735 + ini_.PutInt( TEXT("WndW"), wndW_ ); 736 + ini_.PutInt( TEXT("WndH"), wndH_ ); 737 + ini_.PutBool( TEXT("WndM"), wndM_ ); 738 + 739 + // 新規ファイル関係 740 + ini_.PutInt( TEXT("NewfileCharset"), newfileCharset_ ); 741 + ini_.PutStr( TEXT("NewfileDoctype"), newfileDoctype_.c_str() ); 742 + ini_.PutInt( TEXT("NewfileLB"), newfileLB_ ); 743 + 744 + // MRU 745 + ini_.PutInt( TEXT("MRU"), mrus_ ); 746 + 747 + // DocType 748 + for(DtList::iterator i=++dtList_.begin(); i!=dtList_.end(); ++i ) 749 + { 750 + ini_.SetSection( i->name.c_str() ); 751 + ini_.PutStr( TEXT("Pattern"), i->pattern.c_str() ); 752 + ini_.PutStr( TEXT("Keyword"), i->kwdfile.c_str() ); 753 + ini_.PutStr( TEXT("Layout"), i->layfile.c_str() ); 754 + } 755 + 756 + ulong ct=1; 757 + ini_.SetSection( TEXT("DocType") ); 758 + for(DtList::iterator i=++dtList_.begin(); i!=dtList_.end(); ++i,++ct) 759 + ini_.PutStr( String().SetInt(ct).c_str(), i->name.c_str() ); 760 + ini_.PutStr( String().SetInt(ct).c_str(), TEXT("") ); 761 +} 762 + 763 + 764 + 765 +//------------------------------------------------------------------------- 766 +// [最近使ったファイル]関係 767 +//------------------------------------------------------------------------- 768 + 769 +namespace { 770 + static const TCHAR* const s_mrulock = TEXT("GreenPad_MRUMutex"); 771 +} 772 + 773 +void ConfigManager::AddMRU( const ki::Path& fname ) 774 +{ 775 + Mutex mx(s_mrulock); 776 + 777 + // メモリ内のMRUリストを更新 778 + { 779 + int i; 780 + for( i=0; i<countof(mru_); ++i ) 781 + if( mru_[i] == fname ) 782 + {++i; break;} 783 + for( --i; i>0; --i ) 784 + mru_[i] = mru_[i-1]; 785 + mru_[0] = fname; 786 + } 787 + 788 + // iniへ保存 789 + { 790 + ini_.SetSectionAsUserName(); 791 + const String key = TEXT("MRU"); 792 + for( int i=0; i<countof(mru_); ++i ) 793 + ini_.PutPath( 794 + (key+String().SetInt(i+1)).c_str(), mru_[i] ); 795 + } 796 +} 797 + 798 +void ConfigManager::SetUpMRUMenu( HMENU m, UINT id ) 799 +{ 800 + Mutex mx(s_mrulock); 801 + 802 + // iniから読み込み 803 + { 804 + ini_.SetSectionAsUserName(); 805 + const String key = TEXT("MRU"); 806 + for( int i=0; i<countof(mru_); ++i ) 807 + mru_[i] = ini_.GetPath( 808 + (key+String().SetInt(i+1)).c_str(), Path() ); 809 + } 810 + 811 + // 全項目を削除 812 + while( ::DeleteMenu( m, 0, MF_BYPOSITION ) ); 813 + 814 + // メニュー構築 815 + MENUITEMINFO mi = { sizeof(MENUITEMINFO) }; 816 + mi.fMask = MIIM_ID | MIIM_TYPE; 817 + mi.fType = MFT_STRING; 818 + for( int i=0; i<countof(mru_); ++i ) 819 + { 820 + if( i>=mrus_ || mru_[i].len()==0 ) 821 + { 822 + if( i==0 ) 823 + { 824 + mi.fMask |= MIIM_STATE; 825 + mi.wID = id; 826 + mi.fState = MFS_DISABLED; 827 + mi.dwTypeData = TEXT("no files"); 828 + mi.cch = 0; 829 + ::InsertMenuItem( m, 0, MF_BYPOSITION, &mi ); 830 + } 831 + break; 832 + } 833 + String cpt = mru_[i].CompactIfPossible(60); 834 + mi.wID = id + i; 835 + mi.dwTypeData = const_cast<TCHAR*>(cpt.c_str()); 836 + mi.cch = cpt.len(); 837 + ::InsertMenuItem( m, i, MF_BYPOSITION, &mi ); 838 + } 839 +} 840 + 841 +Path ConfigManager::GetMRU( int no ) const 842 +{ 843 + return (0<=no && no<mrus_ ? mru_[no] : Path()); 844 +} 845 + 846 + 847 +//------------------------------------------------------------------------- 848 +// ウインドウサイズ復元処理 849 +//------------------------------------------------------------------------- 850 + 851 +void ConfigManager::RememberWnd( ki::Window* wnd ) 852 +{ 853 + RECT rc; 854 + wnd->getPos(&rc); 855 + WINDOWPLACEMENT wp = {sizeof(wp)}; 856 + ::GetWindowPlacement( wnd->hwnd(), &wp ); 857 + 858 + if( wp.showCmd==SW_SHOWNORMAL || wp.showCmd == SW_MAXIMIZE ) 859 + wndM_ = (wp.showCmd == SW_MAXIMIZE); 860 + if( wp.showCmd==SW_SHOWNORMAL ) 861 + { 862 + wndX_ = rc.left; 863 + wndY_ = rc.top; 864 + wndW_ = rc.right- rc.left; 865 + wndH_ = rc.bottom - rc.top; 866 + } 867 + //if( this->rememberWindowPlace_ || this->rememberWindowSize_ ) 868 + // SaveIni(); 869 +} 870 + 871 +//------------------------------------------------------------------------- 872 +// [文書タイプ]サブメニューの作成 873 +//------------------------------------------------------------------------- 874 + 875 +void ConfigManager::SetDocTypeMenu( HMENU m, UINT idstart ) 876 +{ 877 + // 全項目を削除 878 + while( ::DeleteMenu( m, 0, MF_BYPOSITION ) ); 879 + 880 + // 順に追加 881 + MENUITEMINFO mi = { sizeof(MENUITEMINFO) }; 882 + mi.fMask = MIIM_ID | MIIM_STATE | MIIM_TYPE; 883 + mi.fType = MFT_STRING | MFT_RADIOCHECK; 884 + 885 + DtList::iterator i=dtList_.begin(), e=dtList_.end(); 886 + for( int ct=0; i!=e; ++i, ++ct ) 887 + { 888 + mi.wID = idstart + ct; 889 + mi.fState = (i==curDt_ ? MFS_CHECKED : MFS_UNCHECKED); 890 + mi.dwTypeData = const_cast<TCHAR*>(i->name.c_str()); 891 + mi.cch = i->name.len(); 892 + ::InsertMenuItem( m, ct, MF_BYPOSITION, &mi ); 893 + } 894 +} 895 + 896 +void ConfigManager::SetDocTypeByMenu( int pos, HMENU m ) 897 +{ 898 + MENUITEMINFO mi = { sizeof(MENUITEMINFO) }; 899 + mi.fMask = MIIM_STATE; 900 + 901 + DtList::iterator i=dtList_.begin(), e=dtList_.end(); 902 + for( int ct=0; i!=e; ++i, ++ct ) 903 + { 904 + mi.fState = (ct==pos ? MFS_CHECKED : MFS_UNCHECKED); 905 + ::SetMenuItemInfo( m, ct, MF_BYPOSITION, &mi ); 906 + if( ct == pos ) 907 + { 908 + curDt_ = i; 909 + LoadLayout( &*curDt_ ); 910 + } 911 + } 912 +} 913 + 914 +void ConfigManager::CheckMenu( HMENU m, int pos ) 915 +{ 916 + MENUITEMINFO mi = { sizeof(MENUITEMINFO) }; 917 + mi.fMask = MIIM_STATE; 918 + 919 + DtList::iterator i=dtList_.begin(), e=dtList_.end(); 920 + for( int ct=0; i!=e; ++i, ++ct ) 921 + { 922 + mi.fState = (ct==pos ? MFS_CHECKED : MFS_UNCHECKED); 923 + ::SetMenuItemInfo( m, ct, MF_BYPOSITION, &mi ); 924 + } 925 +} 926 +
Added ConfigManager.h version [2b7c9df8032db9a4]
1 +#ifndef AFX_ONFIGMANAGER_H__9243DE9D_0F70_40F8_8F90_55436B952B37__INCLUDED_ 2 +#define AFX_ONFIGMANAGER_H__9243DE9D_0F70_40F8_8F90_55436B952B37__INCLUDED_ 3 +#include "editwing/editwing.h" 4 +#include "OpenSaveDlg.h" 5 + 6 + 7 + 8 +// アプリケーションメッセージ 9 +#define GPM_MRUCHANGED WM_APP+0 10 + 11 +//========================================================================= 12 +//@{ @pkg Gp.Main //@} 13 +//@{ 14 +// 設定の一元管理 15 +// 16 +// SetDocTypeで切り替えると、文書タイプ依存の項目を内部で 17 +// 適切に切り替えたり色々します。 18 +//@} 19 +//========================================================================= 20 + 21 +class ConfigManager : public ki::Object 22 +{ 23 +public: 24 + 25 + ConfigManager(); 26 + ~ConfigManager(); 27 + 28 + //@{ 指定した名前のファイル用の文書タイプをロード //@} 29 + int SetDocType( const ki::Path& fname ); 30 + 31 + //@{ 指定した番号の文書タイプをロード //@} 32 + void SetDocTypeByMenu( int pos, HMENU m ); 33 + 34 + //@{ 指定した名前の文書タイプをロード //@} 35 + void SetDocTypeByName( const ki::String& nam ); 36 + 37 + //@{ メニュー項目作成 //@} 38 + void SetDocTypeMenu( HMENU m, UINT idstart ); 39 + 40 + //@{ メニュー項目のチェック修正 //@} 41 + void CheckMenu( HMENU m, int pos ); 42 + 43 + //@{ 設定ダイアログ表示 //@} 44 + bool DoDialog( const ki::Window& parent ); 45 + 46 + //@{ 生のiniファイル操作オブジェクトを取得 //@} 47 + ki::IniFile& getImpl(); 48 + 49 +public: 50 + 51 + //@{ Undo回数制限値 //@} 52 + int undoLimit() const; 53 + 54 + //@{ 文字数のカウント方法 //@} 55 + bool countByUnicode() const; 56 + 57 + //@{ 開く/保存ダイアログに出すフィルタの設定 //@} 58 + const ki::String& txtFileFilter() const; 59 + 60 + //@{ 文字数指定時の折り返し文字数 //@} 61 + int wrapWidth() const; 62 + 63 + //@{ 折り返し方法 //@} 64 + int wrapType() const; 65 + 66 + //@{ 行番号表示する? //@} 67 + bool showLN() const; 68 + 69 + //@{ 表示色・フォントなど //@} 70 + const editwing::VConfig& vConfig() const; 71 + 72 + //@{ キーワードファイル名(フルパス) //@} 73 + ki::Path kwdFile() const; 74 + 75 + //@{ Grep用外部実行ファイル名 //@} 76 + const ki::Path& grepExe() const; 77 + 78 + //@{ 同じウインドウで開くモード //@} 79 + bool openSame() const; 80 + 81 + //@{ ステータスバー表示 //@} 82 + bool showStatusBar() const; 83 + void ShowStatusBarSwitch(); 84 + 85 +public: 86 + //@{ 新規ファイルの文字コードindex //@} 87 + int GetNewfileCsi() const; 88 + 89 + //@{ 新規ファイルの改行コード //@} 90 + ki::lbcode GetNewfileLB() const; 91 + 92 +public: 93 + //@{ [最近使ったファイル]へ追加 //@} 94 + void AddMRU( const ki::Path& fname ); 95 + 96 + //@{ [最近使ったファイル]メニューの構築 //@} 97 + void SetUpMRUMenu( HMENU m, UINT id ); 98 + 99 + //@{ [最近使ったファイル]取得 //@} 100 + ki::Path GetMRU( int no ) const; 101 + 102 + //@{ 対応文字セットリスト取得 //@} 103 + CharSetList& GetCharSetList(); 104 + 105 +public: 106 + //@{ ウインドウ位置・サイズ復元処理 //@} 107 + int GetWndX() const; 108 + int GetWndY() const; 109 + int GetWndW() const; 110 + int GetWndH() const; 111 + bool GetWndM() const; 112 + void RememberWnd( ki::Window* wnd ); 113 + 114 +private: 115 + 116 + ki::IniFile ini_; 117 + bool sharedConfigMode_; 118 + CharSetList charSets_; 119 + 120 + // 全体的な設定 121 + int undoLimit_; 122 + ki::String txtFilter_; 123 + ki::Path grepExe_; 124 + bool openSame_; 125 + bool countbyunicode_; 126 + bool showStatusBar_; 127 + bool rememberWindowSize_; 128 + bool rememberWindowPlace_; 129 + 130 + // ウインドウサイズ記憶 131 + bool wndM_; // maximized? 132 + int wndX_, wndY_, wndW_, wndH_; 133 + 134 + // 文書タイプのリスト 135 + struct DocType 136 + { 137 + // 定義ファイル名など 138 + ki::String name; 139 + ki::String pattern; 140 + ki::String kwdfile; 141 + ki::String layfile; 142 + 143 + // 設定項目 144 + editwing::VConfig vc; 145 + int wrapType; 146 + int wrapWidth; 147 + bool showLN; 148 + }; 149 + typedef ki::olist<DocType> DtList; 150 + 151 + DtList dtList_; 152 + DtList::iterator curDt_; 153 + 154 + // 最近使ったファイルのリスト 155 + int mrus_; 156 + ki::Path mru_[20]; 157 + 158 + // 新規ファイル関係 159 + int newfileCharset_; 160 + ki::String newfileDoctype_; 161 + ki::lbcode newfileLB_; 162 + 163 +private: 164 + 165 + void LoadIni(); 166 + void SaveIni(); 167 + void LoadLayout( DocType* dt ); 168 + bool MatchDocType( const unicode* fname, const unicode* pat ); 169 + 170 +private: 171 + 172 + friend struct ConfigDlg; 173 + NOCOPY(ConfigManager); 174 +}; 175 + 176 + 177 + 178 +//------------------------------------------------------------------------- 179 +#ifndef __ccdoc__ 180 + 181 +inline int ConfigManager::undoLimit() const 182 + { return undoLimit_; } 183 + 184 +inline const ki::String& ConfigManager::txtFileFilter() const 185 + { return txtFilter_; } 186 + 187 +inline int ConfigManager::wrapWidth() const 188 + { return curDt_->wrapWidth; } 189 + 190 +inline int ConfigManager::wrapType() const 191 + { return curDt_->wrapType>0 ? wrapWidth() : curDt_->wrapType; } 192 + 193 +inline bool ConfigManager::showLN() const 194 + { return curDt_->showLN; } 195 + 196 +inline const editwing::VConfig& ConfigManager::vConfig() const 197 + { return curDt_->vc; } 198 + 199 +inline ki::Path ConfigManager::kwdFile() const 200 + { return ki::Path(ki::Path::Exe)+TEXT("type\\")+curDt_->kwdfile; } 201 + 202 +inline const ki::Path& ConfigManager::grepExe() const 203 + { return grepExe_; } 204 + 205 +inline bool ConfigManager::openSame() const 206 + { return openSame_; } 207 + 208 +inline bool ConfigManager::showStatusBar() const 209 + { return showStatusBar_; } 210 + 211 +inline void ConfigManager::ShowStatusBarSwitch() 212 + { showStatusBar_ = !showStatusBar_; SaveIni(); } 213 + 214 +inline bool ConfigManager::countByUnicode() const 215 + { return countbyunicode_; } 216 + 217 +inline ki::IniFile& ConfigManager::getImpl() 218 + { return ini_; } 219 + 220 +inline CharSetList& ConfigManager::GetCharSetList() 221 + { return charSets_; } 222 + 223 +inline int ConfigManager::GetNewfileCsi() const 224 + { return charSets_.findCsi( newfileCharset_ ); } 225 + 226 +inline ki::lbcode ConfigManager::GetNewfileLB() const 227 + { return newfileLB_; } 228 + 229 +inline int ConfigManager::GetWndX() const 230 + { return rememberWindowPlace_ ? wndX_ : CW_USEDEFAULT; } 231 + 232 +inline int ConfigManager::GetWndY() const 233 + { return rememberWindowPlace_ ? wndY_ : CW_USEDEFAULT; } 234 + 235 +inline int ConfigManager::GetWndW() const 236 + { return rememberWindowSize_ ? wndW_ : CW_USEDEFAULT; } 237 + 238 +inline int ConfigManager::GetWndH() const 239 + { return rememberWindowSize_ ? wndH_ : CW_USEDEFAULT; } 240 + 241 +inline bool ConfigManager::GetWndM() const 242 + { return rememberWindowSize_ & wndM_; } 243 + 244 +//========================================================================= 245 + 246 +#endif // __ccdoc__ 247 +#endif // AFX_ONFIGMANAGER_H__9243DE9D_0F70_40F8_8F90_55436B952B37__INCLUDED_
Added GpMain.cpp version [72773e35b0a1a949]
1 +#include "stdafx.h" 2 +#include "rsrc/resource.h" 3 +#include "GpMain.h" 4 +using namespace ki; 5 +using namespace editwing; 6 + 7 + 8 + 9 +//------------------------------------------------------------------------- 10 +// 新規プロセス起動 11 +//------------------------------------------------------------------------- 12 + 13 +void BootNewProcess( const TCHAR* cmd = TEXT("") ) 14 +{ 15 + STARTUPINFO sti; 16 + PROCESS_INFORMATION psi; 17 + ::GetStartupInfo( &sti ); 18 + 19 + String fcmd = Path(Path::ExeName).BeShortStyle(); 20 + fcmd += ' '; 21 + fcmd += cmd; 22 + 23 + if( ::CreateProcess( NULL, const_cast<TCHAR*>(fcmd.c_str()), 24 + NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, 25 + &sti, &psi ) ) 26 + { 27 + ::CloseHandle( psi.hThread ); 28 + ::CloseHandle( psi.hProcess ); 29 + } 30 +} 31 + 32 + 33 + 34 +//------------------------------------------------------------------------- 35 +// ステータスバー制御 36 +//------------------------------------------------------------------------- 37 + 38 +inline GpStBar::GpStBar() 39 + : str_(NULL) 40 + , lb_(2) 41 +{ 42 +} 43 + 44 +inline void GpStBar::SetCsText( const TCHAR* str ) 45 +{ 46 + // 文字コード表示領域にSetTextする 47 + SetText( str_=str, 1 ); 48 +} 49 + 50 +inline void GpStBar::SetLbText( int lb ) 51 +{ 52 + // 改行コード表示領域にSetTextする 53 + static const TCHAR* const lbstr[] = {TEXT("CR"),TEXT("LF"),TEXT("CRLF")}; 54 + SetText( lbstr[lb_=lb], 2 ); 55 +} 56 + 57 +int GpStBar::AutoResize( bool maximized ) 58 +{ 59 + // 文字コード表示領域を確保しつつリサイズ 60 + int h = StatusBar::AutoResize( maximized ); 61 + int w[] = { width()-5, width()-5, width()-5 }; 62 + 63 + HDC dc = ::GetDC( hwnd() ); 64 + SIZE s; 65 + if( ::GetTextExtentPoint32( dc, TEXT("BBBBM"), 5, &s ) ) 66 + w[1] = w[2] - s.cx; 67 + if( ::GetTextExtentPoint32( dc, TEXT("BBBBB"), 5, &s ) ) 68 + w[0] = w[1] - s.cx; 69 + ::ReleaseDC( hwnd(), dc ); 70 + 71 + SetParts( countof(w), w ); 72 + SetCsText( str_ ); 73 + SetLbText( lb_ ); 74 + return h; 75 +} 76 + 77 + 78 + 79 +//------------------------------------------------------------------------- 80 +// ディスパッチャ 81 +//------------------------------------------------------------------------- 82 + 83 +LRESULT GreenPadWnd::on_message( UINT msg, WPARAM wp, LPARAM lp ) 84 +{ 85 + switch( msg ) 86 + { 87 + // アクティブ化。EditCtrlにフォーカスを。 88 + case WM_ACTIVATE: 89 + if( LOWORD(wp) != WA_INACTIVE ) 90 + edit_.SetFocus(); 91 + break; 92 + 93 + // サイズ変更。子窓を適当に移動。 94 + case WM_SIZE: 95 + if( wp==SIZE_MAXIMIZED || wp==SIZE_RESTORED ) 96 + { 97 + int ht = stb_.AutoResize( wp==SIZE_MAXIMIZED ); 98 + edit_.MoveTo( 0, 0, LOWORD(lp), HIWORD(lp)-ht ); 99 + cfg_.RememberWnd(this); 100 + } 101 + break; 102 + 103 + // ウインドウ移動 104 + case WM_MOVE: 105 + { 106 + RECT rc; 107 + getPos(&rc); 108 + cfg_.RememberWnd(this); 109 + } 110 + break; 111 + 112 + // システムコマンド。終了ボタンとか。 113 + case WM_SYSCOMMAND: 114 + if( wp==SC_CLOSE || wp==SC_DEFAULT ) 115 + on_exit(); 116 + else 117 + return WndImpl::on_message( msg, wp, lp ); 118 + break; 119 + 120 + // 右クリックメニュー 121 + case WM_CONTEXTMENU: 122 + if( reinterpret_cast<HWND>(wp) == edit_.hwnd() ) 123 + ::TrackPopupMenu( 124 + ::GetSubMenu( ::GetMenu(hwnd()), 1 ), // 編集メニュー表示 125 + TPM_LEFTALIGN|TPM_TOPALIGN|TPM_LEFTBUTTON|TPM_RIGHTBUTTON, 126 + LOWORD(lp), HIWORD(lp), 0, hwnd(), NULL ); 127 + else 128 + return WndImpl::on_message( msg, wp, lp ); 129 + break; 130 + 131 + // メニューのグレーアウト処理 132 + case WM_INITMENU: 133 + case WM_INITMENUPOPUP: 134 + on_initmenu( reinterpret_cast<HMENU>(wp), msg==WM_INITMENUPOPUP ); 135 + break; 136 + 137 + // D&D 138 + case WM_DROPFILES: 139 + on_drop( reinterpret_cast<HDROP>(wp) ); 140 + break; 141 + 142 + // MRU 143 + case GPM_MRUCHANGED: 144 + SetupMRUMenu(); 145 + break; 146 + 147 + // その他 148 + default: 149 + return WndImpl::on_message( msg, wp, lp ); 150 + } 151 + 152 + return 0; 153 +} 154 + 155 +bool GreenPadWnd::on_command( UINT id, HWND ctrl ) 156 +{ 157 + switch( id ) 158 + { 159 + // Window 160 + case ID_CMD_NEXTWINDOW: on_nextwnd(); break; 161 + case ID_CMD_PREVWINDOW: on_prevwnd(); break; 162 + 163 + // File 164 + case ID_CMD_NEWFILE: on_newfile(); break; 165 + case ID_CMD_OPENFILE: on_openfile(); break; 166 + case ID_CMD_REOPENFILE: on_reopenfile();break; 167 + case ID_CMD_SAVEFILE: on_savefile(); break; 168 + case ID_CMD_SAVEFILEAS: on_savefileas();break; 169 + case ID_CMD_EXIT: on_exit(); break; 170 + 171 + // Edit 172 + case ID_CMD_UNDO: edit_.getDoc().Undo(); break; 173 + case ID_CMD_REDO: edit_.getDoc().Redo(); break; 174 + case ID_CMD_CUT: edit_.getCursor().Cut(); break; 175 + case ID_CMD_COPY: edit_.getCursor().Copy(); break; 176 + case ID_CMD_PASTE: edit_.getCursor().Paste(); break; 177 + case ID_CMD_DELETE: if( edit_.getCursor().isSelected() ) 178 + edit_.getCursor().Del(); break; 179 + case ID_CMD_SELECTALL: edit_.getCursor().Home(true,false); 180 + edit_.getCursor().End(true,true); break; 181 + case ID_CMD_DATETIME: on_datetime(); break; 182 + 183 + // Search 184 + case ID_CMD_FIND: search_.ShowDlg(); break; 185 + case ID_CMD_FINDNEXT: search_.FindNext(); break; 186 + case ID_CMD_FINDPREV: search_.FindPrev(); break; 187 + case ID_CMD_JUMP: on_jump(); break; 188 + case ID_CMD_GREP: on_grep();break; 189 + 190 + // View 191 + case ID_CMD_NOWRAP: edit_.getView().SetWrapType( wrap_=-1 ); break; 192 + case ID_CMD_WRAPWIDTH: edit_.getView().SetWrapType( wrap_=cfg_.wrapWidth() ); break; 193 + case ID_CMD_WRAPWINDOW: edit_.getView().SetWrapType( wrap_=0 ); break; 194 + case ID_CMD_CONFIG: on_config(); break; 195 + case ID_CMD_STATUSBAR: on_statusBar(); break; 196 + 197 + // DocType 198 + default: if( ID_CMD_DOCTYPE <= id ) { 199 + on_doctype( id - ID_CMD_DOCTYPE ); 200 + break; 201 + } else if( ID_CMD_MRU <= id ) { 202 + on_mru( id - ID_CMD_MRU ); 203 + break; 204 + } 205 + 206 + // Default 207 + return false; 208 + } 209 + return true; 210 +} 211 + 212 +bool GreenPadWnd::PreTranslateMessage( MSG* msg ) 213 +{ 214 + // 苦肉の策^^; 215 + if( search_.TrapMsg(msg) ) 216 + return true; 217 + // キーボードショートカット処理 218 + return 0 != ::TranslateAccelerator( hwnd(), accel_, msg ); 219 +} 220 + 221 + 222 + 223 +//------------------------------------------------------------------------- 224 +// コマンド処理 225 +//------------------------------------------------------------------------- 226 + 227 +void GreenPadWnd::on_dirtyflag_change( bool ) 228 +{ 229 + UpdateWindowName(); 230 +} 231 + 232 +void GreenPadWnd::on_newfile() 233 +{ 234 + BootNewProcess(); 235 +} 236 + 237 +void GreenPadWnd::on_openfile() 238 +{ 239 + Path fn; 240 + int cs; 241 + if( ShowOpenDlg( &fn, &cs ) ) 242 + Open( fn, cs ); 243 +} 244 + 245 +void GreenPadWnd::on_reopenfile() 246 +{ 247 + if( !isUntitled() ) 248 + { 249 + ReopenDlg dlg( charSets_, csi_ ); 250 + dlg.GoModal( hwnd() ); 251 + if( dlg.endcode()==IDOK && AskToSave() ) 252 + OpenByMyself( filename_, charSets_[dlg.csi()].ID, false ); 253 + } 254 +} 255 + 256 +void GreenPadWnd::on_savefile() 257 +{ 258 + Save_showDlgIfNeeded(); 259 +} 260 + 261 +void GreenPadWnd::on_savefileas() 262 +{ 263 + if( ShowSaveDlg() ) 264 + { 265 + Save(); 266 + ReloadConfig(); // 文書タイプに応じて表示を更新 267 + } 268 +} 269 + 270 +void GreenPadWnd::on_exit() 271 +{ 272 + search_.SaveToINI( cfg_.getImpl() ); 273 + if( AskToSave() ) 274 + Destroy(); 275 +} 276 + 277 +void GreenPadWnd::on_initmenu( HMENU menu, bool editmenu_only ) 278 +{ 279 + LOGGER("GreenPadWnd::ReloadConfig on_initmenu begin"); 280 + MENUITEMINFO mi = { sizeof(MENUITEMINFO), MIIM_STATE }; 281 + 282 + mi.fState = 283 + (edit_.getCursor().isSelected() ? MFS_ENABLED : MFS_DISABLED); 284 + SetMenuItemInfo( menu, ID_CMD_CUT, FALSE, &mi ); 285 + SetMenuItemInfo( menu, ID_CMD_COPY, FALSE, &mi ); 286 + SetMenuItemInfo( menu, ID_CMD_DELETE, FALSE, &mi ); 287 + 288 + mi.fState = 289 + (edit_.getDoc().isUndoAble() ? MFS_ENABLED : MFS_DISABLED); 290 + SetMenuItemInfo( menu, ID_CMD_UNDO, FALSE, &mi ); 291 + 292 + mi.fState = 293 + (edit_.getDoc().isRedoAble() ? MFS_ENABLED : MFS_DISABLED); 294 + SetMenuItemInfo( menu, ID_CMD_REDO, FALSE, &mi ); 295 + 296 + if( editmenu_only ) 297 + { 298 + LOGGER("GreenPadWnd::ReloadConfig on_initmenu end"); 299 + return; 300 + } 301 + 302 + mi.fState = (isUntitled() || edit_.getDoc().isModified() 303 + ? MFS_ENABLED : MFS_DISABLED); 304 + SetMenuItemInfo( menu, ID_CMD_SAVEFILE, FALSE, &mi ); 305 + 306 + mi.fState = 307 + (!isUntitled() ? MFS_ENABLED : MFS_DISABLED); 308 + SetMenuItemInfo( menu, ID_CMD_REOPENFILE, FALSE, &mi ); 309 + 310 + mi.fState = 311 + (cfg_.grepExe().len()>0 ? MFS_ENABLED : MFS_DISABLED); 312 + SetMenuItemInfo( menu, ID_CMD_GREP, FALSE, &mi ); 313 + 314 + UINT id = (wrap_==-1 ? ID_CMD_NOWRAP 315 + : (wrap_>0 ? ID_CMD_WRAPWIDTH : ID_CMD_WRAPWINDOW)); 316 + ::CheckMenuRadioItem( 317 + menu, ID_CMD_NOWRAP, ID_CMD_WRAPWINDOW, id, MF_BYCOMMAND ); 318 + 319 + ::CheckMenuItem( menu, ID_CMD_STATUSBAR, 320 + cfg_.showStatusBar()?MFS_CHECKED:MFS_UNCHECKED ); 321 + LOGGER("GreenPadWnd::ReloadConfig on_initmenu end"); 322 +} 323 + 324 +void GreenPadWnd::on_drop( HDROP hd ) 325 +{ 326 + UINT iMax = ::DragQueryFile( hd, 0xffffffff, NULL, 0 ); 327 + for( UINT i=0; i<iMax; ++i ) 328 + { 329 + TCHAR str[MAX_PATH]; 330 + ::DragQueryFile( hd, i, str, countof(str) ); 331 + Open( str, AutoDetect ); 332 + } 333 + ::DragFinish( hd ); 334 +} 335 + 336 +void GreenPadWnd::on_jump() 337 +{ 338 + struct JumpDlg : public DlgImpl { 339 + JumpDlg(HWND w) : DlgImpl(IDD_JUMP), w_(w) { GoModal(w); } 340 + void on_init() { 341 + SetCenter(hwnd(),w_); ::SetFocus(item(IDC_LINEBOX)); } 342 + bool on_ok() { 343 + TCHAR str[100]; 344 + ::GetWindowText( item(IDC_LINEBOX), str, countof(str) ); 345 + LineNo = String(str).GetInt(); 346 + return true; 347 + } 348 + int LineNo; HWND w_; 349 + } dlg(hwnd()); 350 + 351 + if( IDOK == dlg.endcode() ) 352 + JumpToLine( dlg.LineNo ); 353 +} 354 + 355 +void GreenPadWnd::on_grep() 356 +{ 357 + Path g = cfg_.grepExe(); 358 + if( g.len() != 0 ) 359 + { 360 + Path d; 361 + if( filename_.len() ) 362 + (d = filename_).BeDirOnly().BeBackSlash(false); 363 + else 364 + d = Path(Path::Cur); 365 + 366 + String fcmd; 367 + for( int i=0, e=g.len(); i<e; ++i ) 368 + if( g[i]==TEXT('%') ) 369 + { 370 + if( g[i+1]==TEXT('1') || g[i+1]==TEXT('D') ) // '1' for bkwd compat 371 + ++i, fcmd += d; 372 + else if( g[i+1]==TEXT('F') ) 373 + ++i, fcmd += filename_; 374 + else if( g[i+1]==TEXT('N') ) 375 + ++i, fcmd += filename_.name(); 376 + } 377 + else 378 + fcmd += g[i]; 379 + 380 + PROCESS_INFORMATION psi; 381 + STARTUPINFO sti = {sizeof(STARTUPINFO)}; 382 + //sti.dwFlags = STARTF_USESHOWWINDOW; 383 + //sti.wShowWindow = SW_SHOWNORMAL; 384 + if( ::CreateProcess( NULL, const_cast<TCHAR*>(fcmd.c_str()), 385 + NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, 386 + &sti, &psi ) ) 387 + { 388 + ::CloseHandle( psi.hThread ); 389 + ::CloseHandle( psi.hProcess ); 390 + } 391 + } 392 +} 393 + 394 +void GreenPadWnd::on_datetime() 395 +{ 396 + TCHAR buf[255], tmp[255]; 397 + ::GetTimeFormat 398 + ( LOCALE_USER_DEFAULT, 0, NULL, TEXT("HH:mm "), buf, countof(buf)); 399 + ::GetDateFormat 400 + ( LOCALE_USER_DEFAULT, 0, NULL, TEXT("yy/MM/dd"),tmp,countof(tmp)); 401 + ::lstrcat( buf, tmp ); 402 + edit_.getCursor().Input( buf, ::lstrlen(buf) ); 403 +} 404 + 405 +void GreenPadWnd::on_doctype( int no ) 406 +{ 407 + if( HMENU m = ::GetSubMenu( ::GetSubMenu(::GetMenu(hwnd()),3),4 ) ) 408 + { 409 + cfg_.SetDocTypeByMenu( no, m ); 410 + ReloadConfig( true ); 411 + } 412 +} 413 + 414 +void GreenPadWnd::on_config() 415 +{ 416 + if( cfg_.DoDialog(*this) ) 417 + { 418 + SetupSubMenu(); 419 + SetupMRUMenu(); 420 + ReloadConfig(false); 421 + } 422 +} 423 + 424 +static inline void MyShowWnd( HWND wnd ) 425 +{ 426 + if( ::IsIconic(wnd) ) 427 + ::ShowWindow( wnd, SW_RESTORE ); 428 + ::BringWindowToTop( wnd ); 429 +} 430 + 431 +void GreenPadWnd::on_nextwnd() 432 +{ 433 + if( HWND next = ::FindWindowEx( NULL, hwnd(), className_, NULL ) ) 434 + { 435 + HWND last=next, pos; 436 + while( last != NULL ) 437 + last = ::FindWindowEx( NULL, pos=last, className_, NULL ); 438 + if( pos != next ) 439 + ::SetWindowPos( hwnd(), pos, 440 + 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW ); 441 + MyShowWnd( next ); 442 + } 443 +} 444 + 445 +void GreenPadWnd::on_prevwnd() 446 +{ 447 + HWND pos=NULL, next=::FindWindowEx( NULL,NULL,className_,NULL ); 448 + if( next==hwnd() ) 449 + { 450 + while( next != NULL ) 451 + next = ::FindWindowEx( NULL,pos=next,className_,NULL ); 452 + if( pos!=hwnd()) 453 + MyShowWnd( pos ); 454 + } 455 + else 456 + { 457 + while( next!=hwnd() && next!=NULL ) 458 + next = ::FindWindowEx( NULL,pos=next,className_,NULL ); 459 + if( next!=NULL ) 460 + MyShowWnd( pos ); 461 + } 462 +} 463 + 464 +void GreenPadWnd::on_statusBar() 465 +{ 466 + stb_.SetStatusBarVisible( !stb_.isStatusBarVisible() ); 467 + cfg_.ShowStatusBarSwitch(); 468 + 469 + WINDOWPLACEMENT wp = {sizeof(wp)}; 470 + ::GetWindowPlacement( hwnd(), &wp ); 471 + if( wp.showCmd != SW_MINIMIZE ) 472 + { 473 + const int ht = stb_.AutoResize( wp.showCmd == SW_MAXIMIZE ); 474 + RECT rc; 475 + getClientRect(&rc); 476 + edit_.MoveTo( 0, 0, rc.right, rc.bottom-ht ); 477 + } 478 +} 479 + 480 +void GreenPadWnd::on_move( const DPos& c, const DPos& s ) 481 +{ 482 + static int busy_cnt = 0; 483 + if( edit_.getDoc().isBusy() && ((++busy_cnt)&0xff) ) 484 + return; 485 + 486 + ulong cad = c.ad; 487 + if( ! cfg_.countByUnicode() ) 488 + { 489 + // ShiftJIS風のByte数カウント 490 + const unicode* cu = edit_.getDoc().tl(c.tl); 491 + const ulong tab = cfg_.vConfig().tabstep; 492 + cad = 0; 493 + for( ulong i=0; i<c.ad; ++i ) 494 + if( cu[i] == L'\t' ) 495 + cad = (cad/tab+1)*tab; 496 + else if( cu[i]<0x80 || 0xff60<=cu[i] && cu[i]<=0xff9f ) 497 + cad = cad + 1; 498 + else 499 + cad = cad + 2; 500 + } 501 + 502 + String str; 503 + str += TEXT('('); 504 + str += String().SetInt(c.tl+1); 505 + str += TEXT(','); 506 + str += String().SetInt(cad+1); 507 + str += TEXT(')'); 508 + if( c != s ) 509 + { 510 + ulong sad = s.ad; 511 + if( ! cfg_.countByUnicode() ) 512 + { 513 + // ShiftJIS風のByte数カウント 514 + const unicode* su = edit_.getDoc().tl(s.tl); 515 + sad = 0; 516 + for( ulong i=0; i<s.ad; ++i ) 517 + sad += (su[i]<0x80 || 0xff60<=su[i] && su[i]<=0xff9f ? 1 : 2); 518 + } 519 + str += TEXT(" - ("); 520 + str += String().SetInt(s.tl+1); 521 + str += TEXT(','); 522 + str += String().SetInt(sad+1); 523 + str += TEXT(')'); 524 + } 525 + stb_.SetText( str.c_str() ); 526 +} 527 + 528 + 529 + 530 +//------------------------------------------------------------------------- 531 +// ユーティリティー 532 +//------------------------------------------------------------------------- 533 + 534 +void GreenPadWnd::JumpToLine( ulong ln ) 535 +{ 536 + edit_.getCursor().MoveCur( DPos(ln-1,0), false ); 537 +} 538 + 539 +void GreenPadWnd::SetupSubMenu() 540 +{ 541 + if( HMENU m = ::GetSubMenu( ::GetSubMenu(::GetMenu(hwnd()),3),4 ) ) 542 + { 543 + cfg_.SetDocTypeMenu( m, ID_CMD_DOCTYPE ); 544 + ::DrawMenuBar( hwnd() ); 545 + } 546 +} 547 + 548 +void GreenPadWnd::UpdateWindowName() 549 +{ 550 + // タイトルバーに表示される文字列の調整 551 + // [FileName *] - GreenPad 552 + String name; 553 + name += TEXT('['); 554 + name += isUntitled() ? TEXT("untitled") : filename_.name(); 555 + if( edit_.getDoc().isModified() ) name += TEXT(" *"); 556 + name += TEXT("] - "); 557 + name += String(IDS_APPNAME).c_str(); 558 + 559 + SetText( name.c_str() ); 560 + stb_.SetCsText( charSets_[csi_].shortName ); 561 + stb_.SetLbText( lb_ ); 562 +} 563 + 564 +void GreenPadWnd::SetupMRUMenu() 565 +{ 566 + if( HMENU m = ::GetSubMenu( ::GetSubMenu(::GetMenu(hwnd()),0),8 ) ) 567 + { 568 + cfg_.SetUpMRUMenu( m, ID_CMD_MRU ); 569 + ::DrawMenuBar( hwnd() ); 570 + } 571 +} 572 + 573 +void GreenPadWnd::on_mru( int no ) 574 +{ 575 + Path fn = cfg_.GetMRU(no); 576 + if( fn.len() != 0 ) 577 + Open( fn, AutoDetect ); 578 +} 579 + 580 + 581 + 582 +//------------------------------------------------------------------------- 583 +// 設定更新処理 584 +//------------------------------------------------------------------------- 585 + 586 +void GreenPadWnd::ReloadConfig( bool noSetDocType ) 587 +{ 588 + // 文書タイプロード 589 + if( !noSetDocType ) 590 + { 591 + int t = cfg_.SetDocType( filename_ ); 592 + if( HMENU m = ::GetSubMenu( ::GetSubMenu(::GetMenu(hwnd()),3),4 ) ) 593 + cfg_.CheckMenu( m, t ); 594 + } 595 + LOGGER("GreenPadWnd::ReloadConfig DocTypeLoaded"); 596 + 597 + // Undo回数制限 598 + edit_.getDoc().SetUndoLimit( cfg_.undoLimit() ); 599 + 600 + // 行番号 601 + bool ln = cfg_.showLN(); 602 + edit_.getView().ShowLineNo( ln ); 603 + 604 + // 折り返し方式 605 + wrap_ = cfg_.wrapType(); 606 + edit_.getView().SetWrapType( wrap_ ); 607 + 608 + // 色・フォント 609 + VConfig vc = cfg_.vConfig(); 610 + edit_.getView().SetFont( vc ); 611 + LOGGER("GreenPadWnd::ReloadConfig ViewConfigLoaded"); 612 + 613 + // キーワードファイル 614 + Path kwd = cfg_.kwdFile(); 615 + FileR fp; 616 + if( kwd.len()!=0 && fp.Open(kwd.c_str()) ) 617 + edit_.getDoc().SetKeyword((const unicode*)fp.base(),fp.size()/2); 618 + else 619 + edit_.getDoc().SetKeyword(NULL,0); 620 + LOGGER("GreenPadWnd::ReloadConfig KeywordLoaded"); 621 +} 622 + 623 + 624 + 625 +//------------------------------------------------------------------------- 626 +// 開く処理 627 +//------------------------------------------------------------------------- 628 + 629 +bool GreenPadWnd::ShowOpenDlg( Path* fn, int* cs ) 630 +{ 631 + // [Open][Cancel] 開くファイル名指定ダイアログを表示 632 + String flst[] = { 633 + String(IDS_TXTFILES), 634 + String(cfg_.txtFileFilter()), 635 + String(IDS_ALLFILES), 636 + String(TEXT("*.*")) 637 + }; 638 + aarr<TCHAR> filt = OpenFileDlg::ConnectWithNull(flst,countof(flst)); 639 + 640 + OpenFileDlg ofd( charSets_ ); 641 + bool ok = ofd.DoModal( hwnd(), filt.get(), filename_.c_str() ); 642 + if( ok ) 643 + { 644 + *fn = ofd.filename(); 645 + *cs = charSets_[ofd.csi()].ID; 646 + } 647 + 648 + return ok; 649 +} 650 + 651 +bool GreenPadWnd::Open( const ki::Path& fn, int cs ) 652 +{ 653 + if( isUntitled() && !edit_.getDoc().isModified() ) 654 + { 655 + // 無題で無変更だったら自分で開く 656 + return OpenByMyself( fn, cs ); 657 + } 658 + else 659 + { 660 + // 同じ窓で開くモードならそうする 661 + if( cfg_.openSame() ) 662 + return ( AskToSave() ? OpenByMyself( fn, cs ) : true ); 663 + 664 + // そうでなければ他へ回す 665 + String 666 + cmd = TEXT("-c"); 667 + cmd += String().SetInt( cs ); 668 + cmd += TEXT(" \""); 669 + cmd += fn; 670 + cmd += TEXT('\"'); 671 + BootNewProcess( cmd.c_str() ); 672 + return true; 673 + } 674 +} 675 + 676 +bool GreenPadWnd::OpenByMyself( const ki::Path& fn, int cs, bool needReConf ) 677 +{ 678 + // ファイルを開けなかったらそこでおしまい。 679 + aptr<TextFileR> tf( new TextFileR(cs) ); 680 + if( !tf->Open( fn.c_str() ) ) 681 + { 682 + // ERROR! 683 + MsgBox( String(IDS_OPENERROR).c_str() ); 684 + return false; 685 + } 686 + 687 + // 自分内部の管理情報を更新 688 + if( fn[0]==TEXT('\\') || fn[1]==TEXT(':') ) 689 + filename_ = fn; 690 + else 691 + filename_ = Path( Path::Cur ) + fn; 692 + if( tf->size() ) 693 + { 694 + csi_ = charSets_.findCsi( tf->codepage() ); 695 + if( tf->nolb_found() ) 696 + lb_ = cfg_.GetNewfileLB(); 697 + else 698 + lb_ = tf->linebreak(); 699 + } 700 + else 701 + { // 空ファイルの場合は新規作成と同じ扱い 702 + csi_ = cfg_.GetNewfileCsi(); 703 + lb_ = cfg_.GetNewfileLB(); 704 + } 705 + filename_.BeShortLongStyle(); 706 + 707 + // カレントディレクトリを、ファイルのある位置以外にしておく 708 + // (こうしないと、開いているファイルのあるディレクトリが削除できない) 709 + ::SetCurrentDirectory( Path(filename_).BeDriveOnly().c_str() ); 710 + 711 + // 文書タイプに応じて表示を更新 712 + if( needReConf ) 713 + ReloadConfig(); 714 + 715 + // 開く 716 + edit_.getDoc().ClearAll(); 717 + edit_.getDoc().OpenFile( tf ); 718 + 719 + // タイトルバー更新 720 + UpdateWindowName(); 721 + 722 + // [最近使ったファイル]へ追加 723 + cfg_.AddMRU( filename_ ); 724 + HWND wnd = NULL; 725 + while( NULL!=(wnd=::FindWindowEx( NULL, wnd, className_, NULL )) ) 726 + SendMessage( wnd, GPM_MRUCHANGED, 0, 0 ); 727 + 728 + return true; 729 +} 730 + 731 + 732 + 733 +//------------------------------------------------------------------------- 734 +// 保存処理 735 +//------------------------------------------------------------------------- 736 + 737 +bool GreenPadWnd::ShowSaveDlg() 738 +{ 739 + // [Save][Cancel] 保存先ファイル名指定ダイアログを表示 740 + 741 + String flst[] = { 742 + String(IDS_ALLFILES), 743 + String(TEXT("*.*")) 744 + }; 745 + aarr<TCHAR> filt = SaveFileDlg::ConnectWithNull( flst, countof(flst) ); 746 + 747 + SaveFileDlg sfd( charSets_, csi_, lb_ ); 748 + if( !sfd.DoModal( hwnd(), filt.get(), filename_.c_str() ) ) 749 + return false; 750 + 751 + filename_ = sfd.filename(); 752 + csi_ = sfd.csi(); 753 + lb_ = sfd.lb(); 754 + 755 + return true; 756 +} 757 + 758 +bool GreenPadWnd::Save_showDlgIfNeeded() 759 +{ 760 + bool wasUntitled = isUntitled(); 761 + 762 + // [Save][Cancel] ファイル名未定ならダイアログ表示 763 + if( isUntitled() ) 764 + if( !ShowSaveDlg() ) 765 + return false; 766 + if( Save() ) 767 + { 768 + if( wasUntitled ) 769 + ReloadConfig(); // 文書タイプに応じて表示を更新 770 + return true; 771 + } 772 + return false; 773 +} 774 + 775 +bool GreenPadWnd::AskToSave() 776 +{ 777 + // 変更されていたら、 778 + // [Yes][No][Cancel] 保存するかどうか尋ねる。 779 + // 保存するなら 780 + // [Save][Cancel] ファイル名未定ならダイアログ表示 781 + 782 + if( edit_.getDoc().isModified() ) 783 + { 784 + int answer = MsgBox( 785 + String(IDS_ASKTOSAVE).c_str(), 786 + String(IDS_APPNAME).c_str(), 787 + MB_YESNOCANCEL|MB_ICONQUESTION 788 + ); 789 + if( answer == IDYES ) return Save_showDlgIfNeeded(); 790 + if( answer == IDCANCEL ) return false; 791 + } 792 + return true; 793 +} 794 + 795 +bool GreenPadWnd::Save() 796 +{ 797 + TextFileW tf( charSets_[csi_].ID, lb_ ); 798 + if( tf.Open( filename_.c_str() ) ) 799 + { 800 + // 無事ファイルに保存できた場合 801 + edit_.getDoc().SaveFile( tf ); 802 + UpdateWindowName(); 803 + // [最近使ったファイル]更新 804 + cfg_.AddMRU( filename_ ); 805 + HWND wnd = NULL; 806 + while( NULL!=(wnd=::FindWindowEx( NULL, wnd, className_, NULL )) ) 807 + SendMessage( wnd, GPM_MRUCHANGED, 0, 0 ); 808 + return true; 809 + } 810 + 811 + // Error! 812 + MsgBox( String(IDS_SAVEERROR).c_str() ); 813 + return false; 814 +} 815 + 816 + 817 + 818 +//------------------------------------------------------------------------- 819 +// メインウインドウの初期化 820 +//------------------------------------------------------------------------- 821 + 822 +GreenPadWnd::ClsName GreenPadWnd::className_ = TEXT("GreenPad MainWnd"); 823 + 824 +GreenPadWnd::GreenPadWnd() 825 + : WndImpl ( className_, WS_OVERLAPPEDWINDOW, WS_EX_ACCEPTFILES ) 826 + , charSets_( cfg_.GetCharSetList() ) 827 + , csi_ ( cfg_.GetNewfileCsi() ) 828 + , lb_ ( cfg_.GetNewfileLB() ) 829 + , search_ ( *this, edit_ ) 830 +{ 831 + LOGGER( "GreenPadWnd::Construct begin" ); 832 + 833 + static WNDCLASSEX wc; 834 + wc.hIcon = app().LoadIcon( IDR_MAIN ); 835 + wc.hCursor = app().LoadOemCursor( IDC_ARROW ); 836 + wc.lpszMenuName = MAKEINTRESOURCE( IDR_MAIN ); 837 + wc.lpszClassName = className_; 838 + WndImpl::Register( &wc ); 839 + 840 + ime().EnableGlobalIME( true ); 841 + 842 + LOGGER( "GreenPadWnd::Construct end" ); 843 +} 844 + 845 +void GreenPadWnd::on_create( CREATESTRUCT* cs ) 846 +{ 847 + LOGGER("GreenPadWnd::on_create begin"); 848 + 849 + accel_ = app().LoadAccel( IDR_MAIN ); 850 + stb_.Create( hwnd() ); 851 + edit_.Create( NULL, hwnd(), 0, 0, 100, 100 ); 852 + LOGGER("GreenPadWnd::on_create edit created"); 853 + edit_.getDoc().AddHandler( this ); 854 + edit_.getCursor().AddHandler( this ); 855 + stb_.SetStatusBarVisible( cfg_.showStatusBar() ); 856 + 857 + LOGGER("GreenPadWnd::on_create halfway"); 858 + 859 + search_.LoadFromINI( cfg_.getImpl() ); 860 + SetupSubMenu(); 861 + SetupMRUMenu(); 862 + 863 + LOGGER("GreenPadWnd::on_create menu"); 864 +} 865 + 866 +bool GreenPadWnd::StartUp( const Path& fn, int cs, int ln ) 867 +{ 868 + LOGGER( "GreenPadWnd::StartUp begin" ); 869 + Create( 0, 0, cfg_.GetWndX(), cfg_.GetWndY(), cfg_.GetWndW(), cfg_.GetWndH(), 0 ); 870 + LOGGER( "GreenPadWnd::Created" ); 871 + if( fn.len()==0 || !OpenByMyself( fn, cs ) ) 872 + { 873 + LOGGER( "for new file..." ); 874 + 875 + // ファイルを開か(け)なかった場合 876 + ReloadConfig( fn.len()==0 ); 877 + LOGGER( "GreenPadWnd::StartUp reloadconfig end" ); 878 + UpdateWindowName(); 879 + LOGGER( "GreenPadWnd::StartUp updatewindowname end" ); 880 + } 881 + 882 + // 指定の行へジャンプ 883 + if( ln != -1 ) 884 + JumpToLine( ln ); 885 + 886 + LOGGER( "GreenPadWnd::StartUp end" ); 887 + return true; 888 +} 889 + 890 +void GreenPadWnd::ShowUp2() 891 +{ 892 + Window::ShowUp( cfg_.GetWndM() ? SW_MAXIMIZE : SW_SHOW ); 893 +} 894 + 895 + 896 +//------------------------------------------------------------------------- 897 +// スタートアップルーチン 898 +// コマンドラインの解析を行う 899 +//------------------------------------------------------------------------- 900 + 901 +int kmain() 902 +{ 903 + LOGGER( "kmain() begin" ); 904 + 905 + Argv arg; 906 + ulong i; 907 + 908 + LOGGER( "argv processed" ); 909 + 910 + //-- まずオプションスイッチを処理 911 + 912 + int optL = -1; 913 + int optC = 0; 914 + 915 + for( i=1; i<arg.size() && arg[i][0]==TEXT('-'); ++i ) 916 + switch( arg[i][1] ) 917 + { 918 + case TEXT('c'): 919 + optC = String::GetInt( arg[i]+2 ); 920 + break; 921 + case TEXT('l'): 922 + optL = String::GetInt( arg[i]+2 ); 923 + break; 924 + } 925 + 926 + LOGGER( "option processed" ); 927 + 928 + //-- 次にファイル名 929 + 930 + Path file; 931 + 932 + if( i < arg.size() ) 933 + { 934 + file = arg[i]; 935 + if( !file.isFile() ) 936 + { 937 + ulong j; // ""無しで半スペ入りでもそれなりに対処 938 + for( j=i+1; j<arg.size(); ++j ) 939 + { 940 + file += ' '; 941 + file += arg[j]; 942 + if( file.isFile() ) 943 + break; 944 + } 945 + 946 + if( j==arg.size() ) 947 + file = arg[i]; 948 + else 949 + i=j; 950 + } 951 + } 952 + 953 + LOGGER( "filename processed" ); 954 + 955 + //-- 余ってる引数があれば、それで新規プロセス起動 956 + 957 + if( ++i < arg.size() ) 958 + { 959 + String cmd; 960 + for( ; i<arg.size(); ++i ) 961 + { 962 + cmd += TEXT('\"'); 963 + cmd += arg[i]; 964 + cmd += TEXT("\" "); 965 + } 966 + ::BootNewProcess( cmd.c_str() ); 967 + } 968 + 969 + LOGGER( "newprocess booted" ); 970 + 971 + //-- メインウインドウ発進 972 + 973 + GreenPadWnd wnd; 974 + if( !wnd.StartUp(file,optC,optL) ) 975 + return -1; 976 + 977 + LOGGER( "kmain() startup ok" ); 978 + 979 + //-- メインループ 980 + 981 + wnd.ShowUp2(); 982 + LOGGER( "showup!" ); 983 + wnd.MsgLoop(); 984 + 985 + LOGGER( "fin" ); 986 + return 0; 987 +}
Added GpMain.h version [fb5b8d0bd744fed9]
1 +#ifndef _GREENPAD_MAIN_H_ 2 +#define _GREENPAD_MAIN_H_ 3 +#include "kilib/kilib.h" 4 +#include "editwing/editwing.h" 5 +#include "OpenSaveDlg.h" 6 +#include "ConfigManager.h" 7 +#include "Search.h" 8 + 9 + 10 + 11 +//========================================================================= 12 +//@{ @pkg Gp.Main //@} 13 +//@{ 14 +// ステータスバー 15 +//@} 16 +//========================================================================= 17 + 18 +class GpStBar : public ki::StatusBar 19 +{ 20 +public: 21 + GpStBar(); 22 + int AutoResize( bool maximized ); 23 + void SetCsText( const TCHAR* str ); 24 + void SetLbText( int lb ); 25 +private: 26 + const TCHAR *str_; 27 + int lb_; 28 +}; 29 + 30 + 31 + 32 +//========================================================================= 33 +//@{ 34 +// メインウインドウ 35 +//@} 36 +//========================================================================= 37 + 38 +class GreenPadWnd 39 + : public ki::WndImpl 40 + , public editwing::doc::DocEvHandler 41 + , public editwing::view::CurEvHandler 42 +{ 43 +public: 44 + 45 + GreenPadWnd(); 46 + bool StartUp( const ki::Path& fn, int cs, int ln ); 47 + void ShowUp2(); 48 + 49 +private: 50 + 51 + void UpdateWindowName(); 52 + void ReloadConfig( bool noSetDocType=false ); 53 + 54 + bool ShowOpenDlg( ki::Path* fn, int* cs ); 55 + bool Open( const ki::Path& fn, int cs ); 56 + bool OpenByMyself( const ki::Path& fn, int cs, bool needReConf=true ); 57 + 58 + bool AskToSave(); 59 + bool Save_showDlgIfNeeded(); 60 + bool ShowSaveDlg(); 61 + bool Save(); 62 + 63 + void JumpToLine( ulong ln ); 64 + void SetupSubMenu(); 65 + void SetupMRUMenu(); 66 + 67 +private: 68 + 69 + bool isUntitled() const { return filename_.len()==0; } 70 + 71 +private: 72 + 73 + ConfigManager cfg_; 74 + SearchManager search_; 75 + CharSetList& charSets_; 76 + 77 + editwing::EwEdit edit_; 78 + GpStBar stb_; 79 + HACCEL accel_; 80 + 81 + ki::Path filename_; 82 + int csi_; 83 + int lb_; 84 + int wrap_; 85 + 86 + static ClsName className_; 87 + 88 +private: 89 + 90 + void on_create( CREATESTRUCT* cs ); 91 + LRESULT on_message( UINT msg, WPARAM wp, LPARAM lp ); 92 + bool on_command( UINT id, HWND ctrl ); 93 + void on_newfile(); 94 + void on_openfile(); 95 + void on_reopenfile(); 96 + void on_savefile(); 97 + void on_savefileas(); 98 + void on_exit(); 99 + void on_initmenu( HMENU menu, bool editmenu_only ); 100 + void on_drop( HDROP hd ); 101 + void on_dirtyflag_change( bool ); 102 + void on_move( const editwing::DPos& c, const editwing::DPos& s ); 103 + void on_jump(); 104 + void on_grep(); 105 + void on_config(); 106 + void on_datetime(); 107 + void on_doctype( int no ); 108 + void on_nextwnd(); 109 + void on_prevwnd(); 110 + void on_mru( int no ); 111 + void on_statusBar(); 112 + bool PreTranslateMessage( MSG* msg ); 113 +}; 114 + 115 + 116 + 117 +//========================================================================= 118 + 119 +#endif // _GREENPAD_MAIN_H_
Added Makefile version [c13aa34ac2a18a0a]
1 + 2 +message: 3 + -@echo Specify one of the following toolset as the target of make: 4 + -@echo make gcc (for MinGW) 5 + -@echo make dmc (for DigitalMars C++) 6 + -@echo make bcc (for Borland C++ Compilers) 7 + -@echo make vcc (for Microsoft Visual C++) 8 + -@echo Please make sure that the "make" program you're using is 9 + -@echo the one from the toolset. 10 + -@echo (GNU make for gcc, nmake for vcc, ... etc.) 11 + 12 +clean: 13 + -@rmdir /Q /S obj 2> nul 14 + -@del /Q release\*.exe 2> nul 15 + 16 +############################################################################ 17 + 18 +DMAK = make# Hey, why no $(MAKE)???? 19 + 20 +gcc: 21 + $(MAKE) -f Makefiles/gcc.mak 22 +dmc: 23 + $(DMAK) -f Makefiles/dmc.mak 24 +vcc: 25 + $(MAKE) -f Makefiles/vcc.mak 26 +bcc: 27 + $(MAKE) -f Makefiles/bcc.mak
Added Makefiles/bcc.mak version [54eb14d0be4ff787]
1 +NAME = bcc 2 +OBJ_SUFFIX = obj 3 + 4 +############################################################################### 5 +TARGET = release\GreenPad_$(NAME).exe 6 +INTDIR = obj\$(NAME) 7 + 8 +all: PRE $(TARGET) 9 + 10 +OBJS = \ 11 + $(INTDIR)\thread.$(OBJ_SUFFIX) \ 12 + $(INTDIR)\log.$(OBJ_SUFFIX) \ 13 + $(INTDIR)\winutil.$(OBJ_SUFFIX) \ 14 + $(INTDIR)\textfile.$(OBJ_SUFFIX) \ 15 + $(INTDIR)\path.$(OBJ_SUFFIX) \ 16 + $(INTDIR)\cmdarg.$(OBJ_SUFFIX) \ 17 + $(INTDIR)\file.$(OBJ_SUFFIX) \ 18 + $(INTDIR)\find.$(OBJ_SUFFIX) \ 19 + $(INTDIR)\ctrl.$(OBJ_SUFFIX) \ 20 + $(INTDIR)\registry.$(OBJ_SUFFIX) \ 21 + $(INTDIR)\window.$(OBJ_SUFFIX) \ 22 + $(INTDIR)\string.$(OBJ_SUFFIX) \ 23 + $(INTDIR)\memory.$(OBJ_SUFFIX) \ 24 + $(INTDIR)\app.$(OBJ_SUFFIX) \ 25 + $(INTDIR)\ip_cursor.$(OBJ_SUFFIX) \ 26 + $(INTDIR)\ip_scroll.$(OBJ_SUFFIX) \ 27 + $(INTDIR)\ip_wrap.$(OBJ_SUFFIX) \ 28 + $(INTDIR)\ip_draw.$(OBJ_SUFFIX) \ 29 + $(INTDIR)\ip_ctrl1.$(OBJ_SUFFIX) \ 30 + $(INTDIR)\ip_text.$(OBJ_SUFFIX) \ 31 + $(INTDIR)\ip_parse.$(OBJ_SUFFIX) \ 32 + $(INTDIR)\GpMain.$(OBJ_SUFFIX) \ 33 + $(INTDIR)\OpenSaveDlg.$(OBJ_SUFFIX) \ 34 + $(INTDIR)\Search.$(OBJ_SUFFIX) \ 35 + $(INTDIR)\RSearch.$(OBJ_SUFFIX) \ 36 + $(INTDIR)\ConfigManager.$(OBJ_SUFFIX) 37 + 38 +LIBS = \ 39 + kernel32.lib \ 40 + user32.lib \ 41 + gdi32.lib \ 42 + shell32.lib \ 43 + advapi32.lib \ 44 + comdlg32.lib \ 45 + comctl32.lib \ 46 + ole32.lib \ 47 + imm32.lib 48 + 49 +PRE: 50 + -@if not exist release mkdir release 51 + -@if not exist obj mkdir obj 52 + -@if not exist $(INTDIR) mkdir $(INTDIR) 53 +############################################################################### 54 + 55 +RES = $(INTDIR)\gp_rsrc.res 56 + 57 +.autodepend 58 +.path.cpp = .;kilib;editwing 59 +.path.rc = rsrc 60 + 61 +COPT = -c -W -AT -d -O -O1 -Oc -Oi -Ov -x- -RT- -Ve -VM -w-par -w-inl -w-pia -H=$(INTDIR)\stdafx.pch -Hh=stdafx.h 62 +LOPT = -aa -Tpe -x -Iobj\bcc -w-rty 63 +ROPT = -m -c932 -l0x411 64 + 65 +$(TARGET): $(OBJS) $(RES) 66 + @ilink32 $(LOPT) c0w32.obj $(OBJS), $@,, cw32.lib import32.lib,, $(RES) 67 + -@del release\GreenPad_bcc.tds 68 + 69 +.rc.res: 70 + @brcc32 $(ROPT) -fo$@ $< 71 + 72 +.cpp.obj: 73 + @bcc32 $(COPT) -o$@ $<
Added Makefiles/dmc.mak version [2c6c5918e3b50bf5]
1 +NAME = dmc 2 +OBJ_SUFFIX = obj 3 + 4 +############################################################################### 5 +TARGET = release\GreenPad_$(NAME).exe 6 +INTDIR = obj\$(NAME) 7 + 8 +all: PRE $(TARGET) 9 + 10 +OBJS = \ 11 + $(INTDIR)\thread.$(OBJ_SUFFIX) \ 12 + $(INTDIR)\log.$(OBJ_SUFFIX) \ 13 + $(INTDIR)\winutil.$(OBJ_SUFFIX) \ 14 + $(INTDIR)\textfile.$(OBJ_SUFFIX) \ 15 + $(INTDIR)\path.$(OBJ_SUFFIX) \ 16 + $(INTDIR)\cmdarg.$(OBJ_SUFFIX) \ 17 + $(INTDIR)\file.$(OBJ_SUFFIX) \ 18 + $(INTDIR)\find.$(OBJ_SUFFIX) \ 19 + $(INTDIR)\ctrl.$(OBJ_SUFFIX) \ 20 + $(INTDIR)\registry.$(OBJ_SUFFIX) \ 21 + $(INTDIR)\window.$(OBJ_SUFFIX) \ 22 + $(INTDIR)\string.$(OBJ_SUFFIX) \ 23 + $(INTDIR)\memory.$(OBJ_SUFFIX) \ 24 + $(INTDIR)\app.$(OBJ_SUFFIX) \ 25 + $(INTDIR)\ip_cursor.$(OBJ_SUFFIX) \ 26 + $(INTDIR)\ip_scroll.$(OBJ_SUFFIX) \ 27 + $(INTDIR)\ip_wrap.$(OBJ_SUFFIX) \ 28 + $(INTDIR)\ip_draw.$(OBJ_SUFFIX) \ 29 + $(INTDIR)\ip_ctrl1.$(OBJ_SUFFIX) \ 30 + $(INTDIR)\ip_text.$(OBJ_SUFFIX) \ 31 + $(INTDIR)\ip_parse.$(OBJ_SUFFIX) \ 32 + $(INTDIR)\GpMain.$(OBJ_SUFFIX) \ 33 + $(INTDIR)\OpenSaveDlg.$(OBJ_SUFFIX) \ 34 + $(INTDIR)\Search.$(OBJ_SUFFIX) \ 35 + $(INTDIR)\RSearch.$(OBJ_SUFFIX) \ 36 + $(INTDIR)\ConfigManager.$(OBJ_SUFFIX) 37 + 38 +LIBS = \ 39 + kernel32.lib \ 40 + user32.lib \ 41 + gdi32.lib \ 42 + shell32.lib \ 43 + advapi32.lib \ 44 + comdlg32.lib \ 45 + comctl32.lib \ 46 + ole32.lib \ 47 + imm32.lib 48 + 49 +PRE: 50 + -@if not exist release mkdir release 51 + -@if not exist obj mkdir obj 52 + -@if not exist $(INTDIR) mkdir $(INTDIR) 53 +############################################################################### 54 + 55 +RC = rsrc\gp_rsrc.rc 56 +RES = $(INTDIR)\gp_rsrc.res 57 + 58 +COPT = -Bj -j0 -Ab -w2 -w7 -o -c 59 +LOPT = -Bj -mn -WA -L/su:Windows:4.0/exet:NT/onerror:noexe 60 +ROPT = -j -32 -l0411 61 + 62 +$(TARGET) : SETI $(OBJS) $(RES) 63 + dmc $(LOPT) -o$(TARGET) $(RES) $(OBJS) $(LIBS) 64 + -@del GreenPad_dmc.map 65 + brc32 $(RES) $(TARGET) 66 +SETI: 67 + @set INCLUDE=kilib;$(INCLUDE) 68 + 69 +OBJ\dmc\gp_rsrc.res : rsrc\gp_rsrc.rc ; brcc32 -m -c932 -l0x411 -fo$@ $** 70 +OBJ\dmc\thread.obj : kilib\thread.cpp ; dmc $(COPT) -o$@ $** 71 +OBJ\dmc\log.obj : kilib\log.cpp ; dmc $(COPT) -o$@ $** 72 +OBJ\dmc\winutil.obj : kilib\winutil.cpp ; dmc $(COPT) -o$@ $** 73 +OBJ\dmc\textfile.obj : kilib\textfile.cpp ; dmc $(COPT) -o$@ $** 74 +OBJ\dmc\path.obj : kilib\path.cpp ; dmc $(COPT) -o$@ $** 75 +OBJ\dmc\cmdarg.obj : kilib\cmdarg.cpp ; dmc $(COPT) -o$@ $** 76 +OBJ\dmc\file.obj : kilib\file.cpp ; dmc $(COPT) -o$@ $** 77 +OBJ\dmc\find.obj : kilib\find.cpp ; dmc $(COPT) -o$@ $** 78 +OBJ\dmc\ctrl.obj : kilib\ctrl.cpp ; dmc $(COPT) -o$@ $** 79 +OBJ\dmc\registry.obj : kilib\registry.cpp ; dmc $(COPT) -o$@ $** 80 +OBJ\dmc\window.obj : kilib\window.cpp ; dmc $(COPT) -o$@ $** 81 +OBJ\dmc\string.obj : kilib\string.cpp ; dmc $(COPT) -o$@ $** 82 +OBJ\dmc\memory.obj : kilib\memory.cpp ; dmc $(COPT) -o$@ $** 83 +OBJ\dmc\app.obj : kilib\app.cpp ; dmc $(COPT) -o$@ $** 84 +OBJ\dmc\ip_cursor.obj : editwing\ip_cursor.cpp ; dmc $(COPT) -o$@ $** 85 +OBJ\dmc\ip_scroll.obj : editwing\ip_scroll.cpp ; dmc $(COPT) -o$@ $** 86 +OBJ\dmc\ip_wrap.obj : editwing\ip_wrap.cpp ; dmc $(COPT) -o$@ $** 87 +OBJ\dmc\ip_draw.obj : editwing\ip_draw.cpp ; dmc $(COPT) -o$@ $** 88 +OBJ\dmc\ip_ctrl1.obj : editwing\ip_ctrl1.cpp ; dmc $(COPT) -o$@ $** 89 +OBJ\dmc\ip_text.obj : editwing\ip_text.cpp ; dmc $(COPT) -o$@ $** 90 +OBJ\dmc\ip_parse.obj : editwing\ip_parse.cpp ; dmc $(COPT) -o$@ $** 91 +OBJ\dmc\GpMain.obj : GpMain.cpp ; dmc $(COPT) -o$@ $** 92 +OBJ\dmc\OpenSaveDlg.obj : OpenSaveDlg.cpp ; dmc $(COPT) -o$@ $** 93 +OBJ\dmc\Search.obj : Search.cpp ; dmc $(COPT) -o$@ $** 94 +OBJ\dmc\RSearch.obj : RSearch.cpp ; dmc $(COPT) -o$@ $** 95 +OBJ\dmc\ConfigManager.obj : ConfigManager.cpp ; dmc $(COPT) -o$@ $**
Added Makefiles/gcc.mak version [3e8f853ea6204f83]
1 + 2 +NAME = gcc 3 +OBJ_SUFFIX = o 4 + 5 +############################################################################### 6 +TARGET = release/GreenPad_$(NAME).exe 7 +INTDIR = obj\$(NAME) 8 + 9 +all: PRE $(TARGET) 10 + 11 +OBJS = \ 12 + $(INTDIR)/thread.$(OBJ_SUFFIX) \ 13 + $(INTDIR)/log.$(OBJ_SUFFIX) \ 14 + $(INTDIR)/winutil.$(OBJ_SUFFIX) \ 15 + $(INTDIR)/textfile.$(OBJ_SUFFIX) \ 16 + $(INTDIR)/path.$(OBJ_SUFFIX) \ 17 + $(INTDIR)/cmdarg.$(OBJ_SUFFIX) \ 18 + $(INTDIR)/file.$(OBJ_SUFFIX) \ 19 + $(INTDIR)/find.$(OBJ_SUFFIX) \ 20 + $(INTDIR)/ctrl.$(OBJ_SUFFIX) \ 21 + $(INTDIR)/registry.$(OBJ_SUFFIX) \ 22 + $(INTDIR)/window.$(OBJ_SUFFIX) \ 23 + $(INTDIR)/string.$(OBJ_SUFFIX) \ 24 + $(INTDIR)/memory.$(OBJ_SUFFIX) \ 25 + $(INTDIR)/app.$(OBJ_SUFFIX) \ 26 + $(INTDIR)/ip_cursor.$(OBJ_SUFFIX) \ 27 + $(INTDIR)/ip_scroll.$(OBJ_SUFFIX) \ 28 + $(INTDIR)/ip_wrap.$(OBJ_SUFFIX) \ 29 + $(INTDIR)/ip_draw.$(OBJ_SUFFIX) \ 30 + $(INTDIR)/ip_ctrl1.$(OBJ_SUFFIX) \ 31 + $(INTDIR)/ip_text.$(OBJ_SUFFIX) \ 32 + $(INTDIR)/ip_parse.$(OBJ_SUFFIX) \ 33 + $(INTDIR)/GpMain.$(OBJ_SUFFIX) \ 34 + $(INTDIR)/OpenSaveDlg.$(OBJ_SUFFIX) \ 35 + $(INTDIR)/Search.$(OBJ_SUFFIX) \ 36 + $(INTDIR)/RSearch.$(OBJ_SUFFIX) \ 37 + $(INTDIR)/ConfigManager.$(OBJ_SUFFIX) 38 + 39 +LIBS = \ 40 + -lkernel32 \ 41 + -luser32 \ 42 + -lgdi32 \ 43 + -lshell32 \ 44 + -ladvapi32 \ 45 + -lcomdlg32 \ 46 + -lcomctl32 \ 47 + -lole32 \ 48 + -limm32 49 + 50 +PRE: 51 + -@if not exist release mkdir release 52 + -@if not exist obj mkdir obj 53 + -@if not exist $(INTDIR) mkdir $(INTDIR) 54 +############################################################################### 55 + 56 +RES = $(INTDIR)/gp_rsrc.o 57 + 58 +VPATH = editwing:kilib 59 +CXXFLAGS = -mno-cygwin -O2 -idirafter kilib -c --input-charset=cp932 60 +LOPT = -mwindows -mno-cygwin 61 + 62 +$(TARGET) : $(OBJS) $(RES) 63 + g++ $(LOPT) -o$(TARGET) $(OBJS) $(RES) $(LIBS) 64 + strip -s $(TARGET) 65 +$(INTDIR)/%.o: rsrc/%.rc 66 + windres -l=0x411 -I rsrc $< $@ 67 +$(INTDIR)/%.o: %.cpp 68 + g++ $(CXXFLAGS) -o$@ $<
Added Makefiles/vcc.mak version [50fae54bd44a5597]
1 +NAME = vcc 2 +OBJ_SUFFIX = obj 3 + 4 +############################################################################### 5 +TARGET = release\GreenPad_$(NAME).exe 6 +INTDIR = obj\$(NAME) 7 + 8 +all: PRE $(TARGET) 9 + 10 +OBJS = \ 11 + $(INTDIR)\thread.$(OBJ_SUFFIX) \ 12 + $(INTDIR)\log.$(OBJ_SUFFIX) \ 13 + $(INTDIR)\winutil.$(OBJ_SUFFIX) \ 14 + $(INTDIR)\textfile.$(OBJ_SUFFIX) \ 15 + $(INTDIR)\path.$(OBJ_SUFFIX) \ 16 + $(INTDIR)\cmdarg.$(OBJ_SUFFIX) \ 17 + $(INTDIR)\file.$(OBJ_SUFFIX) \ 18 + $(INTDIR)\find.$(OBJ_SUFFIX) \ 19 + $(INTDIR)\ctrl.$(OBJ_SUFFIX) \ 20 + $(INTDIR)\registry.$(OBJ_SUFFIX) \ 21 + $(INTDIR)\window.$(OBJ_SUFFIX) \ 22 + $(INTDIR)\string.$(OBJ_SUFFIX) \ 23 + $(INTDIR)\memory.$(OBJ_SUFFIX) \ 24 + $(INTDIR)\app.$(OBJ_SUFFIX) \ 25 + $(INTDIR)\ip_cursor.$(OBJ_SUFFIX) \ 26 + $(INTDIR)\ip_scroll.$(OBJ_SUFFIX) \ 27 + $(INTDIR)\ip_wrap.$(OBJ_SUFFIX) \ 28 + $(INTDIR)\ip_draw.$(OBJ_SUFFIX) \ 29 + $(INTDIR)\ip_ctrl1.$(OBJ_SUFFIX) \ 30 + $(INTDIR)\ip_text.$(OBJ_SUFFIX) \ 31 + $(INTDIR)\ip_parse.$(OBJ_SUFFIX) \ 32 + $(INTDIR)\GpMain.$(OBJ_SUFFIX) \ 33 + $(INTDIR)\OpenSaveDlg.$(OBJ_SUFFIX) \ 34 + $(INTDIR)\Search.$(OBJ_SUFFIX) \ 35 + $(INTDIR)\RSearch.$(OBJ_SUFFIX) \ 36 + $(INTDIR)\ConfigManager.$(OBJ_SUFFIX) 37 + 38 +LIBS = \ 39 + kernel32.lib \ 40 + user32.lib \ 41 + gdi32.lib \ 42 + shell32.lib \ 43 + advapi32.lib \ 44 + comdlg32.lib \ 45 + comctl32.lib \ 46 + ole32.lib \ 47 + imm32.lib 48 + 49 +PRE: 50 + -@if not exist release mkdir release 51 + -@if not exist obj mkdir obj 52 + -@if not exist $(INTDIR) mkdir $(INTDIR) 53 +############################################################################### 54 + 55 +RES = $(INTDIR)\gp_rsrc.res 56 +PCH = $(INTDIR)\gp.pch 57 +DEF = /D NDEBUG /D UNICODE /D _UNICODE /D USEGLOBALIME 58 + 59 +COPT = /nologo $(DEF) /O1isyb1 /GA /GF /FD /Zc:wchar_t /Yu"stdafx.h" /Fp$(PCH) /Fd$(INTDIR) /W3 /MT /c 60 +LOPT = /nologo /manifest:no bufferoverflowU.lib 61 +ROPT = $(DEF) /L 0x411 /I "rsrc" 62 + 63 +$(TARGET): PRE $(PCH) $(OBJS) $(RES) 64 + link $(LOPT) /OUT:$(TARGET) $(OBJS) $(RES) $(LIBS) 65 + 66 +{rsrc}.rc{$(INTDIR)}.res: 67 + rc $(ROPT) /Fo$@ $** 68 + 69 +{.}.cpp{$(INTDIR)}.obj: 70 + cl $(COPT) /Fo$@ $** 71 +{kilib}.cpp{$(INTDIR)}.obj: 72 + cl $(COPT) /Fo$@ $** 73 +{editwing}.cpp{$(INTDIR)}.obj: 74 + cl $(COPT) /Fo$@ $** 75 +$(PCH): kilib\stdafx.cpp 76 + cl $(COPT) /Fo$(INTDIR)\stdafx.obj /Yc"stdafx.h" $**
Added NSearch.h version [b90c4013c91b1e31]
1 +#ifndef AFX_NSEARCH_H__8336E133_90C5_4059_8605_6066BD37D042__INCLUDED_ 2 +#define AFX_NSEARCH_H__8336E133_90C5_4059_8605_6066BD37D042__INCLUDED_ 3 +#include "Search.h" 4 + 5 + 6 + 7 +//========================================================================= 8 +//@{ @pkg Gp.Search //@} 9 +// BM法検索用ポリシーs 10 +//========================================================================= 11 + 12 +//@{ 大文字小文字を区別するポリシー //@} 13 +struct CaseSensitive 14 +{ 15 + static unicode map( unicode c ) 16 + { return c; } 17 + static bool not_equal( unicode c1, unicode c2 ) 18 + { return c1!=c2; } 19 +}; 20 + 21 +//@{ 大文字小文字を区別しないポリシー //@} 22 +struct IgnoreCase 23 +{ 24 + static unicode map( unicode c ) 25 + { return (L'a'<=c && c<=L'z' ? c-L'a'+L'A' : c); } 26 + static bool not_equal( unicode c1, unicode c2 ) 27 + { return map(c1)!=map(c2); } 28 +}; 29 + 30 + 31 + 32 +//========================================================================= 33 +//@{ 34 +// BM法による普通の正方向検索 35 +//@} 36 +//========================================================================= 37 + 38 +template<class ComparisonPolicy> class BMSearch 39 +{ 40 +public: 41 + BMSearch( const unicode* key ) 42 + : keylen_( my_lstrlenW(key) ) 43 + , key_( my_lstrcpyW( new unicode[keylen_+1], key ) ) 44 + { 45 + memFF( lastAppearance_, sizeof(lastAppearance_) ); 46 + for( int i=0, e=keylen_; i<e; ++i ) 47 + lastAppearance_[ ComparisonPolicy::map(key[i]) ] = i; 48 + } 49 + 50 + ~BMSearch() 51 + { 52 + delete [] key_; 53 + } 54 + 55 + int Search( const unicode* str, int strlen ) 56 + { 57 + for( int i=0, e=strlen-keylen_, j, t; i<=e; i+=(j>t?j-t:1) ) 58 + { 59 + for( j=keylen_-1; j>=0; --j ) 60 + { 61 + if( ComparisonPolicy::not_equal( key_[j], str[i+j] ) ) 62 + break; 63 + } 64 + if( j < 0 ) 65 + return i; 66 + t = lastAppearance_[ ComparisonPolicy::map(str[i+j]) ]; 67 + } 68 + return -1; 69 + } 70 + 71 + int keylen() const { return keylen_; } 72 + 73 +private: 74 + int keylen_; 75 + unicode* key_; 76 + int lastAppearance_[65536]; 77 +}; 78 + 79 + 80 + 81 +//========================================================================= 82 +//@{ 83 +// BM法による逆方向検索 84 +//@} 85 +//========================================================================= 86 + 87 +template<class ComparisonPolicy> class BMSearchRev 88 +{ 89 +public: 90 + BMSearchRev( const unicode* key ) 91 + : keylen_( my_lstrlenW(key) ) 92 + , key_( my_lstrcpyW( new unicode[keylen_+1], key ) ) 93 + { 94 + memFF( firstAppearance_, sizeof(firstAppearance_) ); 95 + for( int i=keylen_-1; i>=0; --i ) 96 + firstAppearance_[ ComparisonPolicy::map(key[i]) ] = i; 97 + } 98 + 99 + ~BMSearchRev() 100 + { 101 + delete [] key_; 102 + } 103 + 104 + int Search( const unicode* str, int strlen ) 105 + { 106 + for( int i=strlen-keylen_-1, j, e, t; i>=0; i-=(t>j?t-j:1) ) 107 + { 108 + for( j=0, e=keylen_; j<e; ++j ) 109 + if( ComparisonPolicy::not_equal( key_[j], str[i+j] ) ) 110 + break; 111 + if( j >= e ) 112 + return i; 113 + t = firstAppearance_[ ComparisonPolicy::map(str[i+j]) ]; 114 + if( t == -1 ) t = keylen_; 115 + } 116 + return -1; 117 + } 118 + 119 + int keylen() const { return keylen_; } 120 + 121 +private: 122 + int keylen_; 123 + unicode* key_; 124 + int firstAppearance_[65536]; 125 +}; 126 + 127 + 128 + 129 +//========================================================================= 130 +//@{ 131 +// Searhcableとしての実装(正方向検索) 132 +//@} 133 +//========================================================================= 134 + 135 +template<class CompalisonPolicy> 136 +class NSearch : public Searchable 137 +{ 138 +public: 139 + NSearch( const unicode* key ) : s_(key) {} 140 + 141 +private: 142 + bool Search( 143 + const unicode* str, ulong len, ulong stt, ulong* mbg, ulong* med ) 144 + { 145 + int n = s_.Search( str+stt, len-stt ); 146 + if( n < 0 ) 147 + return false; 148 + *mbg = stt + n; 149 + *med = stt + n + s_.keylen(); 150 + return true; 151 + } 152 + 153 +private: 154 + BMSearch<CompalisonPolicy> s_; 155 +}; 156 + 157 + 158 + 159 +//========================================================================= 160 +//@{ 161 +// Searhcableとしての実装(逆方向検索) 162 +//@} 163 +//========================================================================= 164 + 165 +template<class CompalisonPolicy> 166 +class NSearchRev : public Searchable 167 +{ 168 +public: 169 + NSearchRev( const unicode* key ) : s_(key) {} 170 + 171 +private: 172 + bool Search( 173 + const unicode* str, ulong len, ulong stt, ulong* mbg, ulong* med ) 174 + { 175 + int n = s_.Search( str, stt+s_.keylen() ); 176 + if( n < 0 ) 177 + return false; 178 + *mbg = n; 179 + *med = n + s_.keylen(); 180 + return true; 181 + } 182 + 183 +private: 184 + BMSearchRev<CompalisonPolicy> s_; 185 +}; 186 + 187 + 188 + 189 +//========================================================================= 190 + 191 +#endif
Added OpenSaveDlg.cpp version [d48f24b36f48652a]
1 +#include "stdafx.h" 2 +#include "rsrc/resource.h" 3 +#include "kilib/kilib.h" 4 +#include "OpenSaveDlg.h" 5 +using namespace ki; 6 + 7 + 8 + 9 +//------------------------------------------------------------------------ 10 +// 文字コードリスト 11 +//------------------------------------------------------------------------ 12 + 13 +CharSetList::CharSetList() 14 + : list_( 30 ) 15 +{ 16 + static const TCHAR* const lnmJp[] = { 17 + TEXT("自動判定"), 18 + TEXT("日本語(ShiftJIS)"), 19 + TEXT("日本語(EUC)"), 20 + TEXT("日本語(ISO-2022-JP)"), 21 + TEXT("UTF-5"), 22 + TEXT("UTF-7"), 23 + TEXT("UTF-8"), 24 + TEXT("UTF-8N"), 25 + TEXT("UTF-16BE(BOM)"), 26 + TEXT("UTF-16LE(BOM)"), 27 + TEXT("UTF-16BE"), 28 + TEXT("UTF-16LE"), 29 + TEXT("UTF-32BE(BOM)"), 30 + TEXT("UTF-32LE(BOM)"), 31 + TEXT("UTF-32BE"), 32 + TEXT("UTF-32LE"), 33 + TEXT("欧米"), 34 + TEXT("中欧"), 35 + TEXT("韓国語(EUC-KR)"), 36 + TEXT("韓国語(ISO-2022-KR)"), 37 + TEXT("韓国語(Johab)"), 38 + TEXT("中国語(GB2312)"), 39 + TEXT("中国語(ISO-2022-CN)"), 40 + TEXT("中国語(HZ)"), 41 + TEXT("中国語(Big5)"), 42 + TEXT("キリル語(Windows)"), 43 + TEXT("キリル語(KOI8-R)"), 44 + TEXT("キリル語(KOI8-U)"), 45 + TEXT("タイ語"), 46 + TEXT("トルコ語"), 47 + TEXT("バルト語"), 48 + TEXT("ベトナム語"), 49 + TEXT("ギリシャ語"), 50 + TEXT("MSDOS(us)") 51 + }; 52 + static const TCHAR* const lnmEn[] = { 53 + TEXT("AutoDetect"), 54 + TEXT("Japanese(ShiftJIS)"), 55 + TEXT("Japanese(EUC)"), 56 + TEXT("Japanese(ISO-2022-JP)"), 57 + TEXT("UTF-5"), 58 + TEXT("UTF-7"), 59 + TEXT("UTF-8"), 60 + TEXT("UTF-8N"), 61 + TEXT("UTF-16BE(BOM)"), 62 + TEXT("UTF-16LE(BOM)"), 63 + TEXT("UTF-16BE"), 64 + TEXT("UTF-16LE"), 65 + TEXT("UTF-32BE(BOM)"), 66 + TEXT("UTF-32LE(BOM)"), 67 + TEXT("UTF-32BE"), 68 + TEXT("UTF-32LE"), 69 + TEXT("Latin-1"), 70 + TEXT("Latin-2"), 71 + TEXT("Korean(EUC-KR)"), 72 + TEXT("Korean(ISO-2022-KR)"), 73 + TEXT("Korean(Johab)"), 74 + TEXT("Chinese(GB2312)"), 75 + TEXT("Chinese(ISO-2022-CN)"), 76 + TEXT("Chinese(HZ)"), 77 + TEXT("Chinese(Big5)"), 78 + TEXT("Cyrillic(Windows)"), 79 + TEXT("Cyrillic(KOI8-R)"), 80 + TEXT("Cyrillic(KOI8-U)"), 81 + TEXT("Thai"), 82 + TEXT("Turkish"), 83 + TEXT("Baltic"), 84 + TEXT("Vietnamese"), 85 + TEXT("Greek"), 86 + TEXT("MSDOS(us)") 87 + }; 88 + static const TCHAR* const snm[] = { 89 + TEXT(""), 90 + TEXT("SJIS"), 91 + TEXT("EUC"), 92 + TEXT("JIS"), 93 + TEXT("UTF5"), 94 + TEXT("UTF7"), 95 + TEXT("UTF8"), 96 + TEXT("UTF8"), 97 + TEXT("U16B"), 98 + TEXT("U16L"), 99 + TEXT("U16B"), 100 + TEXT("U16L"), 101 + TEXT("U32B"), 102 + TEXT("U32L"), 103 + TEXT("U32B"), 104 + TEXT("U32L"), 105 + TEXT("LTN1"), 106 + TEXT("LTN2"), 107 + TEXT("UHC"), 108 + TEXT("I2KR"), 109 + TEXT("Jhb"), 110 + TEXT("GBK"), 111 + TEXT("I2CN"), 112 + TEXT("HZ"), 113 + TEXT("BIG5"), 114 + TEXT("CYRL"), 115 + TEXT("KO8R"), 116 + TEXT("KO8U"), 117 + TEXT("THAI"), 118 + TEXT("TRK"), 119 + TEXT("BALT"), 120 + TEXT("VTNM"), 121 + TEXT("GRK"), 122 + TEXT("DOS") 123 + }; 124 + 125 + // 日本語環境なら日本語表示を選ぶ 126 + const TCHAR* const * lnm = (::GetACP()==932 ? lnmJp : lnmEn); 127 + 128 + // いちいち書くの面倒なので短縮表記(^^; 129 + CsInfo cs; 130 + #define Enroll(_id,_nm) cs.ID=_id, \ 131 + cs.longName=lnm[_nm], cs.shortName=snm[_nm], \ 132 + cs.type=LOAD|SAVE, list_.Add( cs ) 133 + #define EnrollS(_id,_nm) cs.ID=_id, \ 134 + cs.longName=lnm[_nm], cs.shortName=snm[_nm], \ 135 + cs.type=SAVE, list_.Add( cs ) 136 + #define EnrollL(_id,_nm) cs.ID=_id, \ 137 + cs.longName=lnm[_nm], cs.shortName=snm[_nm], \ 138 + cs.type=LOAD, list_.Add( cs ) 139 + 140 + // 適宜登録 141 + EnrollL( AutoDetect,0 ); 142 + if( ::IsValidCodePage(932) ) Enroll( SJIS, 1 ), 143 + Enroll( EucJP, 2 ), 144 + Enroll( IsoJP, 3 ); 145 + /* if( always ) */ Enroll( UTF5, 4 ); 146 + Enroll( UTF7, 5 ); 147 + Enroll( UTF8, 6 ); 148 + EnrollS( UTF8N, 7 ); 149 + EnrollS( UTF16b, 8 ); 150 + EnrollS( UTF16l, 9 ); 151 + Enroll( UTF16BE, 10 ); 152 + Enroll( UTF16LE, 11 ); 153 + EnrollS( UTF32b, 12 ); 154 + EnrollS( UTF32l, 13 ); 155 + Enroll( UTF32BE, 14 ); 156 + Enroll( UTF32LE, 15 ); 157 + Enroll( Western, 16 ); 158 + if( ::IsValidCodePage(28592) ) Enroll( Central, 17 ); 159 + if( ::IsValidCodePage(949) ) Enroll( UHC, 18 ), 160 + Enroll( IsoKR, 19 ); 161 + if( ::IsValidCodePage(1361) ) Enroll( Johab, 20 ); 162 + if( ::IsValidCodePage(936) ) Enroll( GBK, 21 ), 163 + Enroll( IsoCN, 22 ), 164 + Enroll( HZ , 23 ); 165 + if( ::IsValidCodePage(950) ) Enroll( Big5 , 24 ); 166 + if( ::IsValidCodePage(28595) ) Enroll( Cyrillic, 25 ); 167 + if( ::IsValidCodePage(20866) ) Enroll( Koi8R, 26 ); 168 + if( ::IsValidCodePage(21866) ) Enroll( Koi8U, 27 ); 169 + if( ::IsValidCodePage(874) ) Enroll( Thai, 28 ); 170 + if( ::IsValidCodePage(1254) ) Enroll( Turkish, 29 ); 171 + if( ::IsValidCodePage(1257) ) Enroll( Baltic, 30 ); 172 + if( ::IsValidCodePage(1258) ) Enroll( Vietnamese,31 ); 173 + if( ::IsValidCodePage(28597) ) Enroll( Greek, 32 ); 174 + Enroll( DOSUS, 33 ); 175 + 176 + // 終了 177 + #undef Enroll 178 + #undef EnrollS 179 + #undef EnrollL 180 +} 181 + 182 +int CharSetList::defaultCs() const 183 +{ 184 + return ::GetACP(); 185 +/* 186 + switch( ::GetACP() ) 187 + { 188 + case 932: return SJIS; 189 + case 936: return GBK; 190 + case 949: return UHC; 191 + case 950: return Big5; 192 + default: return Western; 193 + } 194 +*/ 195 +} 196 + 197 +ulong CharSetList::defaultCsi() const 198 +{ 199 + return findCsi( defaultCs() ); 200 +} 201 + 202 +ulong CharSetList::findCsi( int cs ) const 203 +{ 204 + for( ulong i=0,ie=list_.size(); i<ie; ++i ) 205 + if( list_[i].ID == cs ) 206 + return i; 207 + return 0xffffffff; 208 +} 209 + 210 + 211 + 212 +//------------------------------------------------------------------------ 213 +// 「開く」ダイアログ 214 +//------------------------------------------------------------------------ 215 + 216 +namespace 217 +{ 218 + // 関数終了時に、カレントディレクトリを元に戻す 219 + class CurrentDirRecovery 220 + { 221 + Path cur_; 222 + public: 223 + CurrentDirRecovery() : cur_(Path::Cur) {} 224 + ~CurrentDirRecovery() { ::SetCurrentDirectory(cur_.c_str()); } 225 + }; 226 +} 227 + 228 +OpenFileDlg* OpenFileDlg::pThis; 229 + 230 +bool OpenFileDlg::DoModal( HWND wnd, const TCHAR* fltr, const TCHAR* fnm ) 231 +{ 232 + CurrentDirRecovery cdr; 233 + 234 + if( fnm == NULL ) 235 + filename_[0] = TEXT('\0'); 236 + else 237 + ::lstrcpy( filename_, fnm ); 238 + 239 + OPENFILENAME ofn = {sizeof(ofn)}; 240 + ofn.hwndOwner = wnd; 241 + ofn.hInstance = app().hinst(); 242 + ofn.lpstrFilter = fltr; 243 + ofn.lpstrFile = filename_; 244 + ofn.nMaxFile = countof(filename_); 245 + ofn.lpTemplateName = MAKEINTRESOURCE(IDD_OPENFILEHOOK); 246 + ofn.lpfnHook = OfnHook; 247 + ofn.Flags = OFN_FILEMUSTEXIST | 248 + OFN_HIDEREADONLY | 249 + OFN_EXPLORER | 250 + OFN_ENABLESIZING | 251 + OFN_ENABLEHOOK | 252 + OFN_ENABLETEMPLATE; 253 + 254 + pThis = this; 255 + return ( ::GetOpenFileName(&ofn) != 0 ); 256 +} 257 + 258 +UINT_PTR CALLBACK OpenFileDlg::OfnHook( HWND dlg, UINT msg, WPARAM, LPARAM lp ) 259 +{ 260 + if( msg==WM_INITDIALOG ) 261 + { 262 + // コンボボックスを埋めて、「自動選択」を選ぶ 263 + ComboBox cb( dlg, IDC_CODELIST ); 264 + const CharSetList& csl = pThis->csl_; 265 + for( ulong i=0; i<csl.size(); ++i ) 266 + if( csl[i].type & 2 ) // 2:=LOAD 267 + cb.Add( csl[i].longName ); 268 + cb.Select( csl[0].longName ); 269 + } 270 + else if( msg==WM_NOTIFY ) 271 + { 272 + // OKが押されたら、文字コードの選択状況を記録 273 + if( reinterpret_cast<NMHDR*>(lp)->code==CDN_FILEOK ) 274 + { 275 + ulong j=0, i=ComboBox(dlg,IDC_CODELIST).GetCurSel(); 276 + for(;;++j,--i) 277 + { 278 + while( !(pThis->csl_[j].type & 2) ) // !LOAD 279 + ++j; 280 + if( i==0 ) 281 + break; 282 + } 283 + pThis->csIndex_ = j; 284 + } 285 + } 286 + return FALSE; 287 +} 288 + 289 + 290 + 291 +//------------------------------------------------------------------------ 292 +// 「保存」ダイアログ 293 +//------------------------------------------------------------------------ 294 + 295 +SaveFileDlg* SaveFileDlg::pThis; 296 + 297 +bool SaveFileDlg::DoModal( HWND wnd, const TCHAR* fltr, const TCHAR* fnm ) 298 +{ 299 + CurrentDirRecovery cdr; 300 + 301 + if( fnm == NULL ) 302 + filename_[0] = TEXT('\0'); 303 + else 304 + ::lstrcpy( filename_, fnm ); 305 + 306 + OPENFILENAME ofn = {sizeof(ofn)}; 307 + ofn.hwndOwner = wnd; 308 + ofn.hInstance = app().hinst(); 309 + ofn.lpstrFilter = fltr; 310 + ofn.lpstrFile = filename_; 311 + ofn.nMaxFile = countof(filename_); 312 + ofn.lpTemplateName = MAKEINTRESOURCE(IDD_SAVEFILEHOOK); 313 + ofn.lpfnHook = OfnHook; 314 + ofn.Flags = OFN_HIDEREADONLY | 315 + OFN_PATHMUSTEXIST | 316 + OFN_EXPLORER | 317 + OFN_ENABLESIZING | 318 + OFN_ENABLEHOOK | 319 + OFN_ENABLETEMPLATE | 320 + OFN_OVERWRITEPROMPT; 321 + 322 + pThis = this; 323 + return ( ::GetSaveFileName(&ofn) != 0 ); 324 +} 325 + 326 +UINT_PTR CALLBACK SaveFileDlg::OfnHook( HWND dlg, UINT msg, WPARAM, LPARAM lp ) 327 +{ 328 + if( msg==WM_INITDIALOG ) 329 + { 330 + // コンボボックスを埋めて、適切なのを選ぶ 331 + { 332 + ComboBox cb( dlg, IDC_CODELIST ); 333 + const CharSetList& csl = pThis->csl_; 334 + 335 + for( ulong i=0; i<csl.size(); ++i ) 336 + if( csl[i].type & 1 ) // 1:=SAVE 337 + cb.Add( csl[i].longName ); 338 + cb.Select( csl[pThis->csIndex_].longName ); 339 + } 340 + { 341 + ComboBox cb( dlg, IDC_CRLFLIST ); 342 + static const TCHAR* const lbList[] = { 343 + TEXT("CR"), 344 + TEXT("LF"), 345 + TEXT("CRLF") 346 + }; 347 + 348 + for( ulong i=0; i<countof(lbList); ++i ) 349 + cb.Add( lbList[i] ); 350 + cb.Select( lbList[pThis->lb_] ); 351 + } 352 + } 353 + else if( msg==WM_NOTIFY ) 354 + { 355 + if( reinterpret_cast<NMHDR*>(lp)->code==CDN_FILEOK ) 356 + { 357 + // OKが押されたら、文字コードの選択状況を記録 358 + ulong j=0, i=ComboBox(dlg,IDC_CODELIST).GetCurSel(); 359 + for(;;++j,--i) 360 + { 361 + while( !(pThis->csl_[j].type & 1) ) // !SAVE 362 + ++j; 363 + if( i==0 ) 364 + break; 365 + } 366 + pThis->csIndex_ = j; 367 + // 改行コードも 368 + pThis->lb_ = ComboBox(dlg,IDC_CRLFLIST).GetCurSel(); 369 + } 370 + } 371 + return FALSE; 372 +} 373 + 374 + 375 + 376 +//------------------------------------------------------------------------ 377 +// ユーティリティー 378 +//------------------------------------------------------------------------ 379 + 380 +ki::aarr<TCHAR> OpenFileDlg::ConnectWithNull( String lst[], int num ) 381 +{ 382 + int TtlLen = 1; 383 + for( int i=0; i<num; ++i ) 384 + TtlLen += (lst[i].len() + 1); 385 + 386 + aarr<TCHAR> a( new TCHAR[TtlLen] ); 387 + 388 + TCHAR* p = a.get(); 389 + for( int i=0; i<num; ++i ) 390 + { 391 + ::lstrcpy( p, lst[i].c_str() ); 392 + p += (lst[i].len() + 1); 393 + } 394 + *p = TEXT('\0'); 395 + 396 + return a; 397 +} 398 + 399 + 400 + 401 + 402 +//------------------------------------------------------------------------ 403 +// 「開き直す」ダイアログ 404 +//------------------------------------------------------------------------ 405 + 406 +ReopenDlg::ReopenDlg( const CharSetList& csl, int csi ) 407 + : DlgImpl(IDD_REOPENDLG), csl_(csl), csIndex_(csi) 408 +{ 409 +} 410 + 411 +void ReopenDlg::on_init() 412 +{ 413 + // コンボボックスを埋めて、「自動選択」を選ぶ 414 + ComboBox cb( hwnd(), IDC_CODELIST ); 415 + for( ulong i=0; i<csl_.size(); ++i ) 416 + if( csl_[i].type & 1 ) // 2:=SAVE 417 + cb.Add( csl_[i].longName ); 418 + cb.Select( csl_[csIndex_].longName ); 419 +} 420 + 421 +bool ReopenDlg::on_ok() 422 +{ 423 + // OKが押されたら、文字コードの選択状況を記録 424 + ulong j=0, i=ComboBox(hwnd(),IDC_CODELIST).GetCurSel(); 425 + for(;;++j,--i) 426 + { 427 + while( !(csl_[j].type & 1) ) // !SAVE 428 + ++j; 429 + if( i==0 ) 430 + break; 431 + } 432 + csIndex_ = j; 433 + return true; 434 +}
Added OpenSaveDlg.h version [fa92942f039f4d4b]
1 +#ifndef _GREENPAD_OPENSAVEDLG_H_ 2 +#define _GREENPAD_OPENSAVEDLG_H_ 3 +#include "kilib/ktlarray.h" 4 +#include "kilib/ktlaptr.h" 5 +#include "kilib/string.h" 6 +#include "rsrc/resource.h" 7 + 8 + 9 + 10 +//======================================================================== 11 +//@{ @pkg Gp.Dlg //@} 12 +//@{ 13 +// 利用可能文字コードリスト 14 +//@} 15 +//======================================================================== 16 + 17 +class CharSetList 18 +{ 19 +public: 20 + 21 + struct CsInfo 22 + { 23 + int ID; 24 + const TCHAR* longName; 25 + const TCHAR* shortName; 26 + int type; 27 + }; 28 + 29 +public: 30 + 31 + CharSetList(); 32 + const CsInfo& operator[](size_t i) const { return list_[i]; } 33 + ulong size() const { return list_.size(); } 34 + int defaultCs() const; 35 + ulong defaultCsi() const; 36 + ulong findCsi( int cs ) const; 37 + 38 +private: 39 + 40 + enum { SAVE=1, LOAD=2, BOTH=3 }; 41 + ki::storage<CsInfo> list_; 42 +}; 43 + 44 + 45 + 46 +//======================================================================== 47 +//@{ 48 +// 「ファイルを開く」ダイアログ 49 +// 50 +// Windows共通のダイアログの下に、文字コードの選択欄を 51 +// 付け加えたものを表示する。 52 +//@} 53 +//======================================================================== 54 + 55 +class OpenFileDlg 56 +{ 57 +public: 58 + explicit OpenFileDlg( const CharSetList& csl ); 59 + bool DoModal( HWND wnd, const TCHAR* filter, const TCHAR* fnm ); 60 + 61 +public: 62 + const TCHAR* filename() const; 63 + int csi() const; 64 + 65 +public: 66 + static ki::aarr<TCHAR> ConnectWithNull( ki::String lst[], int num ); 67 + 68 +private: 69 + const CharSetList& csl_; 70 + TCHAR filename_[MAX_PATH]; 71 + int csIndex_; 72 + 73 +private: 74 + static OpenFileDlg* pThis; // マルチスレッド禁止! 75 + static UINT_PTR CALLBACK OfnHook( HWND, UINT, WPARAM, LPARAM ); 76 +}; 77 + 78 + 79 + 80 +//------------------------------------------------------------------------ 81 +#ifndef __ccdoc__ 82 + 83 +inline OpenFileDlg::OpenFileDlg( const CharSetList& csl ) 84 + : csl_(csl) {} 85 + 86 +inline const TCHAR* OpenFileDlg::filename() const 87 + { return filename_; } 88 + 89 +inline int OpenFileDlg::csi() const 90 + { return csIndex_; } 91 + 92 + 93 + 94 +#endif // __ccdoc__ 95 +//======================================================================== 96 +//@{ 97 +// 「ファイルを保存」ダイアログ 98 +// 99 +// Windows共通のダイアログの下に、文字コードの選択欄と 100 +// 改行コードの選択欄を付け加えたものを表示する。 101 +//@} 102 +//======================================================================== 103 + 104 +class SaveFileDlg 105 +{ 106 +public: 107 + explicit SaveFileDlg( const CharSetList& csl, int cs, int lb ); 108 + bool DoModal( HWND wnd, const TCHAR* filter, const TCHAR* fnm ); 109 + 110 +public: 111 + const TCHAR* filename() const; 112 + int csi() const; 113 + int lb() const; 114 + 115 +public: 116 + static ki::aarr<TCHAR> ConnectWithNull( ki::String lst[], int num ); 117 + 118 +private: 119 + const CharSetList& csl_; 120 + TCHAR filename_[MAX_PATH]; 121 + int csIndex_; 122 + int lb_; 123 + 124 +private: 125 + static SaveFileDlg* pThis; // マルチスレッド禁止! 126 + static UINT_PTR CALLBACK OfnHook( HWND, UINT, WPARAM, LPARAM ); 127 +}; 128 + 129 +//------------------------------------------------------------------------ 130 +#ifndef __ccdoc__ 131 + 132 +inline SaveFileDlg::SaveFileDlg( const CharSetList& csl, int cs, int lb ) 133 + : csl_(csl), csIndex_(cs), lb_(lb) {} 134 + 135 +inline const TCHAR* SaveFileDlg::filename() const 136 + { return filename_; } 137 + 138 +inline int SaveFileDlg::csi() const 139 + { return csIndex_; } 140 + 141 +inline int SaveFileDlg::lb() const 142 + { return lb_; } 143 + 144 +inline ki::aarr<TCHAR> SaveFileDlg::ConnectWithNull 145 + ( ki::String lst[], int num ) 146 + { return OpenFileDlg::ConnectWithNull( lst, num ); } 147 + 148 + 149 + 150 +#endif // __ccdoc__ 151 +//======================================================================== 152 +//@{ 153 +// 「開き直す」ダイアログ 154 +// 155 +// 文字コード選択欄表示 156 +//@} 157 +//======================================================================== 158 + 159 +class ReopenDlg : public ki::DlgImpl 160 +{ 161 +public: 162 + ReopenDlg( const CharSetList& csl, int csi ); 163 + int csi() const; 164 + 165 +private: 166 + void on_init(); 167 + bool on_ok(); 168 + 169 +private: 170 + const CharSetList& csl_; 171 + int csIndex_; 172 +}; 173 + 174 +//------------------------------------------------------------------------ 175 +#ifndef __ccdoc__ 176 + 177 +inline int ReopenDlg::csi() const 178 + { return csIndex_; } 179 + 180 + 181 + 182 +//======================================================================== 183 + 184 +#endif // __ccdoc__ 185 +#endif // _GREENPAD_OPENSAVEDLG_H_
Added README.txt version [3c18011e76a7b913]
1 + 2 +=<> 3 +=<> GreenPad ver 1.08+ Source Code 4 +=<> 2008/07/11 5 + 6 + 7 + Windows用簡易テキストエディタ GreenPad のソースコードです。 8 + 下にあげるいくつかのC++コンパイラでコンパイルできます。 9 + 10 + Source code for GreenPad - a simple text editor for Windows. 11 + Can be built by the following compilers. 12 + 13 + - Visual C++ .NET 2005 Express Edition 14 + - Visual C++ 2003 Toolkit 15 + - Microsoft Platform SDK for Windows Server 2003 R2 - March 2006 Edition 16 + - Borland C++ BuilderX 17 + - Borland C++ Compiler 5.5.1 18 + - Digital Mars C++ 8.49 19 + - MinGW (g++ 3.4.2) 20 + 21 + 22 + 23 +:: Visual C++ .NET 2005 :: 24 + 25 + - "kilib.sln" を開いて、「ビルド」メニューの「ソリューションのビルド」 26 + 27 + - Open "kilib.sln" and build the main project. 28 + 29 + 30 + 31 +:: Visual C++ @ Command Prompt (Platform SDK / Toolkit 2003) :: 32 + 33 + - ソースコードのルートディレクトリで "nmake vcc" と打つ 34 + 35 + - Type "nmake vcc" at the root directory of the source archive 36 + 37 + 38 + 39 +:: Visual C++ 6.0 :: 40 + 41 + - 対応しなくなりました。 42 + 作者は確認していませんが、一応 kilib.dsw と kilib.dsp を使えば 43 + もしかしたらビルドできるかも。 44 + 45 + - No longer supported 46 + kilib.dsw and kilib.dsp MAY work. 47 + 48 + 49 + 50 +:: Borland C++ @ Command Prompt (5.5.1 / BuilderX) :: 51 + 52 + - ソースコードのルートディレクトリで "make bcc" と打つ。 53 + 必ずBorland製のmakeコマンドを使用すること 54 + 55 + - Type "make bcc" at the root directory of the source archive 56 + Make sure to use Borland make. 57 + 58 + 59 + 60 +:: Digital Mars C++ :: 61 + 62 + - ソースコードのルートディレクトリで "make dmc" と打つ。 63 + 必ずDigitalmars製のmakeコマンドを使用すること。 64 + なお、Digital Mars 製のリソースコンパイラは力不足のため、 65 + リソースのコンパイルに Borland のコンパイラが必要です。 66 + Borland C++ 5.5 についてくるので入手してください。 67 + あと、imm32.dll をリンクするため imm32.lib が必要です。 68 + お手元で生成するか、http://www.kmonos.net/alang/dmc/ から 69 + 入手してください。 70 + 71 + - Type "make dmc" at the root directory of the source archive 72 + Make sure to use Digitalmars make. 73 + Since DM's resource compiler is pretty poor, you additionaly 74 + need Borland's resource compiler to build GreenPad. 75 + You also need imm32.lib to build. You can generate it by 76 + coff2omf command or something, or you can download it from 77 + http://www.kmonos.net/alang/dmc/ . 78 + 79 + 80 + 81 +:: gcc (MinGW) :: 82 + 83 + - ソースコードのルートディレクトリで "make gcc" と打つ。 84 + 必ずGNU製のmakeコマンドを使用すること。 85 + MinGW に最初から付属してくるリソースコンパイラ windres は 86 + 日本語対応でないことがあります。MinGW のページから binutils 87 + を別途ダウンロードして、そちらの windres をご利用下さい。 88 + 89 + - Type "make gcc" at the root directory of the source archive 90 + Make sure to use GNU make. 91 + MinGW version of windres (resource compiler) seem not to 92 + support Japanese resources. So you need to separately download 93 + binutils from the MinGW page and use the windres in it. 94 + 95 + 96 + 97 +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 98 + 99 +:: ライセンス / License :: 100 + 101 + NYSL Version 0.9982 http://www.kmonos.net/nysl/ 102 + 103 + A. 本ソフトウェアは Everyone'sWare です。このソフトを手にした一人一人が、 104 + ご自分の作ったものを扱うのと同じように、自由に利用することが出来ます。 105 + 106 + A-1. フリーウェアです。作者からは使用料等を要求しません。 107 + A-2. 有料無料や媒体の如何を問わず、自由に転載・再配布できます。 108 + A-3. いかなる種類の 改変・他プログラムでの利用 を行っても構いません。 109 + A-4. 変更したものや部分的に使用したものは、あなたのものになります。 110 + 公開する場合は、あなたの名前の下で行って下さい。 111 + 112 + B. このソフトを利用することによって生じた損害等について、作者は 113 + 責任を負わないものとします。各自の責任においてご利用下さい。 114 + 115 + C. 著作者人格権は K.INABA に帰属します。著作権は放棄します。 116 + 117 + D. 以上の3項は、ソース・実行バイナリの双方に適用されます。 118 + 119 + 120 +--------------------------------------------------------------------------- 121 + by k.inaba( http://www.kmonos.net/ )
Added RSearch.cpp version [e489a8164194c55f]
1 + 2 +#include "stdafx.h" 3 +#include "RSearch.h" 4 +#include "kilib/ktlaptr.h" 5 +using namespace ki; 6 + 7 + 8 + 9 +//========================================================================= 10 +//@{ 11 +// 文字の種類 12 +//@} 13 +//========================================================================= 14 + 15 +enum RegToken 16 +{ 17 + R_Char, // 普通の文字 18 + R_Any, // '.' 19 + R_Lcl, // '[' 20 + R_Rcl, // ']' 21 + R_Ncl, // '^' 22 + R_Range, // '-' 23 + R_Lbr, // '(' 24 + R_Rbr, // ')' 25 + R_Bar, // '|' 26 + R_Star, // '*' 27 + R_Plus, // '+' 28 + R_Quest, // '?' 29 + R_End // '\0' 30 +}; 31 + 32 + 33 + 34 +//========================================================================= 35 +//@{ 36 +// トークンに分解 37 +// 38 +// 行頭を表す^と行末を表す$については上位層で頑張る 39 +//@} 40 +//========================================================================= 41 + 42 +class RegLexer 43 +{ 44 +public: 45 + RegLexer( const wchar_t* pat, ulong len ); 46 + RegToken GetToken(); 47 + wchar_t GetChar() { return chr_; } 48 + 49 +private: 50 + const wchar_t* pat_; 51 + const wchar_t* end_; 52 + const wchar_t* sub_; 53 + wchar_t chr_; 54 +}; 55 + 56 + 57 + 58 +//========================================================================= 59 +//@{ 60 +// トークンに分解:実装 61 +//@} 62 +//========================================================================= 63 + 64 +inline RegLexer::RegLexer( const wchar_t* pat, ulong len ) 65 + : pat_( pat ) 66 + , end_( pat+len ) 67 + , sub_( L"" ) 68 +{ 69 +} 70 + 71 +RegToken RegLexer::GetToken() 72 +{ 73 + const wchar_t*& x = (*sub_ ? sub_ : pat_); 74 + if( x == end_ ) return R_End; 75 + switch( *x++ ) 76 + { 77 + case L'.': return R_Any; 78 + case L'[': return R_Lcl; 79 + case L']': return R_Rcl; 80 + case L'^': return R_Ncl; 81 + case L'-': return R_Range; 82 + case L'(': return R_Lbr; 83 + case L')': return R_Rbr; 84 + case L'|': return R_Bar; 85 + case L'*': return R_Star; 86 + case L'+': return R_Plus; 87 + case L'?': return R_Quest; 88 + case L'\\': if( x==end_ ) return R_End; switch( *x++ ) { 89 + case L't': chr_=L'\t'; return R_Char; 90 + case L'w': sub_=L"[0-9a-zA-Z_]"; return GetToken(); 91 + case L'W': sub_=L"[^0-9a-zA-Z_]"; return GetToken(); 92 + case L'd': sub_=L"[0-9]"; return GetToken(); 93 + case L'D': sub_=L"[^0-9]"; return GetToken(); 94 + case L's': sub_=L"[\t ]"; return GetToken(); 95 + case L'S': sub_=L"[^\t ]"; return GetToken(); 96 + } // fall through... 97 + default: 98 + chr_ = *(x-1); 99 + return R_Char; 100 + } 101 +} 102 + 103 + 104 + 105 +//========================================================================= 106 +//@{ 107 +// 構文木のノードに振られる値の種類 108 +//@} 109 +//========================================================================= 110 + 111 +enum RegType 112 +{ 113 + N_Char, // 普通の文字 (ch) 114 + N_Class, // [...] など (cls) 115 + N_Concat, // 連接 (left, right) 116 + N_Or, // | (left, right) 117 + N_Closure, // * (left) 118 + N_Closure1, // + (left) 119 + N_01, // ? (left) 120 + N_Empty // 空 (--) 121 +}; 122 + 123 +struct RegClass 124 +{ 125 + struct OneRange 126 + { 127 + wchar_t stt; 128 + wchar_t end; 129 + }; 130 + OneRange range; 131 + aptr<RegClass> next; 132 + RegClass( wchar_t s, wchar_t e, RegClass* n ) 133 + { aptr<RegClass> an(n); range.stt=s, range.end=e, next=an; } 134 +}; 135 + 136 +struct RegNode 137 +{ 138 + RegType type; // このノードの種類 139 + wchar_t ch; // 文字 140 + aptr<RegClass> cls; // 文字集合 141 + bool cmpcls; // ↑補集合かどうか 142 + dptr<RegNode> left; // 左の子 143 + dptr<RegNode> right; // 右の子 144 +}; 145 + 146 + 147 + 148 +//========================================================================= 149 +//@{ 150 +// 構文木作成 151 +//@} 152 +//========================================================================= 153 + 154 +class RegParser 155 +{ 156 +public: 157 + RegParser( const unicode* pat ); 158 + RegNode* root() { return root_.get(); } 159 + bool err() { return err_; } 160 + bool isHeadType() const { return isHeadType_; } 161 + bool isTailType() const { return isTailType_; } 162 + 163 +private: 164 + RegNode* make_empty_leaf(); 165 + RegNode* make_char_leaf( wchar_t c ); 166 + RegNode* make_node( RegType t, RegNode* lft, RegNode* rht ); 167 + void eat_token(); 168 + RegNode* expr(); 169 + RegNode* term(); 170 + RegNode* factor(); 171 + RegNode* primary(); 172 + RegNode* reclass(); 173 + 174 +private: 175 + bool err_; 176 + bool isHeadType_; 177 + bool isTailType_; 178 + dptr<RegNode> root_; 179 + 180 + RegLexer lex_; 181 + RegToken nextToken_; 182 +}; 183 + 184 + 185 + 186 +//========================================================================= 187 +//@{ 188 +// 構文木作成:実装 189 +//@} 190 +//========================================================================= 191 + 192 +namespace { static int tmp; } 193 + 194 +inline RegParser::RegParser( const unicode* pat ) 195 + : err_ ( false ) 196 + , isHeadType_( *pat==L'^' ) 197 + , isTailType_( (tmp=my_lstrlenW(pat), tmp && pat[tmp-1]==L'$') ) 198 + , lex_( 199 + (isHeadType_ ? pat+1 : pat), 200 + (my_lstrlenW(pat) - (isHeadType_ ? 1 : 0) 201 + - (isTailType_ ? 1 : 0)) ) 202 +{ 203 + eat_token(); 204 + root_ = expr(); 205 +} 206 + 207 +inline void RegParser::eat_token() 208 +{ 209 + nextToken_ = lex_.GetToken(); 210 +} 211 + 212 +inline RegNode* RegParser::make_empty_leaf() 213 +{ 214 + RegNode* node = new RegNode; 215 + node->type = N_Empty; 216 + return node; 217 +} 218 + 219 +inline RegNode* RegParser::make_char_leaf( wchar_t c ) 220 +{ 221 + RegNode* node = new RegNode; 222 + node->type = N_Char; 223 + node->ch = c; 224 + return node; 225 +} 226 + 227 +RegNode* RegParser::make_node( RegType t, RegNode* lft, RegNode* rht ) 228 +{ 229 + RegNode* node = new RegNode; 230 + node->type = t; 231 + node->left = lft; 232 + node->right= rht; 233 + return node; 234 +} 235 + 236 +RegNode* RegParser::reclass() 237 +{ 238 +// CLASS ::= '^'? CHAR (CHAR | -CHAR)* 239 + 240 + bool neg = false; 241 + if( nextToken_ == R_Ncl ) 242 + neg=true, eat_token(); 243 + 244 + RegClass* cls = NULL; 245 + while( nextToken_ == R_Char ) 246 + { 247 + wchar_t ch = lex_.GetChar(); 248 + eat_token(); 249 + if( nextToken_ == R_Range ) 250 + { 251 + eat_token(); 252 + if( nextToken_ != R_Char ) 253 + err_ = true; 254 + else 255 + { 256 + wchar_t ch2 = lex_.GetChar(); 257 + cls = new RegClass( Min(ch,ch2), Max(ch,ch2), cls ); 258 + eat_token(); 259 + } 260 + } 261 + else 262 + { 263 + cls = new RegClass( ch, ch, cls ); 264 + } 265 + } 266 + 267 + RegNode* node = new RegNode; 268 + node->type = N_Class; 269 + aptr<RegClass> ncls(cls); 270 + node->cls = ncls; 271 + node->cmpcls = neg; 272 + return node; 273 +} 274 + 275 +RegNode* RegParser::primary() 276 +{ 277 +// PRIMARY ::= CHAR 278 +// '.' 279 +// '[' CLASS ']' 280 +// '(' REGEXP ')' 281 + 282 + RegNode* node; 283 + switch( nextToken_ ) 284 + { 285 + case R_Char: 286 + node = make_char_leaf( lex_.GetChar() ); 287 + eat_token(); 288 + break; 289 + case R_Any:{ 290 + node = new RegNode; 291 + node->type = N_Class; 292 + aptr<RegClass> ncls(new RegClass( 0, 65535, NULL )); 293 + node->cls = ncls; 294 + node->cmpcls = false; 295 + eat_token(); 296 + }break; 297 + case R_Lcl: 298 + eat_token(); 299 + node = reclass(); 300 + if( nextToken_ == R_Rcl ) 301 + eat_token(); 302 + else 303 + err_ = true; 304 + break; 305 + case R_Lbr: 306 + eat_token(); 307 + node = expr(); 308 + if( nextToken_ == R_Rbr ) 309 + eat_token(); 310 + else 311 + err_ = true; 312 + break; 313 + default: 314 + node = make_empty_leaf(); 315 + err_ = true; 316 + break; 317 + } 318 + return node; 319 +} 320 + 321 +RegNode* RegParser::factor() 322 +{ 323 +// FACTOR ::= PRIMARY 324 +// PRIMARY '*' 325 +// PRIMARY '+' 326 +// PRIMARY '?' 327 + 328 + RegNode* node = primary(); 329 + switch( nextToken_ ) 330 + { 331 + case R_Star: node=make_node(N_Closure,node,NULL); eat_token();break; 332 + case R_Plus: node=make_node(N_Closure1,node,NULL);eat_token();break; 333 + case R_Quest:node=make_node(N_01,node,NULL ); eat_token();break; 334 + } 335 + return node; 336 +} 337 + 338 +RegNode* RegParser::term() 339 +{ 340 +// TERM ::= EMPTY 341 +// FACTOR TERM 342 + 343 + if( nextToken_ == R_End ) 344 + return make_empty_leaf(); 345 + 346 + RegNode* node = factor(); 347 + if( nextToken_==R_Lbr || nextToken_==R_Lcl 348 + || nextToken_==R_Char|| nextToken_==R_Any ) 349 + node = make_node( N_Concat, node, term() ); 350 + return node; 351 +} 352 + 353 +RegNode* RegParser::expr() 354 +{ 355 +// REGEXP ::= TERM 356 +// TERM '|' REGEXP 357 + 358 + RegNode* node = term(); 359 + if( nextToken_ == R_Bar ) 360 + { 361 + eat_token(); 362 + node = make_node( N_Or, node, expr() ); 363 + } 364 + return node; 365 +} 366 + 367 + 368 + 369 +//========================================================================= 370 +//@{ 371 +// 状態遷移 372 +//@} 373 +//========================================================================= 374 + 375 +struct RegTrans 376 +{ 377 + enum { 378 + Epsilon, 379 + Class, 380 + Char 381 + } type; 382 + aptr<RegClass> cls; // この文字集合 383 + // orEpsilon が来たら 384 + bool cmpcls; 385 + int to; // 状態番号toの状態へ遷移 386 + 387 + aptr<RegTrans> next; // 連結リスト 388 +/* 389 + template<class Cmp> 390 + bool match_i( wchar_t c, Cmp ) 391 + { 392 + c = Cmp::map(c); 393 + RegClass* p = cls.get(); 394 + while( p ) 395 + if( Cmp::map(p->range.stt)<=c && c<=Cmp::map(p->range.end) ) 396 + return true; 397 + else 398 + p = p->next.get(); 399 + return false; 400 + } 401 +*/ 402 + bool match_c( wchar_t c ) 403 + { 404 + for( RegClass* p=cls.get(); p; p=p->next.get() ) 405 + if( p->range.stt<=c && c<=p->range.end ) 406 + return true; 407 + return false; 408 + } 409 + 410 + bool match_i( wchar_t c ) 411 + { 412 + c = IgnoreCase::map(c); 413 + for( RegClass* p=cls.get(); p; p=p->next.get() ) 414 + if( IgnoreCase::map(p->range.stt)<=c 415 + && c<=IgnoreCase::map(p->range.end) ) 416 + return true; 417 + return false; 418 + } 419 + 420 + bool match( wchar_t c, bool caseS ) 421 + { 422 + bool m = caseS ? match_c( c ) : match_i( c ); 423 + return cmpcls ? !m : m; 424 + } 425 +}; 426 + 427 + 428 + 429 +//========================================================================= 430 +//@{ 431 +// 構文木->NFA変換 432 +//@} 433 +//========================================================================= 434 + 435 +class RegNFA 436 +{ 437 +public: 438 + RegNFA( const wchar_t* pat ); 439 + ~RegNFA(); 440 + 441 + int match( const wchar_t* str, int len, bool caseS ); 442 + bool isHeadType() const { return parser.isHeadType(); } 443 + bool isTailType() const { return parser.isTailType(); } 444 + 445 +private: 446 + // マッチング処理 447 + int dfa_match( const wchar_t* str, int len, bool caseS ); 448 + 449 + struct st_ele { int st, ps; }; 450 + void push(storage<st_ele>& stack, int curSt, int pos); 451 + st_ele pop(storage<st_ele>& stack); 452 + 453 +private: 454 + void add_transition( int from, wchar_t ch, int to ); 455 + void add_transition( int from, aptr<RegClass> cls, bool cmp, int to ); 456 + void add_e_transition( int from, int to ); 457 + int gen_state(); 458 + void gen_nfa( int entry, RegNode* t, int exit ); 459 + 460 +private: 461 + RegParser parser; 462 + storage<RegTrans*> st; 463 + int start, final; 464 +}; 465 + 466 +RegNFA::RegNFA( const wchar_t* pat ) 467 + : parser( pat ) 468 +{ 469 + start = gen_state(); 470 + final = gen_state(); 471 + gen_nfa( start, parser.root(), final ); 472 +} 473 + 474 +inline RegNFA::~RegNFA() 475 +{ 476 + for( ulong i=0,e=st.size(); i<e; ++i ) 477 + delete st[i]; 478 +} 479 + 480 +inline void RegNFA::add_transition 481 + ( int from, aptr<RegClass> cls, bool cmp, int to ) 482 +{ 483 + RegTrans* x = new RegTrans; 484 + aptr<RegTrans> nn( st[from] ); 485 + x->next = nn; 486 + x->to = to; 487 + x->type = RegTrans::Class; 488 + x->cls = cls; 489 + x->cmpcls= cmp; 490 + st[from] = x; 491 +} 492 + 493 +inline void RegNFA::add_transition( int from, wchar_t ch, int to ) 494 +{ 495 + aptr<RegClass> cls(new RegClass(ch,ch,NULL)); 496 + add_transition( from, cls, false, to ); 497 +} 498 + 499 +inline void RegNFA::add_e_transition( int from, int to ) 500 +{ 501 + RegTrans* x = new RegTrans; 502 + aptr<RegTrans> nn( st[from] ); 503 + x->next = nn; 504 + x->to = to; 505 + x->type = RegTrans::Epsilon; 506 + st[from] = x; 507 +} 508 + 509 +inline int RegNFA::gen_state() 510 +{ 511 + st.Add( NULL ); 512 + return st.size() - 1; 513 +} 514 + 515 +void RegNFA::gen_nfa( int entry, RegNode* t, int exit ) 516 +{ 517 + switch( t->type ) 518 + { 519 + case N_Char: 520 + // ch 521 + // entry ----> exit 522 + add_transition( entry, t->ch, exit ); 523 + break; 524 + case N_Class: 525 + // cls 526 + // entry -----> exit 527 + add_transition( entry, t->cls, t->cmpcls, exit ); 528 + break; 529 + case N_Concat: { 530 + // left right 531 + // entry ------> step -------> exit 532 + int step = gen_state(); 533 + gen_nfa( entry, t->left.get(), step ); 534 + gen_nfa( step, t->right.get(), exit ); 535 + } break; 536 + case N_Or: 537 + // left 538 + // ------> 539 + // entry ------->--> exit 540 + // right 541 + gen_nfa( entry, t->left.get(), exit ); 542 + gen_nfa( entry, t->right.get(), exit ); 543 + break; 544 + case N_Closure: 545 + // e 546 + // e <------ e 547 + // entry ---> before ------> after ---> exit 548 + // | left ^ 549 + // >------->------------------->------>-| 550 + // e 551 + case N_Closure1: { 552 + // e 553 + // e <------ e 554 + // entry ---> before ------> after ---> exit 555 + // left 556 + int before = gen_state(); 557 + int after = gen_state(); 558 + add_e_transition( entry, before ); 559 + add_e_transition( after, exit ); 560 + add_e_transition( after, before ); 561 + gen_nfa( before, t->left.get(), after ); 562 + if( t->type != N_Closure1 ) 563 + add_e_transition( entry, exit ); 564 + } break; 565 + case N_01: 566 + // e 567 + // ------> 568 + // entry ------> exit 569 + // left 570 + add_e_transition( entry, exit ); 571 + gen_nfa( entry, t->left.get(), exit ); 572 + break; 573 + case N_Empty: 574 + // e 575 + // entry ---> exit 576 + add_e_transition( entry, exit ); 577 + break; 578 + } 579 +} 580 + 581 + 582 + 583 +//========================================================================= 584 +//@{ 585 +// マッチング 586 +//@} 587 +//========================================================================= 588 + 589 +void RegNFA::push(storage<st_ele>& stack, int curSt, int pos) 590 +{ 591 + // ε無限ループ防止策。同じ状態には戻らないように… 592 + for( int i=stack.size()-1; i>=0; --i ) 593 + if( stack[i].ps != pos ) 594 + break; 595 + else if( stack[i].st == curSt ) 596 + return; 597 + 598 + st_ele nw = {curSt,pos}; 599 + stack.Add( nw ); 600 +} 601 + 602 +RegNFA::st_ele RegNFA::pop(storage<st_ele>& stack) 603 +{ 604 + st_ele se = stack[stack.size()-1]; 605 + stack.ForceSize( stack.size()-1 ); 606 + return se; 607 +} 608 + 609 +int RegNFA::match( const wchar_t* str, int len, bool caseS ) 610 +{ 611 + if( parser.err() ) 612 + return -1; // エラー状態なのでmatchとかできません 613 + //if( st.size() <= 31 ) 614 + // return dfa_match(str,len,caseS); // 状態数が少なければDFAを使う、かも 615 + 616 + int matchpos = -1; 617 + 618 + storage<st_ele> stack; 619 + push(stack, start, 0); 620 + while( stack.size() > 0 ) 621 + { 622 + // スタックからpop 623 + st_ele se = pop(stack); 624 + int curSt = se.st; 625 + int pos = se.ps; 626 + 627 + // マッチ成功してたら記録 628 + if( curSt == final ) // 1==終状態 629 + if( matchpos < pos ) 630 + matchpos = pos; 631 + 632 + // さらに先の遷移を調べる 633 + if( matchpos < len ) 634 + for( RegTrans* tr=st[curSt]; tr!=NULL; tr=tr->next.get() ) 635 + if( tr->type == RegTrans::Epsilon ) 636 + push(stack, tr->to, pos); 637 + else if( pos<len && tr->match( str[pos], caseS ) ) 638 + push(stack, tr->to, pos+1); 639 + } 640 + 641 + return matchpos; 642 +} 643 + 644 +int RegNFA::dfa_match( const wchar_t* str, int len, bool caseS ) 645 +{ 646 + int matchpos = -1; 647 + 648 + unsigned int StateSet = (1<<start); 649 + for(int pos=0; StateSet; ++pos) 650 + { 651 + // ε-closure 652 + for(uint DifSS=StateSet; DifSS;) 653 + { 654 + unsigned int NewSS = 0; 655 + for(int s=0; (1u<<s)<=DifSS; ++s) 656 + if( (1u<<s) & DifSS ) 657 + for( RegTrans* tr=st[s]; tr!=NULL; tr=tr->next.get() ) 658 + if( tr->type == RegTrans::Epsilon ) 659 + NewSS |= 1u << tr->to; 660 + DifSS = (NewSS|StateSet) ^ StateSet; 661 + StateSet |= NewSS; 662 + } 663 + 664 + // 受理状態を含んでるかどうか判定 665 + if( StateSet & (1<<final) ) 666 + matchpos = pos; 667 + 668 + // 文字列の終わりに達した 669 + if( pos == len ) 670 + break; 671 + 672 + // 遷移 673 + unsigned int NewSS = 0; 674 + for(int s=0; (1u<<s)<=StateSet; ++s) 675 + if( (1u<<s) & StateSet ) 676 + for( RegTrans* tr=st[s]; tr!=NULL; tr=tr->next.get() ) 677 + if( tr->type!=RegTrans::Epsilon && tr->match(str[pos], caseS) ) 678 + NewSS |= 1u << tr->to; 679 + StateSet = NewSS; 680 + } 681 + 682 + return matchpos; 683 +} 684 + 685 +////////////////////////////////////////////////////////////////////// 686 + 687 +bool reg_match( const wchar_t* pat, const wchar_t* str, bool caseS ) 688 +{ 689 + int len = my_lstrlenW(str); 690 + 691 + RegNFA re( pat ); 692 + return len == re.match( str, len, caseS ); 693 +} 694 + 695 + 696 + 697 +//========================================================================= 698 +//@{ 699 +// GreenPad用検索オブジェクト 700 +//@} 701 +//========================================================================= 702 + 703 +RSearch::RSearch( const unicode* key, bool caseS, bool down ) 704 + : re_ ( new RegNFA(key) ) 705 + , caseS_ ( caseS ) 706 + , down_ ( down ) 707 +{ 708 +} 709 + 710 +bool RSearch::Search( 711 + const unicode* str, ulong len, ulong stt, ulong* mbg, ulong* med ) 712 +{ 713 + if( down_ && re_->isHeadType() && stt>0 ) 714 + return false; 715 + 716 + const int d = (down_ ? 1 : -1); 717 + int s = (!down_ && re_->isHeadType() ? 0 : stt); 718 + const int e = (down_ ? (re_->isHeadType() ? 1 : (long)len) : -1); 719 + 720 + for( ; s!=e; s+=d ) 721 + { 722 + const int L = re_->match( str+s, len-s, caseS_ ); 723 + if( L > 0 ) 724 + { 725 + if( re_->isTailType() && L!=static_cast<int>(len-s) ) 726 + continue; 727 + *mbg = static_cast<ulong>(s); 728 + *med = static_cast<ulong>(s+L); 729 + return true; 730 + } 731 + } 732 + 733 + return false; 734 +} 735 + 736 +
Added RSearch.h version [a1c854d162219a9e]
1 +#ifndef AFX_RSEARCH_H__5A9346D4_3152_4923_8EFC_38264A456364__INCLUDED_ 2 +#define AFX_RSEARCH_H__5A9346D4_3152_4923_8EFC_38264A456364__INCLUDED_ 3 +#include "kilib/ktlaptr.h" 4 +#include "NSearch.h" 5 + 6 + 7 +//========================================================================= 8 +//@{ @pkg Gp.Search //@} 9 +//@{ 10 +// 超簡易正規表現マッチング関数。 11 +// 12 +// patとstr全体がマッチするならtrue、ダメならfalseを返す 13 +//@} 14 +//========================================================================= 15 + 16 +bool reg_match( const wchar_t* pat, const wchar_t* str, bool caseS ); 17 + 18 + 19 +class RegNFA; 20 +//========================================================================= 21 +//@{ 22 +// Searhcableとしての実装 23 +//@} 24 +//========================================================================= 25 + 26 +class RSearch : public Searchable 27 +{ 28 +public: 29 + RSearch( const unicode* key, bool caseS, bool down ); 30 + 31 +private: 32 + virtual bool Search( const unicode* str, ulong len, ulong stt, 33 + ulong* mbg, ulong* med ); 34 + 35 +private: 36 + ki::dptr<RegNFA> re_; 37 + bool caseS_; 38 + bool down_; 39 +}; 40 + 41 + 42 + 43 + 44 + 45 +#endif
Added Search.cpp version [8394be04b45c45f1]
1 + 2 +#include "stdafx.h" 3 +#include "rsrc/resource.h" 4 +#include "Search.h" 5 +#include "NSearch.h" 6 +#include "RSearch.h" 7 +using namespace ki; 8 +using namespace editwing; 9 +using view::VPos; 10 + 11 + 12 + 13 +//------------------------------------------------------------------------- 14 + 15 +SearchManager::SearchManager( ki::Window& w, editwing::EwEdit& e ) 16 + : searcher_( NULL ) 17 + , edit_( e ) 18 + , DlgImpl( IDD_FINDREPLACE ) 19 + , bIgnoreCase_( true ) // 1.08 default true 20 + , bRegExp_( false ) 21 + , bDownSearch_( true ) 22 + , mainWnd_( w ) 23 +{ 24 +} 25 + 26 +SearchManager::~SearchManager() 27 +{ 28 +} 29 + 30 +void SearchManager::SaveToINI( ki::IniFile& ini ) 31 +{ 32 + ini.SetSectionAsUserName(); 33 + ini.PutBool( TEXT("SearchIgnoreCase"), bIgnoreCase_ ); 34 + ini.PutBool( TEXT("SearchRegExp"), bRegExp_ ); 35 +} 36 + 37 +void SearchManager::LoadFromINI( ki::IniFile& ini ) 38 +{ 39 + ini.SetSectionAsUserName(); 40 + bIgnoreCase_ = ini.GetBool( TEXT("SearchIgnoreCase"), bIgnoreCase_ ); 41 + bRegExp_ = ini.GetBool( TEXT("SearchRegExp"), bRegExp_ ); 42 +} 43 + 44 +//------------------------------------------------------------------------- 45 +// ダイアログ関係 46 +//------------------------------------------------------------------------- 47 + 48 +void SearchManager::ShowDlg() 49 +{ 50 +// GoModal( ::GetParent(edit_.hwnd()) ); 51 + if( isAlive() ) 52 + { 53 + SetFront(); 54 + } 55 + else 56 + { 57 + GoModeless( ::GetParent(edit_.hwnd()) ); 58 + ShowUp(); 59 + } 60 +} 61 + 62 +bool SearchManager::TrapMsg(MSG* msg) 63 +{ 64 + if( ! isAlive() || type()==MODAL ) 65 + return false; 66 + return DlgImpl::PreTranslateMessage(msg); 67 +} 68 + 69 +void SearchManager::on_init() 70 +{ 71 + if( bIgnoreCase_ ) 72 + SendMsgToItem( IDC_IGNORECASE, BM_SETCHECK, BST_CHECKED ); 73 + if( bRegExp_ ) 74 + SendMsgToItem( IDC_REGEXP, BM_SETCHECK, BST_CHECKED ); 75 + 76 + if( edit_.getCursor().isSelected() ) 77 + { 78 + // 選択されている状態では、基本的にそれをボックスに表示 79 + ulong dmy; 80 + aarr<unicode> str = edit_.getCursor().getSelectedStr(); 81 + 82 + ulong len=0; 83 + for( ; str[len]!=L'\0' && str[len]!=L'\n'; ++len ); 84 + str[len] = L'\0'; 85 + 86 + if( searcher_.isValid() && 87 + searcher_->Search( str.get(), len, 0, &dmy, &dmy ) ) 88 + { 89 + SendMsgToItem( IDC_FINDBOX, WM_SETTEXT, 0, 90 + reinterpret_cast<LPARAM>(findStr_.c_str()) ); 91 + } 92 + else 93 + { 94 + #ifdef _UNICODE 95 + SendMsgToItem( IDC_FINDBOX, WM_SETTEXT, 0, 96 + reinterpret_cast<LPARAM>(str.get()) ); 97 + #else 98 + ki::aarr<char> ab( new TCHAR[(len+1)*3] ); 99 + ::WideCharToMultiByte( CP_ACP, 0, str.get(), -1, 100 + ab.get(), (len+1)*3, NULL, NULL ); 101 + SendMsgToItem( IDC_FINDBOX, WM_SETTEXT, 0, 102 + reinterpret_cast<LPARAM>(ab.get()) ); 103 + #endif 104 + } 105 + } 106 + else 107 + { 108 + SendMsgToItem( IDC_FINDBOX, WM_SETTEXT, 0, 109 + reinterpret_cast<LPARAM>(findStr_.c_str()) ); 110 + } 111 + 112 + SendMsgToItem( IDC_REPLACEBOX, WM_SETTEXT, 0, 113 + reinterpret_cast<LPARAM>(replStr_.c_str()) ); 114 + 115 + ::SetFocus( item(IDC_FINDBOX) ); 116 + SendMsgToItem( IDC_FINDBOX, EM_SETSEL, 0, 117 + ::GetWindowTextLength(item(IDC_FINDBOX)) ); 118 +} 119 + 120 +void SearchManager::on_destroy() 121 +{ 122 + bChanged_ = false; 123 +} 124 + 125 +bool SearchManager::on_command( UINT cmd, UINT id, HWND ctrl ) 126 +{ 127 + if( cmd==EN_CHANGE ) 128 + { 129 + // 文字列変更があったことを記憶 130 + bChanged_ = true; 131 + } 132 + else if( cmd==BN_CLICKED ) 133 + { 134 + switch( id ) 135 + { 136 + // チェックボックスの変更があったことを記憶 137 + case IDC_IGNORECASE: 138 + case IDC_REGEXP: 139 + bChanged_ = true; 140 + break; 141 + // ボタンが押された場合 142 + case ID_FINDNEXT: 143 + on_findnext(); 144 + break; 145 + case ID_FINDPREV: 146 + on_findprev(); 147 + break; 148 + case ID_REPLACENEXT: 149 + on_replacenext(); 150 + break; 151 + case ID_REPLACEALL: 152 + on_replaceall(); 153 + break; 154 + } 155 + } 156 + else 157 + { 158 + return false; 159 + } 160 + return true; 161 +} 162 + 163 +void SearchManager::on_findnext() 164 +{ 165 + UpdateData(); 166 + ConstructSearcher(); 167 + if( isReady() ) 168 + { 169 + FindNextImpl(); 170 +// End( IDOK ); 171 + } 172 +} 173 + 174 +void SearchManager::on_findprev() 175 +{ 176 + UpdateData(); 177 + ConstructSearcher( false ); 178 + if( isReady() ) 179 + FindPrevImpl(); 180 +} 181 + 182 +void SearchManager::on_replacenext() 183 +{ 184 + UpdateData(); 185 + ConstructSearcher(); 186 + if( isReady() ) 187 + ReplaceImpl(); 188 +} 189 + 190 +void SearchManager::on_replaceall() 191 +{ 192 + UpdateData(); 193 + ConstructSearcher(); 194 + if( isReady() ) 195 + ReplaceAllImpl(); 196 +} 197 + 198 +void SearchManager::UpdateData() 199 +{ 200 + // ダイアログから変更点を取り込み 201 + bIgnoreCase_ = 202 + (BST_CHECKED==SendMsgToItem( IDC_IGNORECASE, BM_GETCHECK )); 203 + bRegExp_ = 204 + (BST_CHECKED==SendMsgToItem( IDC_REGEXP, BM_GETCHECK )); 205 + 206 + TCHAR* str; 207 + LRESULT n = SendMsgToItem( IDC_FINDBOX, WM_GETTEXTLENGTH ); 208 + str = new TCHAR[n+1]; 209 + SendMsgToItem( IDC_FINDBOX, WM_GETTEXT, 210 + n+1, reinterpret_cast<LPARAM>(str) ); 211 + findStr_ = str; 212 + delete [] str; 213 + 214 + n = SendMsgToItem( IDC_REPLACEBOX, WM_GETTEXTLENGTH ); 215 + str = new TCHAR[n+1]; 216 + SendMsgToItem( IDC_REPLACEBOX, WM_GETTEXT, 217 + n+1, reinterpret_cast<LPARAM>(str) ); 218 + replStr_ = str; 219 + delete [] str; 220 +} 221 + 222 +void SearchManager::ConstructSearcher( bool down ) 223 +{ 224 + bChanged_ = (bChanged_ || (bDownSearch_ != down)); 225 + if( (bChanged_ || !isReady()) && findStr_.len()!=0 ) 226 + { 227 + // 検索者作成 228 + bDownSearch_ = down; 229 + const unicode *u = findStr_.ConvToWChar(); 230 + 231 + if( bRegExp_ ) 232 + searcher_ = new RSearch( u, !bIgnoreCase_, bDownSearch_ ); 233 + else 234 + if( bDownSearch_ ) 235 + if( bIgnoreCase_ ) 236 + searcher_ = new NSearch<IgnoreCase>(u); 237 + else 238 + searcher_ = new NSearch<CaseSensitive>(u); 239 + else 240 + if( bIgnoreCase_ ) 241 + searcher_ = new NSearchRev<IgnoreCase>(u); 242 + else 243 + searcher_ = new NSearchRev<CaseSensitive>(u); 244 + 245 + findStr_.FreeWCMem(u); 246 + 247 + // 変更終了フラグ 248 + bChanged_ = false; 249 + } 250 +} 251 + 252 + 253 + 254 +//------------------------------------------------------------------------- 255 + 256 +void SearchManager::FindNext() 257 +{ 258 + if( !isReady() ) 259 + { 260 + ShowDlg(); 261 + } 262 + else 263 + { 264 + ConstructSearcher(); 265 + if( isReady() ) 266 + FindNextImpl(); 267 + } 268 +} 269 + 270 +void SearchManager::FindPrev() 271 +{ 272 + if( !isReady() ) 273 + { 274 + ShowDlg(); 275 + } 276 + else 277 + { 278 + ConstructSearcher( false ); 279 + if( isReady() ) 280 + FindPrevImpl(); 281 + } 282 +} 283 + 284 + 285 + 286 +//------------------------------------------------------------------------- 287 +// 実際の処理の実装 288 +//------------------------------------------------------------------------- 289 + 290 +void SearchManager::FindNextImpl() 291 +{ 292 + // カーソル位置取得 293 + const VPos *stt, *end; 294 + edit_.getCursor().getCurPos( &stt, &end ); 295 + 296 + // 選択範囲ありなら、選択範囲先頭の1文字先から検索 297 + // そうでなければカーソル位置から検索 298 + DPos s = *stt; 299 + if( *stt != *end ) 300 + if( stt->ad == edit_.getDoc().len(stt->tl) ) 301 + s = DPos( stt->tl+1, 0 ); 302 + else 303 + s = DPos( stt->tl, stt->ad+1 ); 304 + 305 + // 検索 306 + DPos b, e; 307 + if( FindNextFromImpl( s, &b, &e ) ) 308 + { 309 + // 見つかったら選択 310 + edit_.getCursor().MoveCur( b, false ); 311 + edit_.getCursor().MoveCur( e, true ); 312 + return; 313 + } 314 + 315 + // 見つからなかった場合 316 + NotFound(); 317 +} 318 + 319 +void SearchManager::NotFound() 320 +{ 321 + //MsgBox( String(IDS_NOTFOUND).c_str() ); 322 + ::MessageBox( NULL, String(IDS_NOTFOUND).c_str(), NULL, MB_OK|MB_TASKMODAL ); 323 +} 324 + 325 +void SearchManager::FindPrevImpl() 326 +{ 327 + // カーソル位置取得 328 + const VPos *stt, *end; 329 + edit_.getCursor().getCurPos( &stt, &end ); 330 + 331 + if( stt->ad!=0 || stt->tl!=0 ) 332 + { 333 + // 選択範囲先頭の1文字前から検索 334 + DPos s; 335 + if( stt->ad == 0 ) 336 + s = DPos( stt->tl-1, edit_.getDoc().len(stt->tl-1) ); 337 + else 338 + s = DPos( stt->tl, stt->ad-1 ); 339 + 340 + // 検索 341 + DPos b, e; 342 + if( FindPrevFromImpl( s, &b, &e ) ) 343 + { 344 + // 見つかったら選択 345 + edit_.getCursor().MoveCur( b, false ); 346 + edit_.getCursor().MoveCur( e, true ); 347 + return; 348 + } 349 + } 350 + 351 + // 見つからなかった場合 352 + NotFound(); 353 +} 354 + 355 +bool SearchManager::FindNextFromImpl( DPos s, DPos* beg, DPos* end ) 356 +{ 357 + // 1行ずつサーチ 358 + doc::Document& d = edit_.getDoc(); 359 + for( ulong mbg,med,e=d.tln(); s.tl<e; ++s.tl, s.ad=0 ) 360 + if( searcher_->Search( 361 + d.tl(s.tl), d.len(s.tl), s.ad, &mbg, &med ) ) 362 + { 363 + beg->tl = end->tl = s.tl; 364 + beg->ad = mbg; 365 + end->ad = med; 366 + return true; // 発見 367 + } 368 + return false; 369 +} 370 + 371 +bool SearchManager::FindPrevFromImpl( DPos s, DPos* beg, DPos* end ) 372 +{ 373 + // 1行ずつサーチ 374 + doc::Document& d = edit_.getDoc(); 375 + for( ulong mbg,med; ; s.ad=d.len(--s.tl) ) 376 + { 377 + if( searcher_->Search( 378 + d.tl(s.tl), d.len(s.tl), s.ad, &mbg, &med ) ) 379 + { 380 + beg->tl = end->tl = s.tl; 381 + beg->ad = mbg; 382 + end->ad = med; 383 + return true; // 発見 384 + } 385 + if( s.tl==0 ) 386 + break; 387 + } 388 + return false; 389 +} 390 + 391 +void SearchManager::ReplaceImpl() 392 +{ 393 + // カーソル位置取得 394 + const VPos *stt, *end; 395 + edit_.getCursor().getCurPos( &stt, &end ); 396 + 397 + // 選択範囲先頭から検索 398 + DPos b, e; 399 + if( FindNextFromImpl( *stt, &b, &e ) ) 400 + if( e == *end ) 401 + { 402 + const wchar_t* ustr = replStr_.ConvToWChar(); 403 + const ulong ulen = my_lstrlenW( ustr ); 404 + 405 + // 置換 406 + edit_.getDoc().Execute( doc::Replace( 407 + b, e, ustr, ulen 408 + ) ); 409 + 410 + replStr_.FreeWCMem( ustr ); 411 + 412 + if( FindNextFromImpl( DPos(b.tl,b.ad+ulen), &b, &e ) ) 413 + { 414 + // 次を選択 415 + edit_.getCursor().MoveCur( b, false ); 416 + edit_.getCursor().MoveCur( e, true ); 417 + return; 418 + } 419 + } 420 + else 421 + { 422 + // そうでなければとりあえず選択 423 + edit_.getCursor().MoveCur( b, false ); 424 + edit_.getCursor().MoveCur( e, true ); 425 + return; 426 + } 427 + 428 + // 見つからなかった場合 429 + NotFound(); 430 +} 431 + 432 +void SearchManager::ReplaceAllImpl() 433 +{ 434 + // まず、実行する置換を全てここに登録する 435 + doc::MacroCommand mcr; 436 + 437 + // 置換後文字列 438 + const wchar_t* ustr = replStr_.ConvToWChar(); 439 + const ulong ulen = my_lstrlenW( ustr ); 440 + 441 + // 文書の頭から検索 442 + int dif=0; 443 + DPos s(0,0), b, e; 444 + while( FindNextFromImpl( s, &b, &e ) ) 445 + { 446 + if( s.tl != b.tl ) dif = 0; 447 + s = e; 448 + 449 + // 置換コマンドを登録 450 + b.ad += dif, e.ad += dif; 451 + mcr.Add( new doc::Replace(b,e,ustr,ulen) ); 452 + dif -= e.ad-b.ad-ulen; 453 + } 454 + 455 + if( mcr.size() > 0 ) 456 + { 457 + // ここで連続置換 458 + edit_.getDoc().Execute( mcr ); 459 + // カーソル移動 460 + e.ad = b.ad + ulen; 461 + edit_.getCursor().MoveCur( e, false ); 462 + // 閉じる? 463 + End( IDOK ); 464 + } 465 + 466 + TCHAR str[255]; 467 + ::wsprintf( str, String(IDS_REPLACEALLDONE).c_str(), mcr.size() ); 468 + MsgBox( str, String(IDS_APPNAME).c_str(), MB_ICONINFORMATION ); 469 + 470 + replStr_.FreeWCMem( ustr ); 471 +}
Added Search.h version [6119f23431c544ed]
1 +#ifndef AFX_SEARCH_H__201E0D70_9C20_420A_8600_966D2BA23010__INCLUDED_ 2 +#define AFX_SEARCH_H__201E0D70_9C20_420A_8600_966D2BA23010__INCLUDED_ 3 +#include "editwing/editwing.h" 4 +#include "kilib/window.h" 5 +#include "kilib/memory.h" 6 +#include "kilib/ktlaptr.h" 7 +#include "kilib/string.h" 8 + 9 + 10 + 11 +//========================================================================= 12 +//@{ @pkg Gp.Search //@} 13 +//@{ 14 +// 検索オブジェクト 15 +//@} 16 +//========================================================================= 17 + 18 +class Searchable : public ki::Object 19 +{ 20 +public: 21 + //@{ 22 + // 検索を行う 23 + // @param str 対象文字列 24 + // @param len 対象文字列の長さ 25 + // @param stt 検索開始index。0なら先頭から 26 + // @param mbg マッチ結果の先頭index 27 + // @param med マッチ結果の終端indexの1個後ろ 28 + // @return マッチしたかどうか 29 + // 30 + // 下方向サーチオブジェクトの場合、stt <= *beg の範囲 31 + // 上方向サーチオブジェクトの場合、*beg <= stt の範囲を検索 32 + //@} 33 + virtual bool Search( const unicode* str, ulong len, ulong stt, 34 + ulong* mbg, ulong* med ) = 0; 35 +}; 36 + 37 + 38 + 39 +//========================================================================= 40 +//@{ 41 +// 検索管理人 42 +// 43 +// 前回検索したときのオプションや検索文字列を覚えておくのが 44 +// このクラスの担当。検索・置換ダイアログの表示等もここで 45 +// やるかもしれない。 46 +//@} 47 +//========================================================================= 48 + 49 +class SearchManager : ki::DlgImpl 50 +{ 51 + typedef editwing::DPos DPos; 52 + 53 +public: 54 + //@{ コンストラクタ。特記事項無し //@} 55 + SearchManager( ki::Window& w, editwing::EwEdit& e ); 56 + 57 + //@{ デストラクタ。特記事項無し //@} 58 + ~SearchManager(); 59 + 60 + //@{ 検索ダイアログ表示 //@} 61 + void ShowDlg(); 62 + 63 + //@{ [次を検索]コマンド //@} 64 + void FindNext(); 65 + 66 + //@{ [前を検索]コマンド //@} 67 + void FindPrev(); 68 + 69 + //@{ 今すぐ検索可能か? //@} 70 + bool isReady() const 71 + { return searcher_.isValid(); } 72 + 73 + //@{ 設定Save //@} 74 + void SaveToINI( ki::IniFile& ini ); 75 + 76 + //@{ 設定Load //@} 77 + void LoadFromINI( ki::IniFile& ini ); 78 + 79 + //@{ 苦肉の策^^; //@} 80 + bool TrapMsg(MSG* msg); 81 + 82 + //@{ 見つかりませんでしたダイアログ //@} 83 + void NotFound(); 84 + 85 +private: 86 + 87 + //@{ [置換]コマンド //@} 88 + void ReplaceImpl(); 89 + 90 + //@{ [全置換]コマンド //@} 91 + void ReplaceAllImpl(); 92 + 93 +private: 94 + 95 + virtual void on_init(); 96 + virtual void on_destroy(); 97 + virtual bool on_command( UINT cmd, UINT id, HWND ctrl ); 98 + void on_findnext(); 99 + void on_findprev(); 100 + void on_replacenext(); 101 + void on_replaceall(); 102 + void UpdateData(); 103 + void ConstructSearcher( bool down=true ); 104 + void FindNextImpl(); 105 + void FindPrevImpl(); 106 + bool FindNextFromImpl( DPos s, DPos* beg, DPos* end ); 107 + bool FindPrevFromImpl( DPos s, DPos* beg, DPos* end ); 108 + 109 +private: 110 + editwing::EwEdit& edit_; 111 + ki::dptr<Searchable> searcher_; 112 + ki::Window& mainWnd_; 113 + 114 + bool bIgnoreCase_; // 大文字小文字を同一視? 115 + bool bRegExp_; // 正規表現? 116 + bool bDownSearch_; // 検索方向 117 + bool bChanged_; // 前回のsearcher構築時から変更があったらtrue 118 + 119 + ki::String findStr_; 120 + ki::String replStr_; 121 + 122 +private: 123 + NOCOPY(SearchManager); 124 +}; 125 + 126 + 127 + 128 +//========================================================================= 129 + 130 +#endif // AFX_SEARCH_H__201E0D70_9C20_420A_8600_966D2BA23010__INCLUDED_
Added editwing/editwing.h version [cb99f56b2add4e68]
1 +#ifndef _EDITWING_H_ 2 +#define _EDITWING_H_ 3 + 4 + 5 + 6 +#include "ewCommon.h" 7 +#include "ewCtrl1.h" 8 + 9 + 10 + 11 +#endif // _EDITWING_H_
Added editwing/ewCommon.h version [629245f9abbd51b3]
1 +#ifndef _EDITWING_COMMON_H_ 2 +#define _EDITWING_COMMON_H_ 3 +#include "../kilib/kilib.h" 4 +#ifndef __ccdoc__ 5 +namespace editwing { 6 +#endif 7 + 8 + 9 +//========================================================================= 10 +// Unicode関係 11 +//========================================================================= 12 + 13 +inline bool isHighSurrogate(unicode ch) 14 +{ 15 + return (0xD800 <= ch && ch <= 0xDBFF); 16 +} 17 + 18 +inline bool isLowSurrogate(unicode ch) 19 +{ 20 + return (0xDC00 <= ch && ch <= 0xDFFF); 21 +} 22 + 23 +//========================================================================= 24 +//@{ @pkg editwing.Common //@} 25 +//@{ 26 +// テキスト中の位置情報 27 +//@} 28 +//========================================================================= 29 + 30 +struct DPos : public ki::Object 31 +{ 32 + //@{ バッファ中のアドレス (0〜 ) //@} 33 + ulong ad; 34 + 35 + //@{ 論理行番号 (0〜 ) //@} 36 + ulong tl; 37 + 38 + bool operator == ( const DPos& r ) const 39 + { return (tl==r.tl && ad==r.ad); } 40 + bool operator != ( const DPos& r ) const 41 + { return (tl!=r.tl || ad!=r.ad); } 42 + bool operator < ( const DPos& r ) const 43 + { return (tl<r.tl || (tl==r.tl && ad<r.ad)); } 44 + bool operator > ( const DPos& r ) const 45 + { return (tl>r.tl || (tl==r.tl && ad>r.ad)); } 46 + bool operator <= ( const DPos& r ) const 47 + { return (tl<r.tl || (tl==r.tl && ad<=r.ad)); } 48 + bool operator >= ( const DPos& r ) const 49 + { return (tl>r.tl || (tl==r.tl && ad>=r.ad)); } 50 + 51 + DPos( ulong t, ulong a ) : tl(t), ad(a) {} 52 + DPos() {} 53 +}; 54 + 55 + 56 + 57 +//========================================================================= 58 +//@{ 59 +// 特殊文字を表す定数値 60 +//@} 61 +//========================================================================= 62 + 63 +enum SpecialChars 64 +{ 65 + scEOF = 0, // EOF 66 + scEOL = 1, // 改行 67 + scTAB = 2, // タブ 68 + scHSP = 3, // 半角スペース 69 + scZSP = 4 // 全角スペース 70 +}; 71 + 72 + 73 + 74 +//========================================================================= 75 +//@{ 76 +// 単語の種類を表す定数値 77 +//@} 78 +//========================================================================= 79 + 80 +enum TokenType 81 +{ 82 + TAB = 0x00, // Tab 83 + WSP = 0x04, // 半角スペース 84 + ALP = 0x08, // 普通の字 85 + CE = 0x0c, // コメント終了タグ 86 + CB = 0x10, // コメント開始タグ 87 + LB = 0x14, // 行コメント開始タグ 88 + Q1 = 0x18, // 単一引用符 89 + Q2 = 0x1c // 二重引用符 90 +}; 91 + 92 + 93 + 94 +//========================================================================= 95 +//@{ 96 +// 色指定箇所を表す定数値 97 +//@} 98 +//========================================================================= 99 + 100 +enum ColorType 101 +{ 102 + TXT = 0, // 文字色 103 + CMT = 1, // コメント文字色 104 + KWD = 2, // キーワード文字色 105 + // = 3, // ( コメントアウトされたキーワード文字色 ) 106 + CTL = 4, // 特殊文字色 107 + BG = 5, // 背景色 108 + LN = 6 // 行番号 109 +}; 110 + 111 + 112 + 113 +//========================================================================= 114 +//@{ 115 +// 折り返し位置を示す定数値 116 +//@} 117 +//========================================================================= 118 + 119 +enum WrapType 120 +{ 121 + NOWRAP = -1, // 折り返し無し 122 + RIGHTEDGE = 0 // 右端 123 +}; 124 + 125 + 126 + 127 +//========================================================================= 128 +//@{ 129 +// 表示設定 130 +// 131 +// フォント・色・タブ幅・特殊文字の表示、の情報を保持。 132 +// ただし、強調単語の指定は Document に対して行う。 133 +//@} 134 +//========================================================================= 135 + 136 +struct VConfig : public ki::Object 137 +{ 138 + //@{ フォント //@} 139 + LOGFONT font; 140 + int fontsize; 141 + 142 + //@{ タブ幅文字数 //@} 143 + int tabstep; 144 + 145 + //@{ 色 //@} 146 + COLORREF color[7]; 147 + 148 + //@{ 特殊文字表示 //@} 149 + bool sc[5]; 150 + 151 + //@{ 危険なデフォルトコンストラクタ //@} 152 + VConfig() {} 153 + 154 + //@{ フォント関係初期化 //@} 155 + VConfig( const TCHAR* fnam, int fsiz ) 156 + { 157 + SetFont( fnam,fsiz ); 158 + tabstep = 4; 159 + color[TXT] = 160 + color[CMT] = 161 + color[KWD] = 162 + color[CTL] = RGB(0,0,0); 163 + color[ BG] = RGB(255,255,255); 164 + color[ LN] = RGB(0,0,0);//255,255,0); 165 + sc[scEOF] = 166 + sc[scEOL] = 167 + sc[scTAB] = 168 + sc[scHSP] = 169 + sc[scZSP] = false; 170 + } 171 + 172 + //@{ フォント関係設定 //@} 173 + void SetFont( const TCHAR* fnam, int fsiz ) 174 + { 175 + fontsize = fsiz; 176 + font.lfWidth = 0; 177 + font.lfEscapement = 0; 178 + font.lfOrientation = 0; 179 + font.lfWeight = FW_DONTCARE; 180 + font.lfItalic = FALSE; 181 + font.lfUnderline = FALSE; 182 + font.lfStrikeOut = FALSE; 183 + font.lfOutPrecision = OUT_DEFAULT_PRECIS; 184 + font.lfClipPrecision = CLIP_DEFAULT_PRECIS; 185 + font.lfQuality = DEFAULT_QUALITY; 186 + font.lfPitchAndFamily = VARIABLE_PITCH|FF_DONTCARE; 187 + font.lfCharSet = DEFAULT_CHARSET; 188 + 189 + ::lstrcpy( font.lfFaceName, fnam ); 190 + 191 + HDC h = ::GetDC( NULL ); 192 + font.lfHeight = -MulDiv(fsiz, ::GetDeviceCaps(h,LOGPIXELSY), 72); 193 + ::ReleaseDC( NULL, h ); 194 + } 195 + 196 + //@{ タブ幅設定 //@} 197 + void SetTabStep( int tab ) 198 + { 199 + tabstep = Max( 1, tab ); 200 + } 201 +}; 202 + 203 + 204 + 205 +//========================================================================= 206 + 207 +} // namespace editwing 208 +#endif // _EDITWING_COMMON_H_
Added editwing/ewCtrl1.h version [3cf45a69ba982b03]
1 +#ifndef _EDITWING_CTRL1_H_ 2 +#define _EDITWING_CTRL1_H_ 3 +#include "ewDoc.h" 4 +#include "ewView.h" 5 +#ifndef __ccdoc__ 6 +namespace editwing { 7 +#endif 8 + 9 + 10 + 11 +//========================================================================= 12 +//@{ @pkg editwing.Ctrl //@} 13 +//@{ 14 +// 簡単なエディットコントロール 15 +// 16 +// とりあえず字が表示できて色が変えられてカーソルが動かせて… 17 +// という、Doc/Viewの基本機能をそのまま使った形のもの。 18 +// ウインドウ分割対応版とかもそのうち作るかもしれない。 19 +//@} 20 +//========================================================================= 21 + 22 +class EwEdit : public ki::WndImpl 23 +{ 24 +public: 25 + 26 + EwEdit(); 27 + ~EwEdit(); 28 + 29 +public: 30 + 31 + //@{ 文書データ操作 //@} 32 + doc::Document& getDoc() { return *doc_; } 33 + 34 + //@{ 表示機能操作 //@} 35 + view::View& getView() { return *view_; } 36 + 37 + //@{ カーソル機能操作 //@} 38 + view::Cursor& getCursor() { return view_->cur(); } 39 + 40 +private: 41 + 42 + ki::dptr<doc::Document> doc_; 43 + ki::dptr<view::View> view_; 44 + static ClsName className_; 45 + 46 +private: 47 + 48 + void on_create( CREATESTRUCT* cs ); 49 + void on_destroy(); 50 + LRESULT on_message( UINT msg, WPARAM wp, LPARAM lp ); 51 +}; 52 + 53 + 54 + 55 +//========================================================================= 56 + 57 +} // namespace editwing 58 +#endif // _EDITWING_CTRL1_H_
Added editwing/ewDoc.h version [f62bdbf2e74c7d8b]
1 +#ifndef _EDITWING_DOC_H_ 2 +#define _EDITWING_DOC_H_ 3 +#include "ewCommon.h" 4 +#ifndef __ccdoc__ 5 +namespace editwing { 6 +namespace doc { 7 +#endif 8 + 9 + 10 + 11 +class DocImpl; 12 +class DocEvHandler; 13 +class Command; 14 +class Insert; 15 +class Delete; 16 +class Replace; 17 + 18 + 19 + 20 +//========================================================================= 21 +//@{ @pkg editwing.Doc //@} 22 +//@{ 23 +// 文書データ 24 +// 25 +// このクラスは単なるインターフェイスで、内部実装は 26 +// class DocImpl で行う。ので、詳しくはそちらを参照のこと。 27 +//@} 28 +//========================================================================= 29 + 30 +class Document : public ki::Object 31 +{ 32 +public: 33 + 34 + //@{ 何もしないコンストラクタ //@} 35 + Document(); 36 + ~Document(); 37 + 38 + //@{ ファイルを開く //@} 39 + void OpenFile( ki::aptr<ki::TextFileR> tf ); 40 + 41 + //@{ ファイルを保存 //@} 42 + void SaveFile( ki::TextFileW& tf ); 43 + 44 + //@{ 内容破棄 //@} 45 + void ClearAll(); 46 + 47 + //@{ 操作コマンド実行 //@} 48 + void Execute( const Command& cmd ); 49 + 50 + //@{ アンドゥ //@] 51 + void Undo(); 52 + 53 + //@{ リドゥ //@] 54 + void Redo(); 55 + 56 + //@{ アンドゥ回数制限 //@] 57 + void SetUndoLimit( long lim ); 58 + 59 + //@{ 変更フラグをクリア //@} 60 + void ClearModifyFlag(); 61 + 62 + //@{ イベントハンドラ登録 //@} 63 + void AddHandler( DocEvHandler* eh ); 64 + 65 + //@{ イベントハンドラ解除 //@} 66 + void DelHandler( DocEvHandler* eh ); 67 + 68 + //@{ キーワード定義切り替え //@} 69 + void SetKeyword( const unicode* defbuf, ulong siz=0 ); 70 + 71 +public: 72 + 73 + //@{ 内部実装クラス //@} 74 + DocImpl& impl() { return *impl_; } 75 + 76 + //@{ 行数 //@} 77 + ulong tln() const; 78 + 79 + //@{ 行バッファ //@} 80 + const unicode* tl( ulong i ) const; 81 + 82 + //@{ 行文字数 //@} 83 + ulong len( ulong i ) const; 84 + 85 + //@{ 指定範囲のテキストの長さ //@} 86 + ulong getRangeLength( const DPos& stt, const DPos& end ) const; 87 + 88 + //@{ 指定範囲のテキスト //@} 89 + void getText( unicode* buf, const DPos& stt, const DPos& end ) const; 90 + 91 + //@{ アンドゥ可能? //@} 92 + bool isUndoAble() const; 93 + 94 + //@{ リドゥ可能? //@} 95 + bool isRedoAble() const; 96 + 97 + //@{ 変更済み? //@} 98 + bool isModified() const; 99 + 100 + //@{ ビジーフラグ(マクロコマンド実行中のみ成立) //@} 101 + void setBusyFlag( bool b=true ) { busy_ = b; } 102 + bool isBusy() const { return busy_; } 103 + 104 +private: 105 + 106 + // 実装 107 + ki::dptr<DocImpl> impl_; 108 + bool busy_; 109 + 110 +private: 111 + 112 + NOCOPY(Document); 113 +}; 114 + 115 + 116 + 117 +//========================================================================= 118 +//@{ 119 +// イベントハンドラインターフェイス 120 +// 121 +// ドキュメントから発生するイベント(挿入/削除などなど…)を 122 +// 受け取りたい場合は、このインターフェイスを継承し、適宜ハンドラを 123 +// 書くこと。Viewの再描画処理などもこれを通じて実行されている。 124 +//@} 125 +//========================================================================= 126 + 127 +class DocEvHandler 128 +{ 129 +public: 130 + //@{ 131 + // テキスト内容が変更されたときに発生 132 + // @param s 変更範囲の先頭 133 + // @param e 変更範囲の終端(前) 134 + // @param e2 変更範囲の終端(後) 135 + // @param reparsed e2より後ろのコメントアウト状態が変化していたらtrue 136 + // @param nmlcmd 挿入/削除/置換ならtrue、ファイル開き/全置換ならfalse 137 + //@} 138 + virtual void on_text_update( const DPos& s, 139 + const DPos& e, const DPos& e2, bool reparsed, bool nmlcmd ) {} 140 + 141 + //@{ 142 + // キーワードが変更されたときに発生 143 + //@} 144 + virtual void on_keyword_change() {} 145 + 146 + //@{ 147 + // ダーティフラグが変更されたときに発生 148 + //@} 149 + virtual void on_dirtyflag_change( bool dirty ) {} 150 +}; 151 + 152 + 153 + 154 +//========================================================================= 155 +//@{ 156 +// 操作コマンドインターフェイス 157 +// 158 +// ドキュメントは、Command から派生したクラスのインスタンスの 159 +// operator() を呼び出すことで、色々な操作を実行する。とりあえず 160 +// 具体的には Insert/Delete/Replace の3つだけ。あとでマクロコマンド用 161 +// クラスも作るつもりだけど、とりあえずは保留。 162 +//@} 163 +//========================================================================= 164 + 165 +class Command : public ki::Object 166 +{ 167 +protected: 168 + friend class UnReDoChain; 169 + friend class MacroCommand; 170 + virtual Command* operator()( Document& doc ) const = 0; 171 +}; 172 + 173 + 174 + 175 +//========================================================================= 176 +//@{ 177 +// 挿入コマンド 178 +//@} 179 +//========================================================================= 180 + 181 +class Insert : public Command 182 +{ 183 +public: 184 + 185 + //@{ 186 + // @param s 挿入位置 187 + // @param str 挿入文字列 188 + // @param len 文字列の長さ 189 + // @param del コマンド終了時にdelete [] strしてよいか? 190 + //@} 191 + Insert( const DPos& s, const unicode* str, ulong len, bool del=false ); 192 + ~Insert(); 193 + 194 +private: 195 + 196 + Command* operator()( Document& doc ) const; 197 + DPos stt_; 198 + const unicode* buf_; 199 + ulong len_; 200 + bool del_; 201 +}; 202 + 203 + 204 + 205 +//========================================================================= 206 +//@{ 207 +// 削除コマンド 208 +//@} 209 +//========================================================================= 210 + 211 +class Delete : public Command 212 +{ 213 +public: 214 + 215 + //@{ 216 + // @param s 開始位置 217 + // @param e 終端位置 218 + //@} 219 + Delete( const DPos& s, const DPos& e ); 220 + 221 +private: 222 + 223 + Command* operator()( Document& doc ) const; 224 + DPos stt_; 225 + DPos end_; 226 +}; 227 + 228 + 229 + 230 + 231 +//========================================================================= 232 +//@{ 233 +// 置換コマンド 234 +//@} 235 +//========================================================================= 236 + 237 +class Replace : public Command 238 +{ 239 +public: 240 + 241 + //@{ 242 + // @param s 開始位置 243 + // @param e 終端位置 244 + // @param str 挿入文字列 245 + // @param len 文字列の長さ 246 + // @param del コマンド終了時にdelete [] strしてよいか? 247 + //@} 248 + Replace( const DPos& s, const DPos& e, 249 + const unicode* str, ulong len, bool del=false ); 250 + ~Replace(); 251 + 252 +private: 253 + 254 + Command* operator()( Document& doc ) const; 255 + DPos stt_; 256 + DPos end_; 257 + const unicode* buf_; 258 + ulong len_; 259 + bool del_; 260 +}; 261 + 262 + 263 + 264 +//========================================================================= 265 +//@{ 266 +// マクロコマンド 267 +// 268 +// 複数のコマンドを一つのコマンドとして連続実行する。 269 +// ただし、Insert/Delete/Replaceを一回行うたびに当然 270 +// 文字列の位置は変化するのだが、それに関する変換処理は 271 +// 行わない。すなわち、Insert->Delete->Insert みたいな 272 +// 連続処理を書くときは、行数や文字数の変化を考慮しながら 273 +// 値を定めていくことが必要になる。ので、あんまり使えない(^^; 274 +//@} 275 +//========================================================================= 276 + 277 +class MacroCommand : public Command 278 +{ 279 +public: 280 + //@{ コマンドの追加 //@} 281 + void Add( Command* cmd ) { arr_.Add(cmd); } 282 + 283 + //@{ コマンド数 //@} 284 + ulong size() const { return arr_.size(); } 285 + 286 + //@ デストラクタ //@} 287 + ~MacroCommand() 288 + { 289 + for( ulong i=0,e=arr_.size(); i<e; ++i ) 290 + delete arr_[i]; 291 + } 292 + 293 +private: 294 + Command* operator()( Document& doc ) const; 295 + ki::storage<Command*> arr_; 296 +}; 297 + 298 + 299 + 300 +//========================================================================= 301 + 302 +}} // namespace editwing::document 303 +#endif // _EDITWING_DOC_H_
Added editwing/ewView.h version [bfa35c0d3f9f6f41]
1 +#ifndef _EDITWING_VIEW_H_ 2 +#define _EDITWING_VIEW_H_ 3 +#include "ewCommon.h" 4 +#include "ewDoc.h" 5 +#ifndef __ccdoc__ 6 +namespace editwing { 7 +namespace view { 8 +#endif 9 + 10 + 11 + 12 +class Canvas; 13 +class ViewImpl; 14 +class Cursor; 15 +class Caret; 16 + 17 + 18 + 19 +//========================================================================= 20 +//@{ @pkg editwing.View //@} 21 +//@{ 22 +// 描画処理など 23 +// 24 +// このクラスでは、メッセージの分配を行うだけで、実装は 25 +// Canvas/ViewImpl 等で行う。ので、詳しくはそちらを参照のこと。 26 +//@} 27 +//========================================================================= 28 + 29 +class View : public ki::WndImpl, public doc::DocEvHandler 30 +{ 31 +public: 32 + 33 + //@{ 何もしないコンストラクタ //@} 34 + View( doc::Document& d, HWND wnd ); 35 + ~View(); 36 + 37 + //@{ 折り返し方式切替 //@} 38 + void SetWrapType( int wt ); 39 + 40 + //@{ 行番号表示/非表示切替 //@} 41 + void ShowLineNo( bool show ); 42 + 43 + //@{ 表示色・フォント切替 //@} 44 + void SetFont( const VConfig& vc ); 45 + 46 + //@{ 内部実装 //@} 47 + ViewImpl& impl() { return *impl_; } 48 + 49 + //@{ カーソル //@} 50 + Cursor& cur(); 51 + 52 +private: 53 + 54 + doc::DocImpl& doc_; 55 + ki::dptr<ViewImpl> impl_; 56 + static ClsName className_; 57 + 58 +private: 59 + 60 + void on_create( CREATESTRUCT* cs ); 61 + void on_destroy(); 62 + LRESULT on_message( UINT msg, WPARAM wp, LPARAM lp ); 63 + void on_text_update( const DPos& s, const DPos& e, const DPos& e2, bool bAft, bool mCur ); 64 + void on_keyword_change(); 65 +}; 66 + 67 + 68 + 69 +//========================================================================= 70 +//@{ 71 +// イベントハンドラインターフェイス 72 +// 73 +// カーソルから発生するイベント色々を 74 +//@} 75 +//========================================================================= 76 + 77 +class CurEvHandler 78 +{ 79 + friend class Cursor; 80 + virtual void on_move( const DPos& c, const DPos& s ) {} 81 + virtual void on_char( Cursor& cur, unicode wch ); 82 + virtual void on_key( Cursor& cur, int vk, bool sft, bool ctl ); 83 + virtual void on_ime( Cursor& cur, unicode* str, ulong len ); 84 +}; 85 + 86 + 87 + 88 +//========================================================================= 89 +//@{ 90 +// 表示位置情報まで含めたDPos 91 +//@} 92 +//========================================================================= 93 + 94 +struct VPos : public DPos 95 +{ 96 + ulong vl; // VLine-Index 97 + ulong rl; // RLine-Index 98 + int vx; // スクロールを考慮しない仮想スクリーン上のx座標(pixel) 99 + int rx; // 文字の並びに左右されてないx座標(pixel) 100 + // == 長い行のしっぽから短い行に [↑] で移動して 101 + // == その後 [↓] で戻れるようなアレです。 102 + void operator=( const DPos& dp ) { tl=dp.tl, ad=dp.ad; } 103 + 104 + VPos(bool) : DPos(0,0),vl(0),rl(0),vx(0),rx(0) {} 105 + VPos() {} 106 +}; 107 + 108 + 109 + 110 +//========================================================================= 111 +//@{ 112 +// カーソル 113 +//@} 114 +//========================================================================= 115 + 116 +class Cursor : public ki::Object 117 +{ 118 +public: 119 + 120 + // 初期化とか 121 + Cursor( HWND wnd, ViewImpl& vw, doc::DocImpl& dc ); 122 + ~Cursor(); 123 + void AddHandler( CurEvHandler* ev ); 124 + void DelHandler( CurEvHandler* ev ); 125 + 126 + // カーソル移動 127 + void MoveCur( const DPos& dp, bool select ); 128 + 129 + // キーによるカーソル移動 130 + void Left( bool wide, bool select ); 131 + void Right( bool wide, bool select ); 132 + void Up( bool wide, bool select ); 133 + void Down( bool wide, bool select ); 134 + void Home( bool wide, bool select ); 135 + void End( bool wide, bool select ); 136 + void PageUp( bool select ); 137 + void PageDown( bool select ); 138 + 139 + // テキスト書き換え 140 + void Input( const unicode* str, ulong len ); 141 + void Input( const char* str, ulong len ); 142 + void InputChar( unicode ch ); 143 + void Del(); 144 + void DelBack(); 145 + 146 + // クリップボード 147 + void Cut(); 148 + void Copy(); 149 + void Paste(); 150 + 151 + // 選択テキスト取得 152 + ki::aarr<unicode> getSelectedStr() const; 153 + 154 + // モード切替 155 + void SetInsMode( bool bIns ); 156 + void SetROMode( bool bRO ); 157 + 158 +public: 159 + 160 + bool isInsMode() const; 161 + bool isROMode() const; 162 + bool isSelected() const; 163 + bool getCurPos( const VPos** start, const VPos** end ) const; 164 + void ResetPos(); 165 + void on_scroll_begin(); 166 + void on_scroll_end(); 167 + void on_text_update( const DPos& s, const DPos& e, const DPos& e2, bool mCur ); 168 + void on_setfocus(); 169 + void on_killfocus(); 170 + void on_keydown( int vk, LPARAM flag ); 171 + void on_char( TCHAR ch ); 172 + void on_ime_composition( LPARAM lp ); 173 + void on_lbutton_down( short x, short y, bool shift ); 174 + void on_mouse_move( short x, short y ); 175 + void on_lbutton_up( short x, short y ); 176 + void on_lbutton_dbl( short x, short y ); 177 + bool on_contextmenu( short x, short y ); 178 + void on_timer(); 179 + int on_ime_reconvertstring( RECONVERTSTRING* rs ); 180 + bool on_ime_confirmreconvertstring( RECONVERTSTRING* rs ); 181 + 182 +private: 183 + 184 + doc::DocImpl& doc_; 185 + ViewImpl& view_; 186 + CurEvHandler* pEvHan_; 187 + ki::dptr<Caret> caret_; 188 + 189 + VPos cur_; // カーソル位置 190 + VPos sel_; // 選択時の軸足位置 191 + bool bIns_; // 挿入モード? 192 + bool bRO_; // 読取専用? 193 + 194 + UINT_PTR timerID_;// マウスドラッグ制御用の 195 + int keyRepTime_; // タイマー関係 196 + int dragX_; // 位置 197 + int dragY_; // 位置 198 + bool lineSelectMode_; // 行選択モード? 199 + 200 + CurEvHandler defaultHandler_; 201 + 202 +private: 203 + 204 + void MoveByMouse( int x, int y ); 205 + void MoveTo( const VPos& vp, bool sel ); 206 + void Ud( int dy, bool select ); 207 + void UpdateCaretPos(); 208 + void Redraw( const VPos& s, const VPos& e ); 209 +}; 210 + 211 + 212 + 213 +//------------------------------------------------------------------------- 214 + 215 +inline bool Cursor::isSelected() const 216 + { return cur_!=sel_; } 217 + 218 +inline bool Cursor::isInsMode() const 219 + { return bIns_; } 220 + 221 +inline bool Cursor::isROMode() const 222 + { return bRO_; } 223 + 224 + 225 + 226 +//========================================================================= 227 + 228 +}} // namespace editwing::view 229 +#endif // _EDITWING_VIEW_H_
Added editwing/ip_ctrl1.cpp version [3bc18713fe7f8f93]
1 +#include "stdafx.h" 2 +#include "ewCtrl1.h" 3 +using namespace ki; 4 +using namespace editwing; 5 + 6 + 7 + 8 +//------------------------------------------------------------------------- 9 +// EwEditコントロール作成/破棄 10 +//------------------------------------------------------------------------- 11 + 12 +EwEdit::ClsName EwEdit::className_ = TEXT("EditWing Control-01"); 13 + 14 +EwEdit::EwEdit() 15 + : WndImpl( className_, WS_CHILD|WS_VISIBLE, WS_EX_CLIENTEDGE ) 16 +{ 17 + static bool ClassRegistered = false; 18 + if( !ClassRegistered ) 19 + { 20 + ClassRegistered = true; 21 + 22 + // 初回構築時のみ、クラス登録を行う 23 + WNDCLASSEX wc = {0}; 24 + wc.lpszClassName = className_; 25 + WndImpl::Register( &wc ); 26 + } 27 +} 28 + 29 +EwEdit::~EwEdit() 30 +{ 31 + Destroy(); 32 +} 33 + 34 +void EwEdit::on_create( CREATESTRUCT* cs ) 35 +{ 36 + doc_ = new doc::Document; 37 + view_ = new view::View( *doc_, hwnd() ); 38 +} 39 + 40 +void EwEdit::on_destroy() 41 +{ 42 + view_ = NULL; 43 + doc_ = NULL; 44 +} 45 + 46 + 47 + 48 +//------------------------------------------------------------------------- 49 +// 簡単なメッセージ制御 50 +//------------------------------------------------------------------------- 51 + 52 +LRESULT EwEdit::on_message( UINT msg, WPARAM wp, LPARAM lp ) 53 +{ 54 + switch( msg ) 55 + { 56 + case WM_SETFOCUS: 57 + { 58 + view_->SetFocus(); 59 + break; 60 + } 61 + case WM_SIZE: 62 + { 63 + RECT rc; 64 + getClientRect( &rc ); 65 + view_->MoveTo( 0, 0, rc.right, rc.bottom ); 66 + break; 67 + } 68 + case EM_CANUNDO: return getDoc().isUndoAble(); 69 + case EM_SETREADONLY: getCursor().SetROMode(wp!=FALSE); return TRUE; 70 + case WM_COPY: getCursor().Copy(); return 0; 71 + case WM_CUT: getCursor().Cut(); return 0; 72 + case WM_PASTE: getCursor().Paste(); return 0; 73 + case EM_UNDO: 74 + case WM_UNDO: getDoc().Undo(); return TRUE; 75 + default: 76 + return WndImpl::on_message( msg, wp, lp ); 77 + } 78 + return 0; 79 +/* 80 +EM_CHARFROMPOS 81 +EM_EMPTYUNDOBUFFER: 82 +EM_FMTLINES 83 +EM_GETCUEBANNER 84 +EM_GETFIRSTVISIBLELINE 85 +EM_GETHANDLE 86 +EM_GETIMESTATUS 87 +EM_GETLIMITTEXT 88 +EM_GETLINE 89 +EM_GETLINECOUNT 90 +EM_GETMARGINS 91 +EM_GETMODIFY 92 +EM_GETPASSWORDCHAR 93 +EM_GETRECT 94 +EM_GETSEL 95 +EM_GETTHUMB 96 +EM_GETWORDBREAKPROC 97 +EM_HIDEBALLOONTIP 98 +EM_LIMITTEXT 99 +EM_LINEFROMCHAR 100 +EM_LINEINDEX 101 +EM_LINELENGTH 102 +EM_LINESCROLL 103 +EM_POSFROMCHAR 104 +EM_REPLACESEL 105 +EM_SCROLL 106 +EM_SCROLLCARET 107 +EM_SETCUEBANNER 108 +EM_SETHANDLE 109 +EM_SETIMESTATUS 110 +EM_SETLIMITTEXT 111 +EM_SETMARGINS 112 +EM_SETMODIFY 113 +EM_SETPASSWORDCHAR 114 +EM_SETRECT 115 +EM_SETRECTNP 116 +EM_SETSEL 117 +EM_SETTABSTOPS 118 +EM_SETWORDBREAKPROC 119 +EM_SHOWBALLOONTIP 120 +WM_COMMAND 121 +WM_CTLCOLOREDIT 122 +WM_CTLCOLORSTATIC 123 +*/ 124 +}
Added editwing/ip_cursor.cpp version [4947f4ab7f00d23b]
1 +#include "stdafx.h" 2 +#include "ip_view.h" 3 +using namespace editwing; 4 +using namespace editwing::view; 5 +using doc::Insert; 6 +using doc::Delete; 7 +using doc::Replace; 8 + 9 + 10 + 11 +//========================================================================= 12 +//---- ip_cursor.cpp カーソルコントロール 13 +// 14 +// カレットを表示したりIMEに適当に対応したり色々。 15 +// ところで疑問なのだが Caret って「カレット」と 16 +// 読むのか「キャレット」と読むのか? 17 +// 18 +//---- ip_text.cpp 文字列操作・他 19 +//---- ip_parse.cpp キーワード解析 20 +//---- ip_wrap.cpp 折り返し 21 +//---- ip_scroll.cpp スクロール 22 +//---- ip_draw.cpp 描画・他 23 +//========================================================================= 24 + 25 + 26 + 27 +//------------------------------------------------------------------------- 28 +// Caret制御用ラッパー 29 +//------------------------------------------------------------------------- 30 + 31 +class editwing::view::Caret : public Object 32 +{ 33 +public: 34 + 35 + Caret( HWND wnd ) 36 + : hwnd_( wnd ), created_( false ) {} 37 + 38 + ~Caret() 39 + { Destroy(); } 40 + 41 + void Show() 42 + { if( created_ ) ::ShowCaret( hwnd_ ); } 43 + 44 + void Hide() 45 + { if( created_ ) ::HideCaret( hwnd_ ); } 46 + 47 + void Destroy() 48 + { if( created_ ) ::DestroyCaret(), created_=false; } 49 + 50 + void SetPos( int x, int y ) 51 + { if( created_ ) ::SetCaretPos(x,y), ime().SetPos(hwnd_,x,y); } 52 + 53 + void Create( int H, int W, const LOGFONT& lf ) 54 + { 55 + if( created_ ) 56 + ::DestroyCaret(); 57 + created_ = true; 58 + ::CreateCaret( hwnd_, NULL, W, H ); 59 + ime().SetFont( hwnd_, lf ); 60 + Show(); 61 + } 62 + 63 + bool isAlive() 64 + { return created_; } 65 + 66 + HWND hwnd() 67 + { return hwnd_; } 68 + 69 +private: 70 + 71 + const HWND hwnd_; 72 + bool created_; 73 +}; 74 + 75 + 76 + 77 +//------------------------------------------------------------------------- 78 +// カーソル初期化 79 +//------------------------------------------------------------------------- 80 + 81 +Cursor::Cursor( HWND wnd, ViewImpl& vw, doc::DocImpl& dc ) 82 + : view_ ( vw ) 83 + , doc_ ( dc ) 84 + , pEvHan_ ( &defaultHandler_ ) 85 + , caret_ ( new Caret(wnd) ) 86 + , bIns_ ( true ) 87 + , bRO_ ( false ) 88 + , timerID_( 0 ) 89 + , lineSelectMode_( false ) 90 +{ 91 + // てきとーに情報初期化 92 + ::SystemParametersInfo( SPI_GETKEYBOARDSPEED, 0, &keyRepTime_, 0 ); 93 + cur_.tl = cur_.ad = cur_.vl = cur_.rl = 0; 94 + cur_.vx = cur_.rx = 0; sel_ = cur_; 95 +} 96 + 97 +Cursor::~Cursor() 98 +{ 99 +} 100 + 101 +void Cursor::AddHandler( CurEvHandler* ev ) 102 +{ 103 + pEvHan_ = ev; 104 +} 105 + 106 +void Cursor::DelHandler( CurEvHandler* ev ) 107 +{ 108 + if( ev == pEvHan_ ) 109 + pEvHan_ = &defaultHandler_; 110 +} 111 + 112 + 113 + 114 +//------------------------------------------------------------------------- 115 +// ヘルパー関数群 116 +//------------------------------------------------------------------------- 117 + 118 +void Cursor::UpdateCaretPos() 119 +{ 120 + // メンバ変数の値を元に、実際にCaretを動かす処理 121 + int x, y; 122 + view_.GetOrigin( &x, &y ); 123 + x += cur_.vx; 124 + y += cur_.vl * view_.fnt().H(); 125 + 126 + // 行番号ゾーンにCaretがあっても困るので左に追いやる 127 + if( 0<x && x<view_.left() ) 128 + x = -view_.left(); 129 + 130 + // セット 131 + caret_->SetPos( x, y ); 132 + pEvHan_->on_move( cur_, sel_ ); 133 +} 134 + 135 +void Cursor::Redraw( const VPos& s, const VPos& e ) 136 +{ 137 + int x, y; // 原点 138 + view_.GetOrigin( &x, &y ); 139 + 140 + POINT sp = {x+s.vx, y+s.vl*view_.fnt().H()}; 141 + POINT ep = {x+e.vx, y+e.vl*view_.fnt().H()}; 142 + if( s > e ) // Swap 143 + sp.x^=ep.x, ep.x^=sp.x, sp.x^=ep.x, 144 + sp.y^=ep.y, ep.y^=sp.y, sp.y^=ep.y; 145 + ep.x+=2; 146 + 147 + // 手抜き16bitチェック入り… 148 + const long LFT = view_.left(); 149 + const long RHT = view_.right(); 150 + const long TOP = 0; 151 + const int BTM = view_.bottom(); 152 + 153 + if( sp.y == ep.y ) 154 + { 155 + RECT rc = { Max(LFT,sp.x), sp.y, Min(RHT,ep.x), sp.y+view_.fnt().H() }; 156 + ::InvalidateRect( caret_->hwnd(), &rc, FALSE ); 157 + } 158 + else 159 + { 160 + RECT rc = { Max(LFT,sp.x), Max(TOP,sp.y), RHT, Min<int>(BTM,sp.y+view_.fnt().H()) }; 161 + ::InvalidateRect( caret_->hwnd(), &rc, FALSE ); 162 + RECT re = { LFT, Max(TOP,ep.y), Min(RHT,ep.x), Min<int>(BTM,ep.y+view_.fnt().H()) }; 163 + ::InvalidateRect( caret_->hwnd(), &re, FALSE ); 164 + RECT rd = { LFT, Max(TOP,rc.bottom), RHT, Min<int>((long)BTM,re.top) }; 165 + ::InvalidateRect( caret_->hwnd(), &rd, FALSE ); 166 + } 167 +} 168 + 169 +bool Cursor::getCurPos( const VPos** start, const VPos** end ) const 170 +{ 171 + *start = *end = &cur_; 172 + if( cur_==sel_ )//|| !caret_->isAlive() ) 173 + return false; 174 + if( cur_ < sel_ ) 175 + *end = &sel_; 176 + else 177 + *start = &sel_; 178 + return true; 179 +} 180 + 181 + 182 + 183 + 184 +//------------------------------------------------------------------------- 185 +// Viewからの指令を処理 186 +//------------------------------------------------------------------------- 187 + 188 +void Cursor::on_setfocus() 189 +{ 190 + caret_->Create( view_.fnt().H(), 191 + (bIns_ ? 2 : view_.fnt().W()), view_.fnt().LogFont() ); 192 + UpdateCaretPos(); 193 +} 194 + 195 +void Cursor::on_killfocus() 196 +{ 197 + caret_->Destroy(); 198 + Redraw( cur_, sel_ ); 199 +} 200 + 201 +void Cursor::on_scroll_begin() 202 +{ 203 + caret_->Hide(); 204 +} 205 + 206 +void Cursor::on_scroll_end() 207 +{ 208 + UpdateCaretPos(); 209 + caret_->Show(); 210 +} 211 + 212 +void Cursor::ResetPos() 213 +{ 214 + // 設定変更などに対応 215 + view_.ConvDPosToVPos( cur_, &cur_ ); 216 + view_.ConvDPosToVPos( sel_, &sel_ ); 217 + UpdateCaretPos(); 218 + if( caret_->isAlive() ) 219 + view_.ScrollTo( cur_ ); 220 +} 221 + 222 +void Cursor::on_text_update 223 + ( const DPos& s, const DPos& e, const DPos& e2, bool mCur ) 224 +{ 225 + VPos* search_base = NULL; 226 + 227 + if( mCur && s==cur_ && e==sel_ ) 228 + { 229 + search_base = &cur_; 230 + } 231 + else if( mCur && s==sel_ && e==cur_ ) 232 + { 233 + search_base = &sel_; 234 + } 235 + else 236 + { 237 + Redraw( cur_, sel_ ); 238 + if( mCur && caret_->isAlive() ) 239 + { 240 + if( cur_ <= s ) 241 + search_base = &cur_; 242 + } 243 + else 244 + { 245 + if( s < cur_ ) 246 + { 247 + if( cur_ <= e ) 248 + cur_ = e2; 249 + else if( cur_.tl == e.tl ) 250 + cur_.tl=e2.tl, cur_.ad=e2.ad+cur_.ad-e.ad; 251 + else 252 + cur_.tl=e2.tl-e.tl; 253 + view_.ConvDPosToVPos( cur_, &cur_ ); 254 + } 255 + if( s < sel_ ) 256 + sel_ = cur_; 257 + } 258 + } 259 + 260 + if( mCur ) 261 + { 262 + view_.ConvDPosToVPos( e2, &cur_, search_base ); 263 + sel_ = cur_; 264 + if( caret_->isAlive() ) 265 + view_.ScrollTo( cur_ ); 266 + } 267 + UpdateCaretPos(); 268 +} 269 + 270 + 271 + 272 +//------------------------------------------------------------------------- 273 +// キー入力への対応 274 +//------------------------------------------------------------------------- 275 + 276 +void CurEvHandler::on_char( Cursor& cur, unicode wch ) 277 +{ 278 + cur.InputChar( wch ); 279 +} 280 + 281 +void CurEvHandler::on_ime( Cursor& cur, unicode* str, ulong len ) 282 +{ 283 + cur.Input( str, len ); 284 +} 285 + 286 +void CurEvHandler::on_key( Cursor& cur, int vk, bool sft, bool ctl ) 287 +{ 288 + switch( vk ) 289 + { 290 + case VK_HOME: cur.Home( ctl, sft ); break; 291 + case VK_END: cur.End( ctl, sft ); break; 292 + case VK_RIGHT: cur.Right( ctl, sft ); break; 293 + case VK_LEFT: cur.Left( ctl, sft ); break; 294 + case VK_UP: cur.Up( ctl, sft ); break; 295 + case VK_DOWN: cur.Down( ctl, sft ); break; 296 + case VK_PRIOR: cur.PageUp( sft ); break; 297 + case VK_NEXT: cur.PageDown( sft ); break; 298 + case VK_DELETE: cur.Del(); break; 299 + case VK_BACK: cur.DelBack(); break; 300 + case VK_INSERT: cur.SetInsMode(!cur.isInsMode()); break; 301 + } 302 +} 303 + 304 +void Cursor::on_char( TCHAR ch ) 305 +{ 306 + if( !bRO_ && ch!=0x7f 307 + && ((unsigned)ch>=0x20 || ch==TEXT('\r') || ch==TEXT('\t')) ) 308 + { 309 + #ifdef _UNICODE 310 + pEvHan_->on_char( *this, ch ); 311 + #else 312 + unicode wc = ch; 313 + if( ch & 0x80 ) // 非ASCII文字にはトリビアルでない変換が必要 314 + ::MultiByteToWideChar( CP_ACP, MB_COMPOSITE, &ch, 1, &wc, 1 ); 315 + pEvHan_->on_char( *this, wc ); 316 + #endif 317 + } 318 +} 319 + 320 +void Cursor::on_ime_composition( LPARAM lp ) 321 +{ 322 + view_.ScrollTo( cur_ ); 323 + if( !bRO_ && (lp&GCS_RESULTSTR) ) 324 + { 325 + unicode* str; 326 + ulong len; 327 + ime().GetString( caret_->hwnd(), &str, &len ); 328 + if( str ) 329 + { 330 + pEvHan_->on_ime( *this, str, len ); 331 + delete [] str; 332 + } 333 + } 334 +} 335 + 336 +void Cursor::on_keydown( int vk, LPARAM flag ) 337 +{ 338 + bool sft = (::GetKeyState(VK_SHIFT)>>15)!=0; 339 + bool ctl = (::GetKeyState(VK_CONTROL)>>15)!=0; 340 + pEvHan_->on_key( *this, vk, sft, ctl ); 341 +} 342 + 343 + 344 + 345 +//------------------------------------------------------------------------- 346 +// モード切替 347 +//------------------------------------------------------------------------- 348 + 349 +void Cursor::SetInsMode( bool bIns ) 350 +{ 351 + bIns_ = bIns; 352 + on_setfocus(); 353 +} 354 + 355 +void Cursor::SetROMode( bool bRO ) 356 +{ 357 + bRO_ = bRO; 358 +} 359 + 360 + 361 + 362 +//------------------------------------------------------------------------- 363 +// 文字入力・削除 364 +//------------------------------------------------------------------------- 365 + 366 +void Cursor::InputChar( unicode ch ) 367 +{ 368 + // 「上書モード & 選択状態でない & 行末でない」なら右一文字選択 369 + if( !bIns_ && cur_==sel_ && doc_.len(cur_.tl)!=cur_.ad ) 370 + Right( false, true ); 371 + 372 + // 入力 373 + Input( &ch, 1 ); 374 +} 375 + 376 +void Cursor::Input( const unicode* str, ulong len ) 377 +{ 378 + if( cur_==sel_ ) 379 + doc_.Execute( Insert( cur_, str, len ) ); 380 + else 381 + doc_.Execute( Replace( cur_, sel_, str, len ) ); 382 +} 383 + 384 +void Cursor::Input( const char* str, ulong len ) 385 +{ 386 + unicode* ustr = new unicode[ len*4 ]; 387 + len = ::MultiByteToWideChar( CP_ACP, 0, str, len, ustr, len*4 ); 388 + Input( ustr, len ); 389 + delete [] ustr; 390 +} 391 + 392 +void Cursor::DelBack() 393 +{ 394 + // 選択状態なら BackSpace == Delete 395 + // でなければ、 BackSpace == Left + Delete (手抜き 396 + if( cur_ == sel_ ) 397 + { 398 + if( cur_.tl==0 && cur_.ad==0 ) 399 + return; 400 + Left( false, false ); 401 + } 402 + Del(); 403 +} 404 + 405 +void Cursor::Del() 406 +{ 407 + // 選択状態なら cur_ 〜 sel_ を削除 408 + // でなければ、 cur_ 〜 rightOf(cur_) を削除 409 + DPos dp = (cur_==sel_ ? doc_.rightOf(cur_) : (DPos)sel_ ); 410 + if( cur_ != dp ) 411 + doc_.Execute( Delete( cur_, dp ) ); 412 +} 413 + 414 + 415 + 416 +//------------------------------------------------------------------------- 417 +// テキスト取得 418 +//------------------------------------------------------------------------- 419 + 420 +ki::aarr<unicode> Cursor::getSelectedStr() const 421 +{ 422 + DPos dm=cur_, dM=sel_; 423 + if( cur_ > sel_ ) 424 + dm=sel_, dM=cur_; 425 + 426 + // テキスト取得 427 + int len = doc_.getRangeLength( dm, dM ); 428 + ki::aarr<unicode> ub( new unicode[len+1] ); 429 + doc_.getText( ub.get(), dm, dM ); 430 + return ub; 431 +} 432 + 433 +//------------------------------------------------------------------------- 434 +// クリップボード処理 435 +//------------------------------------------------------------------------- 436 + 437 +void Cursor::Cut() 438 +{ 439 + if( cur_ != sel_ ) 440 + { 441 + // コピーして削除 442 + Copy(); 443 + Del(); 444 + } 445 +} 446 + 447 +void Cursor::Copy() 448 +{ 449 + Clipboard clp( caret_->hwnd(), false ); 450 + if( cur_==sel_ || !clp.isOpened() ) 451 + return; 452 + 453 + DPos dm=cur_, dM=sel_; 454 + if( cur_ > sel_ ) 455 + dm=sel_, dM=cur_; 456 + 457 + HGLOBAL h; 458 + unicode* p; 459 + int len = doc_.getRangeLength( dm, dM ); 460 + 461 + if( app().isNT() ) 462 + { 463 + // NT系ならそのままダイレクトに 464 + h = ::GlobalAlloc( GMEM_MOVEABLE, (len+1)*2 ); 465 + doc_.getText( static_cast<unicode*>(::GlobalLock(h)), dm, dM ); 466 + ::GlobalUnlock( h ); 467 + clp.SetData( CF_UNICODETEXT, h ); 468 + } 469 + else 470 + { 471 + // 9x系なら変換が必要 472 + h = ::GlobalAlloc( GMEM_MOVEABLE, (len+1)*3 ); 473 + p = new unicode[len+1]; 474 + doc_.getText( p, dm, dM ); 475 + ::WideCharToMultiByte( CP_ACP, 0, p, -1, 476 + static_cast<char*>(::GlobalLock(h)), (len+1)*3, NULL, NULL ); 477 + ::GlobalUnlock( h ); 478 + clp.SetData( CF_TEXT, h ); 479 + delete [] p; 480 + } 481 +} 482 + 483 +void Cursor::Paste() 484 +{ 485 + Clipboard clp( caret_->hwnd(), true ); 486 + if( clp.isOpened() ) 487 + { 488 + Clipboard::Text txt = clp.GetUnicodeText(); 489 + if( txt.data() != NULL ) 490 + doc_.Execute( 491 + Replace( cur_, sel_, txt.data(), my_lstrlenW(txt.data()) ) 492 + ); 493 + } 494 +} 495 + 496 + 497 + 498 +//------------------------------------------------------------------------- 499 +// カーソル移動 500 +//------------------------------------------------------------------------- 501 + 502 +void Cursor::MoveCur( const DPos& dp, bool select ) 503 +{ 504 + VPos vp; 505 + view_.ConvDPosToVPos( dp, &vp ); 506 + MoveTo( vp, select ); 507 +} 508 + 509 +void Cursor::MoveTo( const VPos& vp, bool sel ) 510 +{ 511 + if( sel ) 512 + { 513 + // 選択状態が変わる範囲を再描画 514 + Redraw( vp, cur_ ); 515 + } 516 + else 517 + { 518 + // 選択解除される範囲を再描画 519 + if( cur_ != sel_ ) 520 + Redraw( cur_, sel_ ); 521 + sel_ = vp; 522 + } 523 + cur_ = vp; 524 + UpdateCaretPos(); 525 + view_.ScrollTo( cur_ ); 526 +} 527 + 528 +void Cursor::Home( bool wide, bool select ) 529 +{ 530 + VPos np; 531 + np.ad = np.vx = np.rx = np.rl = 0; 532 + if( wide ) // 文書の頭へ 533 + np.tl = np.vl = 0; 534 + else // 行の頭へ 535 + { 536 + // 1.07.4 --> 1.08 :: Virtual Home 537 + // np.tl = cur_.tl, np.vl = cur_.vl-cur_.rl; 538 + 539 + if( cur_.rl == 0 ) 540 + np.tl = cur_.tl, np.vl = cur_.vl-cur_.rl; 541 + else 542 + view_.ConvDPosToVPos( doc_.rightOf(DPos(cur_.tl, view_.rlend(cur_.tl,cur_.rl-1))), &np, &cur_ ); 543 + } 544 + MoveTo( np, select ); 545 +} 546 + 547 +void Cursor::End( bool wide, bool select ) 548 +{ 549 + VPos np; 550 + if( wide ) // 文書の末尾へ 551 + { 552 + np.tl = doc_.tln()-1; 553 + np.vl = view_.vln()-1; 554 + } 555 + else // 行の末尾へ 556 + { 557 + // 1.07.4 --> 1.08 :: Virtual End 558 + // np.tl = cur_.tl; 559 + // np.vl = cur_.vl + view_.rln(np.tl) - 1 - cur_.rl; 560 + 561 + view_.ConvDPosToVPos( DPos(cur_.tl, view_.rlend(cur_.tl,cur_.rl)), &np, &cur_ ); 562 + MoveTo( np, select ); 563 + return; 564 + } 565 + np.ad = doc_.len(np.tl); 566 + np.rl = view_.rln(np.tl)-1; 567 + np.rx = np.vx = view_.GetLastWidth( np.tl ); 568 + 569 + MoveTo( np, select ); 570 +} 571 + 572 +void Cursor::Ud( int dy, bool select ) 573 +{ 574 + // はみ出す場合は、先頭行/終端行で止まるように制限 575 + VPos np = cur_; 576 + if( (signed)np.vl + dy < 0 ) 577 + dy = -(signed)np.vl; 578 + else if( np.vl + dy >= view_.vln() ) 579 + dy = view_.vln()-np.vl-1; 580 + 581 + np.vl += dy; 582 + np.rl += dy; 583 + if( dy<0 ) // 上へ戻る場合 584 + { 585 + // ジャンプ先論理行の行頭へDash! 586 + while( (signed)np.rl < 0 ) 587 + np.rl += view_.rln(--np.tl); 588 + } 589 + else if( dy>0 ) // 下へ進む場合 590 + { 591 + // ジャンプ先論理行の行頭へDash! 592 + while( (signed)np.rl > 0 ) 593 + np.rl -= view_.rln(np.tl++); 594 + if( (signed)np.rl < 0 ) 595 + np.rl += view_.rln(--np.tl); //行き過ぎ修正〜 596 + } 597 + 598 + // x座標決定にかかる 599 + const unicode* str = doc_.tl(np.tl); 600 + 601 + // 右寄せになってる。不自然? 602 + np.ad = (np.rl==0 ? 0 : view_.rlend(np.tl,np.rl-1)+1); 603 + np.vx = (np.rl==0 ? 0 : view_.fnt().W(&str[np.ad-1])); 604 + while( np.vx < np.rx && np.ad < view_.rlend(np.tl,np.rl) ) 605 + { 606 + // 左寄せにしてみた。 607 + ulong newvx; 608 + if( str[np.ad] == L'\t' ) 609 + newvx = view_.fnt().nextTab(np.vx); 610 + else 611 + newvx = np.vx + view_.fnt().W(&str[np.ad]); 612 + if( newvx > ulong(np.rx) ) 613 + break; 614 + np.vx = newvx; 615 + ++np.ad; 616 + } 617 + 618 + MoveTo( np, select ); 619 +} 620 + 621 +void Cursor::Up( bool wide, bool select ) 622 +{ 623 + Ud( wide?-3:-1, select ); 624 +} 625 + 626 +void Cursor::Down( bool wide, bool select ) 627 +{ 628 + Ud( wide?3:1, select ); 629 +} 630 + 631 +void Cursor::PageUp( bool select ) 632 +{ 633 + Ud( -view_.cy()/view_.fnt().H(), select ); 634 +} 635 + 636 +void Cursor::PageDown( bool select ) 637 +{ 638 + Ud( view_.cy()/view_.fnt().H(), select ); 639 +} 640 + 641 +void Cursor::Left( bool wide, bool select ) 642 +{ 643 + VPos np; 644 + if( cur_!=sel_ && !select ) 645 + np = Min( cur_, sel_ ), np.rx = np.vx; 646 + else 647 + view_.ConvDPosToVPos( doc_.leftOf(cur_,wide), &np, &cur_ ); 648 + MoveTo( np, select ); 649 +} 650 + 651 +void Cursor::Right( bool wide, bool select ) 652 +{ 653 + VPos np; 654 + if( cur_!=sel_ && !select ) 655 + np = Max( cur_, sel_ ), np.rx = np.vx; 656 + else 657 + view_.ConvDPosToVPos( doc_.rightOf(cur_,wide), &np, &cur_ ); 658 + MoveTo( np, select ); 659 +} 660 + 661 + 662 + 663 +//------------------------------------------------------------------------- 664 +// マウス入力への対応 665 +//------------------------------------------------------------------------- 666 + 667 +void Cursor::on_lbutton_dbl( short x, short y ) 668 +{ 669 + // 行番号ゾーンの場合は特に何もしない 670 + if( view_.lna()-view_.fnt().F() < x ) 671 + // 行末の場合も特に何もしない 672 + if( cur_.ad != doc_.len(cur_.tl) ) 673 + { 674 + VPos np; 675 + view_.ConvDPosToVPos( doc_.wordStartOf(cur_), &np, &cur_ ); 676 + MoveTo( np, false ); 677 + Right( true, true ); 678 + } 679 +} 680 + 681 +bool Cursor::on_contextmenu( short x, short y ) 682 +{ 683 + // Not Tracked 684 + return false; 685 +} 686 + 687 +void Cursor::on_lbutton_down( short x, short y, bool shift ) 688 +{ 689 + if( !shift ) 690 + { 691 + // これまでの選択範囲をクリア 692 + Redraw( cur_, sel_ ); 693 + 694 + // 行番号ゾーンのクリックだったら、行選択モードに 695 + lineSelectMode_ = ( x < view_.lna()-view_.fnt().F() ); 696 + 697 + // 選択開始位置を調整 698 + view_.GetVPos( x, y, &sel_ ); 699 + if( lineSelectMode_ ) 700 + view_.ConvDPosToVPos( DPos(sel_.tl,0), &sel_, &sel_ ); 701 + cur_ = sel_; 702 + } 703 + 704 + // 移動! 705 + MoveByMouse( dragX_=x, dragY_=y ); 706 + 707 + // マウス位置の追跡開始 708 + timerID_ = ::SetTimer( caret_->hwnd(), 178116, keyRepTime_, NULL ); 709 + ::SetCapture( caret_->hwnd() ); 710 +} 711 + 712 +void Cursor::on_lbutton_up( short x, short y ) 713 +{ 714 + // 追跡解除 715 + if( timerID_ != 0 ) 716 + { 717 + ::ReleaseCapture(); 718 + ::KillTimer( caret_->hwnd(), timerID_ ); 719 + timerID_ = 0; 720 + } 721 +} 722 + 723 +void Cursor::on_mouse_move( short x, short y ) 724 +{ 725 + if( timerID_ != 0 ) 726 + { 727 + // View内部ならMouseMoveに反応 728 + POINT pt = { dragX_=x, dragY_=y }; 729 + if( PtInRect( &view_.zone(), pt ) ) 730 + MoveByMouse( dragX_, dragY_ ); 731 + } 732 +} 733 + 734 +void Cursor::on_timer() 735 +{ 736 + // View外部ならTimerに反応 737 + POINT pt = { dragX_, dragY_ }; 738 + if( !PtInRect( &view_.zone(), pt ) ) 739 + MoveByMouse( dragX_, dragY_ ); 740 +} 741 + 742 +void Cursor::MoveByMouse( int x, int y ) 743 +{ 744 + VPos vp; 745 + view_.GetVPos( x, y, &vp, lineSelectMode_ ); 746 + MoveTo( vp, true ); 747 +} 748 + 749 +//------------------------------------------------------------------------- 750 +// 再変換 751 +//------------------------------------------------------------------------- 752 + 753 +int Cursor::on_ime_reconvertstring( RECONVERTSTRING* rs ) 754 +{ 755 + if( ! isSelected() || cur_.tl != sel_.tl ) 756 + return 0; 757 + 758 +#ifdef _UNICODE 759 + aarr<unicode> str = getSelectedStr(); 760 +#else 761 + aarr<char> str; 762 + { 763 + aarr<unicode> ub = getSelectedStr(); 764 + ulong len; 765 + for(len=0; ub[len]; ++len); 766 + ki::aarr<char> nw( new TCHAR[(len+1)*3] ); 767 + str = nw; 768 + ::WideCharToMultiByte( CP_ACP, 0, ub.get(), -1, 769 + str.get(), (len+1)*3, NULL, NULL ); 770 + } 771 +#endif 772 + const ulong len = ::lstrlen(str.get()); 773 + if( rs != NULL ) 774 + { 775 + rs->dwSize = sizeof(RECONVERTSTRING) + (len+1)*sizeof(TCHAR); 776 + rs->dwVersion = 0; 777 + rs->dwStrOffset = sizeof(RECONVERTSTRING); 778 + rs->dwStrLen = len; 779 + rs->dwCompStrOffset = 0; 780 + rs->dwCompStrLen = len; 781 + rs->dwTargetStrOffset = 0; 782 + rs->dwTargetStrLen = len; 783 + memmove( ((char*)rs)+rs->dwStrOffset, str.get(), (len+1)*sizeof(TCHAR) ); 784 + 785 + if( sel_ < cur_ ) 786 + { 787 + DPos psel_ = sel_; 788 + MoveCur( cur_, false ); 789 + MoveCur( psel_, true ); 790 + } 791 + } 792 + return sizeof(RECONVERTSTRING) + (len+1)*sizeof(TCHAR); 793 +} 794 + 795 +bool Cursor::on_ime_confirmreconvertstring( RECONVERTSTRING* rs ) 796 +{ 797 + return false; 798 +} 799 +
Added editwing/ip_doc.h version [8369bb0837c81915]
1 +#ifndef _EDITWING_IP_DOC_H_ 2 +#define _EDITWING_IP_DOC_H_ 3 +#include "ewDoc.h" 4 +using namespace ki; 5 +#ifndef __ccdoc__ 6 +namespace editwing { 7 +namespace doc { 8 +#endif 9 + 10 + 11 + 12 +//@{ @pkg editwing.Doc.Impl //@} 13 +class Parser; 14 + 15 + 16 + 17 +//========================================================================= 18 +//@{ 19 +// 行バッファ構造体 20 +// 21 +// UCS-2ベタの形式でテキストデータを保持する。またそれと同時に、 22 +// キーワードファイルによって指定された強調語を区別するための 23 +// 解析処理結果用バッファも管理する。文字データに終端NULは 24 +// 付けないが、解析作業の高速化のため、終端 U+007f が入る。 25 +//@} 26 +//========================================================================= 27 + 28 +class Line : public Object 29 +{ 30 +public: 31 + 32 + //@{ 指定テキストで初期化 //@} 33 + Line( const unicode* str, ulong len ) 34 + : alen_( 10>len ? 10 : len ) 35 + , len_ ( len ) 36 + , str_ ( static_cast<unicode*>( mem().Alloc((alen_+1)*2+alen_) ) ) 37 + , flg_ ( reinterpret_cast<uchar*>(str_+alen_+1) ) 38 + , commentBitReady_( false ) 39 + , isLineHeadCommented_( 0 ) 40 + { 41 + memmove( str_, str, len*2 ); 42 + str_[ len ] = 0x007f; 43 + } 44 + 45 + ~Line() 46 + { 47 + mem().DeAlloc( str_, (alen_+1)*2+alen_ ); 48 + } 49 + 50 + //@{ テキスト挿入(指定位置に指定サイズ) //@} 51 + void InsertAt( ulong at, const unicode* buf, ulong siz ) 52 + { 53 + if( len_+siz > alen_ ) 54 + { 55 + // バッファ拡張 56 + ulong psiz = (alen_+1)*2+alen_; 57 + alen_ = Max( alen_<<1, len_+siz ); 58 + unicode* tmpS = 59 + static_cast<unicode*>( mem().Alloc((alen_+1)*2+alen_) ); 60 + uchar* tmpF = 61 + reinterpret_cast<uchar*>(tmpS+alen_+1); 62 + // コピー 63 + memmove( tmpS, str_, at*2 ); 64 + memmove( tmpS+at+siz, str_+at, (len_-at+1)*2 ); 65 + memmove( tmpF, flg_, at ); 66 + // 古いのを削除 67 + mem().DeAlloc( str_, psiz ); 68 + str_ = tmpS; 69 + flg_ = tmpF; 70 + } 71 + else 72 + { 73 + memmove( str_+at+siz, str_+at, (len_-at+1)*2 ); 74 + memmove( flg_+at+siz, flg_+at, (len_-at) ); 75 + } 76 + memmove( str_+at, buf, siz*sizeof(unicode) ); 77 + len_ += siz; 78 + } 79 + 80 + //@{ テキスト挿入(末尾に) //@} 81 + void InsertToTail( const unicode* buf, ulong siz ) 82 + { 83 + InsertAt( len_, buf, siz ); 84 + } 85 + 86 + //@{ テキスト削除(指定位置から指定サイズ) //@} 87 + void RemoveAt( ulong at, ulong siz ) 88 + { 89 + memmove( str_+at, str_+at+siz, (len_-siz-at+1)*2 ); 90 + memmove( flg_+at, flg_+at+siz, (len_-siz-at) ); 91 + len_ -= siz; 92 + } 93 + 94 + //@{ テキスト削除(指定位置から末尾まで) //@} 95 + void RemoveToTail( ulong at ) 96 + { 97 + if( at < len_ ) 98 + str_[ len_=at ] = 0x007f; 99 + } 100 + 101 + //@{ バッファにコピー(指定位置から指定サイズ) //@} 102 + ulong CopyAt( ulong at, ulong siz, unicode* buf ) 103 + { 104 + memmove( buf, str_+at, siz*sizeof(unicode) ); 105 + return siz; 106 + } 107 + 108 + //@{ バッファにコピー(指定位置から末尾まで) //@} 109 + ulong CopyToTail( ulong at, unicode* buf ) 110 + { 111 + return CopyAt( at, len_-at, buf ); 112 + } 113 + 114 + //@{ 長さ //@} 115 + ulong size() const 116 + { return len_; } 117 + 118 + //@{ テキスト //@} 119 + unicode* str() 120 + { return str_; } 121 + 122 + //@{ テキスト(const) //@} 123 + const unicode* str() const 124 + { return str_; } 125 + 126 + //@{ 解析結果 //@} 127 + uchar* flg() 128 + { return flg_; } 129 + 130 + //@{ 解析結果(const) //@} 131 + const uchar* flg() const 132 + { return flg_; } 133 + 134 + // ask 135 + bool isCmtBitReady() const 136 + { return commentBitReady_; } 137 + uchar isLineHeadCmt() const 138 + { return isLineHeadCommented_; } 139 + // for doc 140 + uchar TransitCmt( uchar start ) 141 + { 142 + isLineHeadCommented_ = start; 143 + commentBitReady_ = false; 144 + return (commentTransition_>>start)&1; 145 + } 146 + // for parser 147 + void SetTransitFlag( uchar flag ) 148 + { commentTransition_ = flag; } 149 + void CommentBitUpdated() 150 + { commentBitReady_ = true; } 151 + 152 +private: 153 + ulong alen_; 154 + ulong len_; 155 + unicode* str_; 156 + uchar* flg_; 157 + 158 + uchar isLineHeadCommented_; 159 + uchar commentTransition_; 160 + bool commentBitReady_; 161 +}; 162 + 163 + 164 + 165 +//========================================================================= 166 +//@{ 167 +// Unicodeテキスト切り分け君 168 +// 169 +// 行単位で処理を行うことが多いので、その行毎に分ける処理を 170 +// 切り出した。getLine() するたびに、指定したポインタと整数変数へ 171 +// 先頭から順に行のデータを格納して行く。 172 +//@} 173 +//========================================================================= 174 + 175 +class UniReader 176 +{ 177 +public: 178 + 179 + //@{ 読みとり元バッファを与えて初期化 //@} 180 + UniReader( 181 + const unicode* str, ulong len, 182 + const unicode** ansstr, ulong* anslen ) 183 + : ptr_ ( str ) 184 + , end_ ( str+len ) 185 + , ans_ ( ansstr ) 186 + , aln_ ( anslen ) 187 + , empty_( false ) {} 188 + 189 + //@{ 読み終わったかどうかチェック //@} 190 + bool isEmpty() 191 + { return empty_; } 192 + 193 + //@{ 一行取得 //@} 194 + void getLine() 195 + { 196 + // 次の改行の位置を取得 197 + const unicode *p=ptr_, *e=end_; 198 + for( ; p<e; ++p ) 199 + if( *p == L'\r' || *p == L'\n' ) 200 + break; 201 + // 記録 202 + *ans_ = ptr_; 203 + *aln_ = int(p-ptr_); 204 + // 改行コードスキップ 205 + if( p == e ) 206 + empty_ = true; 207 + else 208 + if( *(p++)==L'\r'&& p<e && *p==L'\n' ) 209 + ++p; 210 + ptr_ = p; 211 + } 212 + 213 +private: 214 + bool empty_; 215 + const unicode *ptr_, *end_, **ans_; 216 + ulong *aln_; 217 +}; 218 + 219 + 220 + 221 +//========================================================================= 222 +//@{ 223 +// Undo/Redo用に、Commandオブジェクトを保存しておくクラス 224 +//@} 225 +//========================================================================= 226 + 227 +class UnReDoChain : public Object 228 +{ 229 +public: 230 + 231 + //@{ コンストラクタ //@} 232 + UnReDoChain(); 233 + 234 + //@{ デストラクタ //@} 235 + ~UnReDoChain(); 236 + 237 + //@{ Undo実行 //@} 238 + void Undo( Document& doc ); 239 + 240 + //@{ Redo実行 //@} 241 + void Redo( Document& doc ); 242 + 243 + //@{ 新しいコマンドを実行 //@} 244 + void NewlyExec( const Command& cmd, Document& doc ); 245 + 246 + //@{ 初期状態に戻す //@} 247 + void Clear(); 248 + 249 + //@{ 保存位置フラグを現在位置にセット //@} 250 + void SavedHere(); 251 + 252 + //@{ Undo/Redoの回数制限を指定。-1 = Infinite //@} 253 + void SetLimit( long lim ); 254 + 255 +public: 256 + 257 + //@{ Undo操作が可能か? //@} 258 + bool isUndoAble() const; 259 + 260 + //@{ Redo操作が可能か? //@} 261 + bool isRedoAble() const; 262 + 263 + //@{ 保存後、変更されているか? //@} 264 + bool isModified() const; 265 + 266 +private: 267 + 268 + struct Node : public Object 269 + { 270 + Node(); 271 + Node( Command*, Node*, Node* ); 272 + ~Node(); 273 + void ResetCommand( Command* cmd ); 274 + ulong ChainDelete(Node*& savedPos_ref); 275 + Node *next_, *prev_; 276 + Command *cmd_; 277 + }; 278 + 279 +private: 280 + 281 + Node headTail_; 282 + Node* savedPos_; 283 + Node* lastOp_; 284 + ulong num_; 285 + ulong limit_; 286 + 287 +private: 288 + 289 + NOCOPY(UnReDoChain); 290 +}; 291 + 292 + 293 + 294 +//------------------------------------------------------------------------- 295 +#ifndef __ccdoc__ 296 + 297 +inline void UnReDoChain::SavedHere() 298 + { savedPos_ = lastOp_; } 299 + 300 +inline bool UnReDoChain::isUndoAble() const 301 + { return (lastOp_ != &headTail_); } 302 + 303 +inline bool UnReDoChain::isRedoAble() const 304 + { return (lastOp_->next_ != &headTail_); } 305 + 306 +inline bool UnReDoChain::isModified() const 307 + { return (lastOp_ != savedPos_); } 308 + 309 + 310 + 311 +#endif // __ccdoc__ 312 +//========================================================================= 313 +//@{ 314 +// Documentクラスの実装部分 315 +//@} 316 +//========================================================================= 317 + 318 +class DocImpl : public Object, EzLockable, Runnable 319 +{ 320 +public: 321 + 322 + DocImpl( Document& theDoc ); 323 + ~DocImpl(); 324 + 325 + //@{ 操作コマンド実行 //@} 326 + void Execute( const Command& cmd ); 327 + 328 + //@{ キーワード定義切り替え //@} 329 + void SetKeyword( const unicode* defbuf, ulong siz ); 330 + 331 + //@{ イベントハンドラ登録 //@} 332 + void AddHandler( DocEvHandler* eh ); 333 + 334 + //@{ イベントハンドラ解除 //@} 335 + void DelHandler( DocEvHandler* eh ); 336 + 337 + //@{ ファイルを開く //@} 338 + void OpenFile( aptr<TextFileR> tf ); 339 + 340 + //@{ ファイルを保存 //@} 341 + void SaveFile( TextFileW& tf ); 342 + 343 + //@{ 内容破棄 //@} 344 + void ClearAll(); 345 + 346 + //@{ アンドゥ //@] 347 + void Undo(); 348 + 349 + //@{ リドゥ //@] 350 + void Redo(); 351 + 352 + //@{ アンドゥ回数制限 //@] 353 + void SetUndoLimit( long lim ); 354 + 355 + //@{ 変更フラグをクリア //@} 356 + void ClearModifyFlag(); 357 + 358 +public: 359 + 360 + //@{ 行数 //@} 361 + ulong tln() const; 362 + 363 + //@{ 行バッファ //@} 364 + const unicode* tl( ulong i ) const; 365 + 366 + //@{ 行解析結果バッファ //@} 367 + const uchar* pl( ulong i ) const; 368 + 369 + //@{ 行文字数 //@} 370 + ulong len( ulong i ) const; 371 + 372 + //@{ 指定範囲のテキストの長さ //@} 373 + ulong getRangeLength( const DPos& stt, const DPos& end ); 374 + 375 + //@{ 指定範囲のテキスト //@} 376 + void getText( unicode* buf, const DPos& stt, const DPos& end ); 377 + 378 + //@{ 指定位置の単語の先頭を取得 //@} 379 + DPos wordStartOf( const DPos& dp ) const; 380 + 381 + //@{ 指定位置の一つ左の位置を取得 //@} 382 + DPos leftOf( const DPos& dp, bool wide=false ) const; 383 + 384 + //@{ 指定位置の一つ右の位置を取得 //@} 385 + DPos rightOf( const DPos& dp, bool wide=false ) const; 386 + 387 + //@{ アンドゥ可能? //@} 388 + bool isUndoAble() const; 389 + 390 + //@{ リドゥ可能? //@} 391 + bool isRedoAble() const; 392 + 393 + //@{ 変更済み? //@} 394 + bool isModified() const; 395 + 396 +private: 397 + 398 + Document& doc_; // 自分 399 + aptr<Parser> parser_; // 文字列解析役 400 + gapbufobj<Line> text_; // テキストデータ 401 + mutable storage<DocEvHandler*> pEvHan_; // イベント通知先 402 + UnReDoChain urdo_; // アンドゥリドゥ 403 + 404 + aptr<TextFileR> currentOpeningFile_; 405 + 406 +private: 407 + 408 + // 変更通知 409 + void Fire_KEYWORDCHANGE(); 410 + void Fire_MODIFYFLAGCHANGE(); 411 + void Fire_TEXTUPDATE( const DPos& s, 412 + const DPos& e, const DPos& e2, bool reparsed, bool nmlcmd ); 413 + 414 + // ヘルパー関数 415 + bool ReParse( ulong s, ulong e ); 416 + void SetCommentBit( const Line& x ) const; 417 + void CorrectPos( DPos& pos ); 418 + void CorrectPos( DPos& stt, DPos& end ); 419 + 420 + // 挿入・削除作業 421 + bool InsertingOperation( 422 + DPos& stt, const unicode* str, ulong len, DPos& undoend ); 423 + bool DeletingOperation( 424 + DPos& stt, DPos& end, unicode*& undobuf, ulong& undosiz ); 425 + 426 + // パラレルリード 427 + virtual void StartThread(); 428 + 429 +private: 430 + 431 + NOCOPY(DocImpl); 432 + friend class Insert; 433 + friend class Delete; 434 + friend class Replace; 435 +}; 436 + 437 + 438 + 439 +//------------------------------------------------------------------------- 440 + 441 +inline ulong DocImpl::tln() const 442 + { return text_.size(); } 443 + 444 +inline const unicode* DocImpl::tl( ulong i ) const 445 + { return text_[i].str(); } 446 + 447 +inline ulong DocImpl::len( ulong i ) const 448 + { return text_[i].size(); } 449 + 450 +inline const uchar* DocImpl::pl( ulong i ) const 451 + { 452 + const Line& x = text_[i]; 453 + if( !x.isCmtBitReady() ) 454 + SetCommentBit( x ); 455 + return x.flg(); 456 + } 457 + 458 + 459 + 460 +//========================================================================= 461 + 462 +}} // namespace editwing::doc 463 +#endif // _EDITWING_IP_DOC_H_
Added editwing/ip_draw.cpp version [b299730b30885144]
1 +#include "stdafx.h" 2 +#include "ip_view.h" 3 +using namespace editwing; 4 +using namespace editwing::view; 5 + 6 + 7 + 8 +//========================================================================= 9 +//---- ip_draw.cpp 描画・他 10 +// 11 +// 折り返しとか色とかを考慮しつつ、実際に描画処理を 12 +// 行うのがここ。あとメッセージディスパッチャなども 13 +// ついでにこのファイルに。^^; 14 +// 15 +//---- ip_text.cpp 文字列操作・他 16 +//---- ip_parse.cpp キーワード解析 17 +//---- ip_wrap.cpp 折り返し 18 +//---- ip_scroll.cpp スクロール 19 +//---- ip_cursor.cpp カーソルコントロール 20 +//========================================================================= 21 + 22 + 23 + 24 +//------------------------------------------------------------------------- 25 +// Viewの初期化・解放 26 +//------------------------------------------------------------------------- 27 + 28 +View::ClsName 29 + View::className_ = TEXT("EditWing View"); 30 + 31 +View::View( doc::Document& d, HWND wnd ) 32 + : WndImpl( className_, WS_CHILD|WS_VISIBLE|WS_VSCROLL|WS_HSCROLL ) 33 + , doc_ ( d.impl() ) 34 +{ 35 + static bool ClassRegistered = false; 36 + if( !ClassRegistered ) 37 + { 38 + // 初回構築時のみ、クラス登録を行う 39 + ClassRegistered = true; 40 + WNDCLASSEX wc = {0}; 41 + wc.lpszClassName = className_; 42 + wc.style = CS_DBLCLKS | CS_OWNDC; 43 + wc.hCursor = app().LoadOemCursor( IDC_IBEAM ); 44 + 45 + // GlobalIMEを有効にする 46 + ATOM a = WndImpl::Register( &wc ); 47 + ime().FilterWindows( &a, 1 ); 48 + } 49 + 50 + // 窓作成 51 + Create( NULL, wnd ); 52 +} 53 + 54 +View::~View() 55 +{ 56 + // 窓破棄 57 + Destroy(); 58 +} 59 + 60 +void View::on_create( CREATESTRUCT* cs ) 61 +{ 62 + impl_ = new ViewImpl( *this, doc_ ); 63 + doc_.AddHandler( this ); 64 +} 65 + 66 +void View::on_destroy() 67 +{ 68 + doc_.DelHandler( this ); 69 + impl_ = NULL; 70 +} 71 + 72 + 73 + 74 +//------------------------------------------------------------------------- 75 +// サブオブジェクトにそのまま回す 76 +//------------------------------------------------------------------------- 77 + 78 +void View::SetWrapType( int wt ) 79 + { impl_->SetWrapType( wt ); } 80 + 81 +void View::ShowLineNo( bool show ) 82 + { impl_->ShowLineNo( show ); } 83 + 84 +void View::SetFont( const VConfig& vc ) 85 + { impl_->SetFont( vc ); } 86 + 87 +void View::on_keyword_change() 88 + { ::InvalidateRect( hwnd(), NULL, FALSE ); } 89 + 90 +void View::on_text_update 91 + ( const DPos& s, const DPos& e, const DPos& e2, bool bAft, bool mCur ) 92 + { impl_->on_text_update( s, e, e2, bAft, mCur ); } 93 + 94 +Cursor& View::cur() 95 + { return impl_->cur(); } 96 + 97 +LRESULT View::on_message( UINT msg, WPARAM wp, LPARAM lp ) 98 +{ 99 + switch( msg ) 100 + { 101 + case WM_PAINT:{ 102 + PAINTSTRUCT ps; 103 + ::BeginPaint( hwnd(), &ps ); 104 + impl_->on_paint( ps ); 105 + ::EndPaint( hwnd(), &ps ); 106 + }break; 107 + 108 + case WM_SIZE: 109 + impl_->on_view_resize( LOWORD(lp), HIWORD(lp) ); 110 + break; 111 + 112 + case WM_HSCROLL: 113 + impl_->on_hscroll( LOWORD(wp) ); 114 + break; 115 + 116 + case WM_VSCROLL: 117 + impl_->on_vscroll( LOWORD(wp) ); 118 + break; 119 + 120 + case WM_MOUSEWHEEL: 121 + impl_->on_wheel( HIWORD(wp) ); 122 + break; 123 + 124 + case WM_SETFOCUS: 125 + cur().on_setfocus(); 126 + break; 127 + 128 + case WM_KILLFOCUS: 129 + cur().on_killfocus(); 130 + break; 131 + 132 + case WM_TIMER: 133 + cur().on_timer(); 134 + break; 135 + 136 + case WM_KEYDOWN: 137 + cur().on_keydown( (int)wp, lp ); 138 + break; 139 + 140 + case WM_CHAR: 141 + cur().on_char( (TCHAR)wp ); 142 + break; 143 + 144 + case WM_LBUTTONDOWN: 145 + cur().on_lbutton_down( LOWORD(lp), HIWORD(lp), (wp&MK_SHIFT)!=0 ); 146 + break; 147 + 148 + case WM_LBUTTONUP: 149 + cur().on_lbutton_up( LOWORD(lp), HIWORD(lp) ); 150 + break; 151 + 152 + case WM_LBUTTONDBLCLK: 153 + cur().on_lbutton_dbl( LOWORD(lp), HIWORD(lp) ); 154 + break; 155 + 156 + case WM_MOUSEMOVE: 157 + cur().on_mouse_move( LOWORD(lp), HIWORD(lp) ); 158 + break; 159 + 160 + case WM_CONTEXTMENU: 161 + if( !cur().on_contextmenu( LOWORD(lp), HIWORD(lp) ) ) 162 + return WndImpl::on_message( msg, wp, lp ); 163 + break; 164 + 165 + case WM_IME_REQUEST: 166 + switch( wp ) 167 + { 168 + case IMR_RECONVERTSTRING: 169 + return cur().on_ime_reconvertstring( 170 + reinterpret_cast<RECONVERTSTRING*>(lp) ); 171 + case IMR_CONFIRMRECONVERTSTRING: 172 + return cur().on_ime_confirmreconvertstring( 173 + reinterpret_cast<RECONVERTSTRING*>(lp) ); 174 + } 175 + break; 176 + 177 + case WM_IME_STARTCOMPOSITION: 178 + cur().on_ime_composition( 0 ); 179 + return WndImpl::on_message( msg, wp, lp ); 180 + 181 + case WM_IME_COMPOSITION: 182 + cur().on_ime_composition( lp ); 183 + if( lp&GCS_RESULTSTR ) 184 + break; 185 + // fall through... 186 + 187 + default: 188 + return WndImpl::on_message( msg, wp, lp ); 189 + } 190 + return 0; 191 +} 192 + 193 + 194 + 195 +//------------------------------------------------------------------------- 196 +// 線を引くとか四角く塗るとか、そーいう基本的な処理 197 +//------------------------------------------------------------------------- 198 + 199 +Painter::Painter( HDC hdc, const VConfig& vc ) 200 + : dc_ ( hdc ) 201 + , font_ ( ::CreateFontIndirect( &vc.font ) ) 202 + , pen_ ( ::CreatePen( PS_SOLID, 0, vc.color[CTL] ) ) 203 + , brush_ ( ::CreateSolidBrush( vc.color[BG] ) ) 204 + , widthTable_( new int[65536] ) 205 +{ 206 + // 制御文字を描画するか否か?のフラグを記憶 207 + for( int i=0; i<countof(scDraw_); ++i ) 208 + scDraw_[i] = vc.sc[i]; 209 + 210 + // 文字色を記憶 211 + for( int i=0; i<countof(colorTable_); ++i ) 212 + colorTable_[i] = vc.color[i]; 213 + colorTable_[3] = vc.color[CMT]; 214 + 215 + // DCにセット 216 + ::SelectObject( dc_, font_ ); 217 + ::SelectObject( dc_, pen_ ); 218 + ::SelectObject( dc_, brush_ ); 219 + ::SetBkMode( dc_, TRANSPARENT ); 220 + ::SetMapMode( dc_, MM_TEXT ); 221 + 222 + // 文字幅テーブル初期化(ASCII範囲の文字以外は遅延処理) 223 + memFF( widthTable_, 65536*sizeof(int) ); 224 + ::GetCharWidthW( dc_, L' ', L'~', widthTable_+L' ' ); 225 + widthTable_[L'\t'] = W() * Max(1,vc.tabstep); 226 + // 下位サロゲートは文字幅ゼロ 227 + mem00( widthTable_+0xDC00, (0xE000 - 0xDC00)*sizeof(int) ); 228 + 229 + // 数字の最大幅を計算 230 + figWidth_ = 0; 231 + for( unicode ch=L'0'; ch<=L'9'; ++ch ) 232 + if( figWidth_ < widthTable_[ch] ) 233 + figWidth_ = widthTable_[ch]; 234 + 235 + // 高さの情報 236 + TEXTMETRIC met; 237 + ::GetTextMetrics( dc_, &met ); 238 + height_ = met.tmHeight; 239 + 240 + // LOGFONT 241 + ::GetObject( font_, sizeof(LOGFONT), &logfont_ ); 242 +} 243 + 244 +Painter::~Painter() 245 +{ 246 + // 適当な別オブジェクトをくっつけて自分を解放する 247 + ::SelectObject( dc_, ::GetStockObject( OEM_FIXED_FONT ) ); 248 + ::SelectObject( dc_, ::GetStockObject( BLACK_PEN ) ); 249 + ::SelectObject( dc_, ::GetStockObject( WHITE_BRUSH ) ); 250 + ::DeleteObject( font_ ); 251 + ::DeleteObject( pen_ ); 252 + ::DeleteObject( brush_ ); 253 + delete [] widthTable_; 254 +} 255 + 256 +inline void Painter::CharOut( unicode ch, int x, int y ) 257 +{ 258 + ::TextOutW( dc_, x, y, &ch, 1 ); 259 +} 260 + 261 +inline void Painter::StringOut 262 + ( const unicode* str, int len, int x, int y ) 263 +{ 264 + ::TextOutW( dc_, x, y, str, len ); 265 +} 266 + 267 +inline void Painter::SetColor( int i ) 268 +{ 269 + ::SetTextColor( dc_, colorTable_[i] ); 270 +} 271 + 272 +inline void Painter::Fill( const RECT& rc ) 273 +{ 274 + ::FillRect( dc_, &rc, brush_ ); 275 +} 276 + 277 +inline void Painter::Invert( const RECT& rc ) 278 +{ 279 + ::InvertRect( dc_, &rc ); 280 +} 281 + 282 +inline void Painter::DrawLine( int x1, int y1, int x2, int y2 ) 283 +{ 284 + ::MoveToEx( dc_, x1, y1, NULL ); 285 + ::LineTo( dc_, x2, y2 ); 286 +} 287 + 288 +inline void Painter::SetClip( const RECT& rc ) 289 +{ 290 + ::IntersectClipRect( dc_, rc.left, rc.top, rc.right, rc.bottom ); 291 +} 292 + 293 +inline void Painter::ClearClip() 294 +{ 295 + ::SelectClipRgn( dc_, NULL ); 296 +} 297 + 298 +void Painter::DrawHSP( int x, int y, int times ) 299 +{ 300 + // 半角スペース記号(ホチキスの芯型)を描く 301 + const int w=Wc(L' '), h=H(); 302 + POINT pt[4] = { 303 + { x , y+h-4 }, 304 + { x , y+h-2 }, 305 + { x+w-3, y+h-2 }, 306 + { x+w-3, y+h-5 } 307 + }; 308 + while( times-- ) 309 + { 310 + if( 0 <= pt[3].x ) 311 + ::Polyline( dc_, pt, countof(pt) ); 312 + pt[0].x += w; 313 + pt[1].x += w; 314 + pt[2].x += w; 315 + pt[3].x += w; 316 + } 317 +} 318 + 319 +void Painter::DrawZSP( int x, int y, int times ) 320 +{ 321 + // 全角スペース記号(平たい四角)を描く 322 + const int w=Wc(0x3000/*L' '*/), h=H(); 323 + POINT pt[4] = { 324 + { x , y+h-4 }, 325 + { x , y+h-2 }, 326 + { x+w-3, y+h-2 }, 327 + { x+w-3, y+h-4 } 328 + }; 329 + while( times-- ) 330 + { 331 + if( 0 <= pt[3].x ) 332 + ::Polygon( dc_, pt, countof(pt) ); 333 + pt[0].x += w; 334 + pt[1].x += w; 335 + pt[2].x += w; 336 + pt[3].x += w; 337 + } 338 +} 339 + 340 + 341 + 342 +//------------------------------------------------------------------------- 343 +// 再描画したい範囲を Invalidate する。 344 +//------------------------------------------------------------------------- 345 + 346 +void ViewImpl::ReDraw( ReDrawType r, const DPos* s ) 347 +{ 348 + // まずスクロールバーを更新 349 + UpdateScrollBar(); 350 + 351 + switch( r ) 352 + { 353 + case ALL: // 全画面 354 + 355 + ::InvalidateRect( hwnd_, NULL, FALSE ); 356 + break; 357 + 358 + case LNAREA: // 行番号表示域のみ 359 + 360 + if( lna() > 0 ) 361 + { 362 + RECT rc = { 0, 0, lna(), bottom() }; 363 + ::InvalidateRect( hwnd_, &rc, FALSE ); 364 + } 365 + break; 366 + 367 + case LINE: // 指定した行の後半 368 + case AFTER: // 指定した行以下全部 369 + 370 + { 371 + DPos st = ( s->ad==0 ? *s : doc_.leftOf(*s,true) ); 372 + InvalidateView( st, r==AFTER ); 373 + } 374 + } 375 +} 376 + 377 + 378 + 379 +//------------------------------------------------------------------------- 380 +// WM_PAINTハンドラ 381 +//------------------------------------------------------------------------- 382 + 383 +void ViewImpl::on_paint( const PAINTSTRUCT& ps ) 384 +{ 385 + // 描画範囲の情報を詳しく取得 386 + Painter& p = cvs_.getPainter(); 387 + VDrawInfo v( ps.rcPaint ); 388 + GetDrawPosInfo( v ); 389 + 390 + if( ps.rcPaint.right <= lna() ) 391 + { 392 + // case A: 行番号表示域のみ更新 393 + DrawLNA( v, p ); 394 + } 395 + else if( lna() <= ps.rcPaint.left ) 396 + { 397 + // case B: テキスト表示域のみ更新 398 + DrawTXT( v, p ); 399 + } 400 + else 401 + { 402 + // case C: 両方更新 403 + DrawLNA( v, p ); 404 + p.SetClip( cvs_.zone() ); 405 + DrawTXT( v, p ); 406 + p.ClearClip(); 407 + } 408 +} 409 + 410 + 411 + 412 +//------------------------------------------------------------------------- 413 +// 行番号ゾーン描画 414 +//------------------------------------------------------------------------- 415 + 416 +void ViewImpl::DrawLNA( const VDrawInfo& v, Painter& p ) 417 +{ 418 + // 419 + // 文字列のまま足し算を行うルーチン 420 + // 421 + struct strint { 422 + strint( ulong num ) { 423 + int i=11; 424 + while( num ) digit[--i] = (unicode)(L'0'+(num%10)), num/=10; 425 + while( i ) digit[--i] = L' '; 426 + } 427 + void operator++() { 428 + int i=10; 429 + do 430 + if( digit[i] == L'9' ) 431 + digit[i] = L'0'; 432 + else 433 + { ++digit[i]; return; } 434 + while( digit[--i] != L' ' ); 435 + digit[i] = L'1'; 436 + } 437 + void Output( Painter& f, int x, int y ) { 438 + for( unicode* p=digit+10; *p!=L' '; --p,x-=f.F() ) 439 + f.CharOut( *p, x, y ); 440 + } 441 + unicode digit[11]; 442 + }; 443 + 444 + // 背面消去 445 + RECT rc = { v.rc.left, v.rc.top, lna(), v.rc.bottom }; 446 + p.Fill( rc ); 447 + 448 + if( v.rc.top < v.YMAX ) 449 + { 450 + // 境界線表示 451 + int line = lna() - p.F()/2; 452 + p.DrawLine( line, v.rc.top, line, v.YMAX ); 453 + p.SetColor( LN ); 454 + 455 + // 行番号表示 456 + strint n = v.TLMIN+1; 457 + int y = v.YMIN; 458 + int edge = lna() - p.F()*2; 459 + for( ulong i=v.TLMIN; y<v.YMAX; ++i,++n ) 460 + { 461 + n.Output( p, edge, y ); 462 + y += p.H() * rln(i); 463 + } 464 + } 465 +} 466 + 467 + 468 + 469 +//------------------------------------------------------------------------- 470 +// テキスト描画 471 +//------------------------------------------------------------------------- 472 + 473 +inline void ViewImpl::Inv( int y, int xb, int xe, Painter& p ) 474 +{ 475 + RECT rc = { 476 + Max( left(), xb ), y, 477 + Min( right(), xe ), y+p.H()-1 478 + }; 479 + p.Invert( rc ); 480 +} 481 + 482 +void ViewImpl::DrawTXT( const VDrawInfo v, Painter& p ) 483 +{ 484 + // 定数1 485 +// const int TAB = p.T(); 486 + const int H = p.H(); 487 + const ulong TLM = doc_.tln()-1; 488 + 489 + // 作業用変数1 490 + RECT a = { 0, v.YMIN, 0, v.YMIN+p.H() }; 491 + int clr = -1; 492 + register int x, x2; 493 + register ulong i, i2; 494 + 495 + // 論理行単位のLoop 496 + for( ulong tl=v.TLMIN; a.top<v.YMAX; ++tl ) 497 + { 498 + // 定数2 499 + const unicode* str = doc_.tl(tl); 500 + const uchar* flg = doc_.pl(tl); 501 + const int rYMAX = Min<int>( v.YMAX, a.top+rln(tl)*H ); 502 + 503 + // 作業用変数2 504 + ulong stt=0, end, t, n; 505 + 506 + // 表示行単位のLoop 507 + for( ulong rl=0; a.top<rYMAX; ++rl,a.top+=H,a.bottom+=H,stt=end ) 508 + { 509 + // 作業用変数3 510 + end = rlend(tl,rl); 511 + if( a.bottom<=v.YMIN ) 512 + continue; 513 + 514 + // テキストデータ描画 515 + for( x2=x=0,i2=i=stt; x<=v.XMAX && i<end; x=x2,i=i2 ) 516 + { 517 + // n := 次のTokenの頭 518 + t = (flg[i]>>5); 519 + n = i + t; 520 + if( n >= end ) 521 + n = end; 522 + else if( t==7 || t==0 ) 523 + while( n<end && (flg[n]>>5)==0 ) 524 + ++n; 525 + 526 + // x2, i2 := このTokenの右端 527 + i2 ++; 528 + x2 = (str[i]==L'\t' ? p.nextTab(x2) : x2+p.W(&str[i])); 529 + // if( x2 <= v.XMIN ) 530 + // x=x2, i=i2; 531 + while( i2<n && x2<=v.XMAX ) 532 + x2 += p.W( &str[i2++] ); 533 + 534 + // 再描画すべき範囲と重なっていない 535 + if( x2<=v.XMIN ) 536 + continue; 537 + 538 + // x, i := このトークンの左端 539 + if( x<v.XMIN ) 540 + { 541 + // tabの分が戻りすぎ? 542 + x = x2, i = i2; 543 + while( v.XMIN<x ) 544 + x -= p.W( &str[--i] ); 545 + } 546 + 547 + // 背景塗りつぶし 548 + a.left = x + v.XBASE; 549 + a.right = x2 + v.XBASE; 550 + p.Fill( a ); 551 + 552 + // 描画 553 + switch( str[i] ) 554 + { 555 + case L'\t': 556 + if( p.sc(scTAB) ) 557 + { 558 + p.SetColor( clr=CTL ); 559 + for( ; i<i2; ++i, x=p.nextTab(x) ) 560 + p.CharOut( L'>', x+v.XBASE, a.top ); 561 + } 562 + break; 563 + case L' ': 564 + if( p.sc(scHSP) ) 565 + p.DrawHSP( x+v.XBASE, a.top, i2-i ); 566 + break; 567 + case 0x3000://L' ': 568 + if( p.sc(scZSP) ) 569 + p.DrawZSP( x+v.XBASE, a.top, i2-i ); 570 + break; 571 + default: 572 + if( clr != (flg[i]&3) ) 573 + p.SetColor( clr=(flg[i]&3) ); 574 + p.StringOut( str+i, i2-i, x+v.XBASE, a.top ); 575 + //p.StringOut( str+i, i2-i, x+v.XBASE, a.top ); 576 + // 何故だか2度描きしないとうまくいかん… 577 + break; 578 + } 579 + } 580 + 581 + // 選択範囲だったら反転 582 + if( v.SYB<=a.top && a.top<=v.SYE ) 583 + Inv( a.top, a.top==v.SYB?v.SXB:(v.XBASE), 584 + a.top==v.SYE?v.SXE:(v.XBASE+x), p ); 585 + 586 + // 行末より後ろの余白を背景色塗 587 + if( x<v.XMAX ) 588 + { 589 + a.left = v.XBASE + Max( v.XMIN, x ); 590 + a.right= v.XBASE + v.XMAX; 591 + p.Fill( a ); 592 + } 593 + } 594 + 595 + // 行末記号描画反転 596 + SpecialChars sc = (tl==TLM ? scEOF : scEOL); 597 + if( i==doc_.len(tl) && -32768<x+v.XBASE ) 598 + { 599 + if( p.sc(sc) ) 600 + { 601 + static const unicode* const sstr[] = { L"[EOF]", L"/" }; 602 + static const int slen[] = { 5, 1 }; 603 + p.SetColor( clr=CTL ); 604 + p.StringOut( sstr[sc], slen[sc], x+v.XBASE, a.top-H ); 605 + } 606 + if( v.SYB<a.top && a.top<=v.SYE && sc==scEOL ) 607 + Inv( a.top-H, x+v.XBASE, x+v.XBASE+p.Wc(L'/'), p ); 608 + } 609 + } 610 + 611 + // EOF後余白を背景色塗 612 + if( a.top < v.rc.bottom ) 613 + { 614 + a.left = v.rc.left; 615 + a.right = v.rc.right; 616 + a.bottom = v.rc.bottom; 617 + p.Fill( a ); 618 + } 619 +}
Added editwing/ip_parse.cpp version [81bbb0c1ba6ccbac]
1 +#include "stdafx.h" 2 +#include "ip_doc.h" 3 +using namespace editwing; 4 +using namespace editwing::doc; 5 + 6 + 7 + 8 +//========================================================================= 9 +//---- ip_parse.cpp キーワード解析 10 +// 11 +// キーワード定義ファイルに従って、保持する文字列を 12 +// 適切に切り分ける作業がここ。 13 +// 14 +//---- ip_text.cpp 文字列操作・他 15 +//---- ip_wrap.cpp 折り返し 16 +//---- ip_scroll.cpp スクロール 17 +//---- ip_draw.cpp 描画・他 18 +//---- ip_cursor.cpp カーソルコントロール 19 +//========================================================================= 20 + 21 + 22 + 23 +//========================================================================= 24 +// 25 +// 解析結果データ仕様 26 +// これだけ色々姑息な手段を持ち込んで本当に 27 +// 速くなっているのかどうかは不明…(^^; 28 +// 29 +// ----------------------------------------------- 30 +// 31 +// Line::isLineHeadCommented_ 32 +// 0: 行頭がブロックコメントの内部ではない 33 +// 1: 行頭がブロックコメントの内部 34 +// 35 +// ----------------------------------------------- 36 +// 37 +// Line::commentTransition_ 38 +// 00: 行末は常にコメントの外 39 +// 01: 行頭と行末はコメント状態が逆転 40 +// 10: 行頭と行末はコメント状態が同じ 41 +// 11: 行末は常にコメントの中 42 +// 43 +// ----------------------------------------------- 44 +// 45 +// 以上二つのフラグを元に、前の行の情報から今の行の情報を 46 +// this.head = (prev.trans >> prev.head)&1; 47 +// で順次計算していくことが出来る。 48 +// この計算の際に内部バッファの状態まで書き換えるのは 49 +// コストがでかすぎるので、次に示すフラグを見ながら 50 +// 描画寸前に適宜調整する。 51 +// 52 +// ----------------------------------------------- 53 +// 54 +// Line::commentBitReady_ 55 +// コメントビットが調整済みかどうか 56 +// 57 +// ----------------------------------------------- 58 +// 59 +// Line::str_[] 60 +// UCS-2ベタで、文字列データがそのまま格納される。 61 +// ただし、パーサの高速化のために最終文字の後ろに 62 +// 0x007fが付加される。 63 +// 64 +// ----------------------------------------------- 65 +// 66 +// Line::flg_ 67 +// 一文字毎に、下のような8bitのフラグを割り当てる 68 +// | aaabbbcd | 69 +// 70 +// ----------------------------------------------- 71 +// 72 +// aaa == "PosInToken" 73 +// 0: トークンの途中 74 +// 1-6: トークンの頭。次の頭は1-6文字先。 75 +// 7: トークンの頭。次の頭は7文字以上先。 76 +// 77 +// ----------------------------------------------- 78 +// 79 +// bbb == "TokenType" 80 +// 0: TAB: タブ文字 81 +// 1: WSP: ホワイトスペース 82 +// 2: TXT: 普通の文字 83 +// 3: CE: コメント開始タグ 84 +// 4: CB: コメント終了タグ 85 +// 5: LB: 行コメント開始タグ 86 +// 6: Q1: '' 引用符1 87 +// 7: Q2: "" 引用符2 88 +// 89 +// ----------------------------------------------- 90 +// 91 +// c == "isKeyword?" 92 +// 0: キーワードではない 93 +// 1: キーワード 94 +// 95 +// ----------------------------------------------- 96 +// 97 +// d == "inComment?" 98 +// 0: コメントの中ではない 99 +// 1: コメントの中 100 +// 101 +// ----------------------------------------------- 102 + 103 + 104 + 105 +namespace { 106 +//------------------------------------------------------------------------- 107 +// コメントの中なのか外なのか等を判定するためのオートマトン 108 +// 109 +// /* が出たらその後ろはコメントで */ が出たらその後ろはノーマルゾーン 110 +// …という単純な規則では上手く行かない。例えば str"/*"str なんてものが 111 +// 出現した場合に困ってしまう。そこで、 112 +// ・普通のテキスト 113 +// ・ブロックコメントの中 114 +// ・行コメントの中 115 +// ・一重引用符の中 116 +// ・二重引用符の中 117 +// の5種類の状態に分けて、それぞれの場合について、どの記号が出たら 118 +// 次にどの状態に移るのか…を処理する必要がある。その状態変化の規則を 119 +// 5x5の2次元配列で与えて管理する。 120 +//------------------------------------------------------------------------- 121 + 122 +enum CommentDFASymbol{ sCB, sCE, sLB, sQ1, sQ2, sXXX }; 123 +struct CommentDFA 124 +{ 125 + // <状態> 126 + // 最下位bitが、現在コメント内かどうかのフラグになります。 127 + // ブロックコメント中かどうかは (state>>1)&(state) で。 128 + // 000: normal text 011: in BlockComment 129 + // 001: in LineComment 100: in Quote2 130 + // 010: in Quote1 131 + // 132 + // <シンボル> 133 + // C++で言うと下の通り 134 + // 値はTokenTypeフラグとシンクロするようになってます。 135 + // 000: CE */ 011: Q1 ' 136 + // 001: CB /* 100: Q2 " 137 + // 010: LB // 138 + 139 + // 初期状態を指定。コメント内かコメント外か 140 + CommentDFA( bool inComment ) 141 + : state( inComment ? 3 : 0 ) {} 142 + 143 + // 入力符号を与えて状態遷移 144 + void transit( int sym ) 145 + { state = tr_table[state][sym]; } 146 + 147 + // 現在の状態 148 + int state; 149 + 150 + // 状態遷移テーブル 151 + static const int tr_table[5][5]; 152 +}; 153 + 154 +const int CommentDFA::tr_table[5][5] = { 155 + {0,3,1,2,4}, 156 + {1,1,1,1,1}, 157 + {2,2,2,0,2}, 158 + {0,3,3,3,3}, 159 + {4,4,4,4,0}, 160 +}; 161 + 162 + 163 + 164 +//------------------------------------------------------------------------- 165 +// 単純な、キーワード格納構造体。 166 +// ChainHashの要素にするためnextポインタがつけてあります。 167 +//------------------------------------------------------------------------- 168 + 169 +struct Keyword : public Object 170 +{ 171 + unicode* str; 172 + const ulong len; 173 + Keyword* next; 174 + 175 + Keyword( const unicode* s, ulong l ) 176 + : str( new unicode[l+1] ) 177 + , len( l ) 178 + , next( NULL ) 179 + { memmove( str, s, l*sizeof(unicode) ); } 180 + 181 + ~Keyword() 182 + { delete [] str; } 183 +}; 184 + 185 + 186 + 187 +//------------------------------------------------------------------------- 188 +// サポート関数。Unicodeテキスト同士の比較 189 +//------------------------------------------------------------------------- 190 + 191 +static bool compare_s(const unicode* a,const unicode* b,ulong l) 192 +{ 193 + // 大文字小文字を区別 194 + while( l-- ) 195 + if( *a++ != *b++ ) 196 + return false; 197 + return true; 198 +} 199 + 200 +static bool compare_i(const unicode* a,const unicode* b,ulong l) 201 +{ 202 + // 大文字小文字を区別しない(雑) 203 + while( l-- ) 204 + if( ((*a++) ^ (*b++)) & 0xdf ) 205 + return false; 206 + return true; 207 +} 208 + 209 + 210 + 211 +//------------------------------------------------------------------------- 212 +// 与えられた記号文字列から、コメント開始等の意味のあるトークンを 213 +// 切り出してくるための構造。 214 +//------------------------------------------------------------------------- 215 + 216 +class TagMap 217 +{ 218 + Keyword* tag_[3]; // 0:CE 1:CB 2:LB 219 + bool esc_, q1_, q2_, map_[128]; 220 + 221 +public: 222 + 223 + TagMap( const unicode* cb, ulong cblen, 224 + const unicode* ce, ulong celen, 225 + const unicode* lb, ulong lblen, 226 + bool q1, bool q2, bool esc ) 227 + : q1_ ( q1 ) 228 + , q2_ ( q2 ) 229 + , esc_( esc ) 230 + { 231 + // '/' で始まる記号は使われているか…? 232 + // みたいな、1文字目のみのチェックに使う表を作成 233 + tag_[0] = tag_[1] = tag_[2] = NULL; 234 + mem00( map_, sizeof(map_) ); 235 + map_[L'\''] = q1; 236 + map_[L'\"'] = q2; 237 + map_[L'\\'] = esc; 238 + if( celen!=0 ){ map_[*ce]=true; tag_[0]=new Keyword(ce,celen); } 239 + if( cblen!=0 ){ map_[*cb]=true; tag_[1]=new Keyword(cb,cblen); } 240 + if( lblen!=0 ){ map_[*lb]=true; tag_[2]=new Keyword(lb,lblen); } 241 + } 242 + 243 + ~TagMap() 244 + { 245 + // キーワード解放 246 + delete tag_[0]; 247 + delete tag_[1]; 248 + delete tag_[2]; 249 + } 250 + 251 + bool does_esc() 252 + { 253 + // \ によるエスケープをするかどうか 254 + return esc_; 255 + } 256 + 257 + ulong SymbolLoop( 258 + const unicode* str, ulong len, ulong& mlen, int& sym ) 259 + { 260 + // 有意味な記号にマッチするまでループ 261 + // 返値に、マッチするまでに飛ばした文字数、 262 + // mlen,symに、マッチした記号の情報を返す 263 + 264 + int i; 265 + ulong ans=0; 266 + for( sym=sXXX, mlen=1; ans<len; ++ans ) 267 + if( map_[str[ans]] ) 268 + { 269 + for( i=2; i>=0; --i ) 270 + if( tag_[i]!=NULL 271 + && tag_[i]->len <= len-ans 272 + && compare_s( 273 + tag_[i]->str, str+ans, tag_[i]->len ) ) 274 + { 275 + sym = i; 276 + mlen = tag_[i]->len; 277 + goto symbolfound; 278 + } 279 + if( str[ans] == L'\'' ) // 一重引用符 280 + { 281 + if( q1_ ) 282 + { 283 + sym = sQ1; 284 + goto symbolfound; 285 + } 286 + } 287 + else if( str[ans] == L'\"' ) // 二重引用符 288 + { 289 + if( q2_ ) 290 + { 291 + sym = sQ2; 292 + goto symbolfound; 293 + } 294 + } 295 + else if( str[ans] == L'\\' ) // \ の後の文字はSkip 296 + { 297 + if( esc_ && ans+1<len ) 298 + ++ans; 299 + } 300 + } 301 + 302 + symbolfound: 303 + return ans; 304 + } 305 +}; 306 + 307 + 308 + 309 +//------------------------------------------------------------------------- 310 +// 与えられた文字列がキーワードかどうか高速判定するためのハッシュ表 311 +//------------------------------------------------------------------------- 312 + 313 +class KeywordMap 314 +{ 315 + Keyword* backet_[4096]; 316 + storage<Keyword*> dustbox_; 317 + bool (*compare_)(const unicode*,const unicode*,ulong); 318 + 319 +public: 320 + 321 + KeywordMap( bool bCaseSensitive ) 322 + : compare_( bCaseSensitive ? compare_s : compare_i ) 323 + { 324 + // ハッシュ表初期化 325 + mem00( backet_, sizeof(backet_) ); 326 + } 327 + 328 + ~KeywordMap() 329 + { 330 + // 解放 331 + for( ulong i=0; i<dustbox_.size(); ++i ) 332 + delete dustbox_[i]; 333 + } 334 + 335 + void AddKeyword( const unicode* str, ulong len ) 336 + { 337 + // データ登録 338 + Keyword* x = new Keyword(str,len); 339 + int h = hash(str,len); 340 + 341 + if( backet_[h] == NULL ) 342 + { 343 + // ハッシュテーブルが空の場合 344 + backet_[h] = x; 345 + } 346 + else 347 + { 348 + // チェイン末尾に繋ぐ場合 349 + Keyword *q=backet_[h],*p=backet_[h]->next; 350 + while( p!=NULL ) 351 + q=p, p=p->next; 352 + q->next = x; 353 + } 354 + 355 + // データクリア用のリストにも入れておく 356 + dustbox_.Add(x); 357 + } 358 + 359 + ulong isKeyword( const unicode* str, ulong len ) 360 + { 361 + // 登録されているキーワードと一致するか? 362 + for( Keyword* p=backet_[hash(str,len)]; p!=NULL; p=p->next ) 363 + if( p->len==len && compare_( p->str, str, len ) ) 364 + return 2; 365 + return 0; 366 + } 367 + 368 +private: 369 + 370 + static int hash( const unicode* a, ulong al ) 371 + { 372 + // 12bitに潰すめっちゃ雑なハッシュ関数 373 + // ルーチン分けるの面倒なので、大文字小文字は常に区別されない。(^^; 374 + int h=0,i=0; 375 + while( al-- ) 376 + { 377 + h ^= ((*(a++)&0xdf)<<i); 378 + i = (i+5)&7; 379 + } 380 + return h&4095; 381 + } 382 +}; 383 + 384 + 385 + 386 +//------------------------------------------------------------------------- 387 +// 以上の道具立てでもって、テキストの解析を行うParser 388 +//------------------------------------------------------------------------- 389 +} 390 + 391 +class editwing::doc::Parser 392 +{ 393 + KeywordMap kwd_; 394 + TagMap tag_; 395 + 396 +public: 397 + // 初期化1 398 + Parser( 399 + const unicode* cb, ulong cblen, 400 + const unicode* ce, ulong celen, 401 + const unicode* lb, ulong lblen, 402 + bool q1, bool q2, bool esc, 403 + bool casesensitive 404 + ) 405 + : tag_( cb, cblen, ce, celen, lb, lblen, q1, q2, esc ) 406 + , kwd_( casesensitive ) 407 + { 408 + } 409 + 410 + // 初期化2:キーワード追加 411 + void AddKeyword( const unicode* str, ulong len ) 412 + { 413 + kwd_.AddKeyword( str, len ); 414 + } 415 + 416 + // 行データ解析 417 + uchar Parse( Line& line, uchar cmst ) 418 + { 419 + line.TransitCmt( cmst ); 420 + 421 + // ASCII振り分けテーブル。 422 + // シフト無しでTokenTypeに流用出来るようにするため、 423 + // 値が4飛びになってます 424 + enum { T=0, W=4, A=8, S=12, O=0 }; 425 + static const uchar letter_type[128] = { 426 + O,O,O,O,O,O,O,O,O,T,O,O,O,O,O,O, 427 + O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O, 428 + W,S,S,S,S,S,S,S,S,S,S,S,S,S,S,S, 429 + A,A,A,A,A,A,A,A,A,A,S,S,S,S,S,S, 430 + S,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A, 431 + A,A,A,A,A,A,A,A,A,A,A,S,S,S,S,A, 432 + S,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A, 433 + A,A,A,A,A,A,A,A,A,A,A,S,S,S,S,O, 434 + }; 435 + 436 + // PosInToken算出用の距離エンコーダ( 5bitシフト済み ) 437 + // ( _d>7 ? 7<<5 : _d<<5 ) 438 + #define tkenc(_d) ( (_d)>7 ? 0xe0 : (_d)<<5 ) 439 + 440 + // コメント状態遷移追跡用オートマトン 441 + CommentDFA dfa[2] = {CommentDFA(false), CommentDFA(true)}; 442 + int& cmtState = dfa[line.isLineHeadCmt()].state; 443 + int commentbit = cmtState&1; 444 + 445 + // 作業領域 446 + int sym; 447 + ulong j, k, um, m; 448 + uchar t, f; 449 + 450 + // ループ〜 451 + const unicode* str = line.str(); 452 + uchar* flg = line.flg(); 453 + ulong ie = line.size(); 454 + for( ulong i=0; i<ie; i=j ) 455 + { 456 + j = i; 457 + 458 + // ASCII文字でない場合 459 + if( str[i] >= 0x007f ) 460 + { 461 + f = (ALP | commentbit); 462 + if( str[i] == 0x3000 )//L' ' ) 463 + while( str[++j] == 0x3000 ) 464 + flg[j] = f; 465 + else 466 + while( str[++j] >= 0x80 && str[j]!=0x3000 ) 467 + flg[j] = f; 468 + flg[i] = static_cast<uchar>(tkenc(j-i) | f); 469 + } 470 + // ASCII文字の場合?? 471 + else 472 + { 473 + t = letter_type[str[i]]; 474 + if( t==S && tag_.does_esc() ) 475 + do 476 + if( j+1<ie && str[j]==L'\\' ) 477 + j++; 478 + while( str[++j]<0x7f && S==letter_type[str[j]] ); 479 + else 480 + while( str[++j]<0x7f && t==letter_type[str[j]] ); 481 + 482 + f = (t | commentbit); 483 + 484 + switch( t ) 485 + { 486 + // アルファベット&数字 487 + case A: 488 + f |= kwd_.isKeyword( str+i, j-i ); 489 + // fall... 490 + 491 + // タブ・制御文字 492 + case T: 493 + // fall... 494 + 495 + // 半角空白 496 + case W: 497 + for( k=i+1; k<j; ++k ) 498 + flg[k] = f; 499 + flg[i] = (uchar)(tkenc(j-i)|f); 500 + break; 501 + 502 + // 記号 503 + case S: 504 + k = i; 505 + while( k < j ) 506 + { 507 + // マッチしなかった部分 508 + um = tag_.SymbolLoop( str+k, j-k, m, sym ); 509 + f = (0x20 | ALP | commentbit); 510 + while( um-- ) 511 + flg[k++] = f; 512 + if( k >= j ) 513 + break; 514 + 515 + // マッチした部分 516 + f = (CE | commentbit); 517 + dfa[0].transit( sym ); 518 + dfa[1].transit( sym ); 519 + commentbit = cmtState&1; 520 + if( sym != 0 ) // 0:comment end 521 + f = (((sym+3)<<2) | commentbit); 522 + flg[k++] = (uchar)(tkenc(m)|f); 523 + while( --m ) 524 + flg[k++] = f; 525 + } 526 + break; 527 + } 528 + } 529 + } 530 + 531 + // transitフラグ更新 532 + line.SetTransitFlag( 533 + (dfa[1].state & (dfa[1].state<<1)) | 534 + ((dfa[0].state>>1) & dfa[0].state) 535 + ); 536 + line.CommentBitUpdated(); 537 + return line.TransitCmt( cmst ); 538 + } 539 + 540 + // コメントビットを正しく調整 541 + void SetCommentBit( Line& line ) 542 + { 543 + CommentDFA dfa( line.isLineHeadCmt()==1 ); 544 + ulong commentbit = dfa.state&1; 545 + 546 + // ループ〜 547 + const unicode* str = line.str(); 548 + uchar* flg = line.flg(); 549 + ulong j,k,ie = line.size(); 550 + for( ulong i=0; i<ie; i=j ) 551 + { 552 + // Tokenの終端を得る 553 + k = (flg[i]>>5); 554 + j = i + k; 555 + if( j >= ie ) 556 + j = ie; 557 + else if( k==7 ) // || k==0 ) 558 + while( (flg[j]>>5)==0 && j<ie ) 559 + ++j; 560 + 561 + k = (flg[i] & 0x1c); 562 + if( k <= CE ) 563 + { 564 + for( ; i<j; ++i ) 565 + flg[i] = (uchar)((flg[i] & 0xfe) | commentbit); 566 + } 567 + if( k >= CE ) 568 + { 569 + dfa.transit( (k>>2)-3 ); 570 + commentbit = dfa.state&1; 571 + if( k != CE ) 572 + for( ; i<j; ++i ) 573 + flg[i] = (uchar)((flg[i] & 0xfe) | commentbit); 574 + } 575 + } 576 + 577 + line.CommentBitUpdated(); 578 + } 579 +}; 580 + 581 + 582 + 583 +//------------------------------------------------------------------------- 584 +// 定義ファイル読みとり処理とか 585 +//------------------------------------------------------------------------- 586 + 587 +DocImpl::DocImpl( Document& theDoc ) 588 + : doc_ ( theDoc ) 589 + , pEvHan_ ( 2 ) 590 +{ 591 + text_.Add( new Line(L"",0) ); // 最初は一行だけ 592 + SetKeyword( NULL, 0 ); // キーワード無し 593 +} 594 + 595 +DocImpl::~DocImpl() 596 +{ 597 + // このファイルにデストラクタを入れておかないと、 598 + // delete parser_ が出来なくなる。^^; 599 +} 600 + 601 +void DocImpl::SetKeyword( const unicode* defbuf, ulong siz ) 602 +{ 603 + // BOMがあったらスキップ 604 + if( siz!=0 && *defbuf==0xfeff ) 605 + ++defbuf, --siz; 606 + 607 + // 読み込み準備 608 + const unicode* str; 609 + ulong len; 610 + UniReader r( defbuf, siz, &str, &len ); 611 + bool flags[] = {false,false,false,false}; 612 + const unicode* tags[] = {NULL,NULL,NULL}; 613 + ulong taglen[] = {0,0,0}; 614 + 615 + if( siz != 0 ) 616 + { 617 + // 1行目:フラグ 618 + // case? q1? q2? esc? 619 + r.getLine(); 620 + for( ulong i=0; i<len; ++i ) 621 + flags[i] = (str[i]==L'1'); 622 + 623 + // 2〜4行目 624 + // ブロコメ開始記号、ブロコメ終了記号、行コメ記号 625 + for( int j=0; j<3; ++j ) 626 + { 627 + r.getLine(); 628 + tags[j] = str; 629 + taglen[j] = len; 630 + } 631 + } 632 + 633 + // パーサー作成 634 + aptr<Parser> np( new Parser( 635 + tags[0], taglen[0], tags[1], taglen[1], tags[2], taglen[2], 636 + flags[1], flags[2], flags[3], flags[0] ) ); 637 + parser_ = np; 638 + 639 + // 5行目以降:キーワードリスト 640 + while( !r.isEmpty() ) 641 + { 642 + r.getLine(); 643 + if( len != 0 ) 644 + parser_->AddKeyword( str, len ); 645 + } 646 + 647 + // 全行解析し直し 648 + ReParse( 0, tln()-1 ); 649 + 650 + // 変更通知 651 + Fire_KEYWORDCHANGE(); 652 +} 653 + 654 +bool DocImpl::ReParse( ulong s, ulong e ) 655 +{ 656 + ulong i; 657 + uchar cmt = text_[s].isLineHeadCmt(); 658 + 659 + // まずは変更範囲を再解析 660 + for( i=s; i<=e; ++i ) 661 + cmt = parser_->Parse( text_[i], cmt ); 662 + 663 + // コメントアウト状態に変化がなかったらここでお終い。 664 + if( i==tln() || text_[i].isLineHeadCmt()==cmt ) 665 + return false; 666 + 667 + // 例えば、/* が入力された場合などは、下の方の行まで 668 + // コメントアウト状態の変化を伝達する必要がある。 669 + do 670 + cmt = text_[i++].TransitCmt( cmt ); 671 + while( i<tln() && text_[i].isLineHeadCmt()!=cmt ); 672 + return true; 673 +} 674 + 675 +void DocImpl::SetCommentBit( const Line& x ) const 676 +{ 677 + parser_->SetCommentBit( const_cast<Line&>(x) ); 678 +}
Added editwing/ip_scroll.cpp version [a2aa2ab09e9c8e83]
1 +#include "stdafx.h" 2 +#include "ip_view.h" 3 +using namespace editwing; 4 +using namespace editwing::view; 5 + 6 + 7 + 8 +//========================================================================= 9 +//---- ip_scroll.cpp スクロール 10 +// 11 +// ウインドウサイズはスクロールバーの位置によって 12 +// 描画位置を適当に更新していく処理がここ。 13 +// 14 +//---- ip_text.cpp 文字列操作・他 15 +//---- ip_parse.cpp キーワード解析 16 +//---- ip_wrap.cpp 折り返し 17 +//---- ip_draw.cpp 描画・他 18 +//---- ip_cursor.cpp カーソルコントロール 19 +//========================================================================= 20 + 21 + 22 + 23 +//------------------------------------------------------------------------- 24 +// 描画領域サイズ管理 25 +//------------------------------------------------------------------------- 26 + 27 +namespace 28 +{ 29 + static int Log10( ulong n ) 30 + { 31 + const static ulong power_of_ten[] = 32 + { 1, 10, 100, 1000, 10000, 100000, 1000000, 33 + 10000000, 100000000, 1000000000 }; // 10^0 〜 10^9 34 + int c=3; 35 + if( power_of_ten[9] <= n ) 36 + c=10; 37 + else 38 + while( power_of_ten[c] <= n ) 39 + c++; 40 + return c; // 3<=c<=10 s.t. 10^(c-1) <= n < 10^c 41 + } 42 +} 43 + 44 +bool Canvas::CalcLNAreaWidth() 45 +{ 46 + const int prev = txtZone_.left; 47 + if( showLN_ ) 48 + { 49 + txtZone_.left = (1 + figNum_) * font_->F(); 50 + if( txtZone_.left+font_->W() >= txtZone_.right ) 51 + txtZone_.left = 0; // 行番号ゾーンがデカすぎるときは表示しない 52 + } 53 + else 54 + { 55 + txtZone_.left = 0; 56 + } 57 + 58 + return (prev != txtZone_.left); 59 +} 60 + 61 +void Canvas::CalcWrapWidth() 62 +{ 63 + switch( wrapType_ ) 64 + { 65 + case NOWRAP: 66 + wrapWidth_ = 0xffffffff; 67 + break; 68 + case RIGHTEDGE: 69 + wrapWidth_ = txtZone_.right - txtZone_.left - 3; 70 + break; //Caretの分-3補正 71 + default: 72 + wrapWidth_ = wrapType_ * font_->W(); 73 + break; 74 + } 75 +} 76 + 77 +Canvas::Canvas( const View& vw ) 78 + : wrapType_ ( -1 ) 79 + , showLN_ ( false ) 80 + , wrapWidth_( 0xffffffff ) 81 + , figNum_ ( 3 ) 82 + , font_ ( new Painter( ::GetDC(vw.hwnd()), 83 + VConfig(TEXT("FixedSys"),14) ) ) 84 +{ 85 + vw.getClientRect( &txtZone_ ); 86 +} 87 + 88 +bool Canvas::on_view_resize( int cx, int cy ) 89 +{ 90 + txtZone_.right = cx; 91 + txtZone_.bottom = cy; 92 + 93 + CalcLNAreaWidth(); 94 + if( wrapType_ == RIGHTEDGE ) 95 + { 96 + CalcWrapWidth(); 97 + return true; 98 + } 99 + return false; 100 +} 101 + 102 +void Canvas::on_font_change( const VConfig& vc ) 103 +{ 104 + HDC dc = font_->getDC(); 105 + font_ = NULL; // 先にデストラクタを呼ばねばならない… 106 + // ってうわー格好悪ぃーーー(T_T) 107 + font_ = new Painter( dc, vc ); 108 + 109 + CalcLNAreaWidth(); 110 + CalcWrapWidth(); 111 +} 112 + 113 +void Canvas::on_config_change( int wrap, bool showln ) 114 +{ 115 + showLN_ = showln; 116 + wrapType_ = wrap; 117 + 118 + CalcLNAreaWidth(); 119 + CalcWrapWidth(); 120 +} 121 + 122 +bool Canvas::on_tln_change( ulong tln ) 123 +{ 124 + figNum_ = Log10( tln ); // 桁数計算 125 + 126 + if( CalcLNAreaWidth() ) 127 + { 128 + if( wrapType_ == RIGHTEDGE ) 129 + CalcWrapWidth(); 130 + return true; 131 + } 132 + return false; 133 +} 134 + 135 + 136 + 137 +//------------------------------------------------------------------------- 138 +// スクロールバー計算ルーチン 139 +//------------------------------------------------------------------------- 140 +// rl (横スクロール情報) 141 +// max: view.txt.txtwidth() 142 +// page: view.cx() 143 +// pos: 0〜max-page 144 + 145 +// ud (縦スクロール情報) 146 +// max: view.txt.vln() + page - 1 147 +// page: view.cy() / view.fnt.H() 148 +// delta: 0〜view.fnt.H() 149 +// pos: 0〜max-page (topの行番号) 150 + 151 +bool ViewImpl::ReSetScrollInfo() 152 +{ 153 + const int prevRlPos = rlScr_.nPos; 154 + const ulong cx = cvs_.zone().right - cvs_.zone().left; 155 + const ulong cy = cvs_.zone().bottom; 156 + 157 + // 横は変な値にならないよう補正するだけでよい 158 +// rlScr_.nPage = cx + 1; 159 +// rlScr_.nMax = Max( textCx_, cx ); 160 +// rlScr_.nPos = Min<int>( rlScr_.nPos, rlScr_.nMax-rlScr_.nPage+1 ); 161 + rlScr_.nPage = cx + 1; 162 + rlScr_.nMax = Max( textCx_+3, cx ); 163 + rlScr_.nPos = Min<int>( rlScr_.nPos, rlScr_.nMax-rlScr_.nPage+1 ); 164 + 165 + // 縦はnPageとnMaxはとりあえず補正 166 + // nPosは場合によって直し方が異なるので別ルーチンにて 167 + udScr_.nPage = cy / cvs_.getPainter().H() + 1; 168 + udScr_.nMax = vln() + udScr_.nPage - 2; 169 + 170 + // 横スクロールが起きたらtrue 171 + return (prevRlPos != rlScr_.nPos); 172 +} 173 + 174 +void ViewImpl::ForceScrollTo( ulong tl ) 175 +{ 176 + udScr_.nPos = tl2vl(tl); 177 + udScr_tl_ = tl; 178 + udScr_vrl_ = 0; 179 +} 180 + 181 +ulong ViewImpl::tl2vl( ulong tl ) const 182 +{ 183 + if( vln() == doc_.tln() ) 184 + return tl; 185 + 186 + ulong vl=0; 187 + for( ulong i=0; i<tl; ++i ) 188 + vl += rln(i); 189 + return vl; 190 +} 191 + 192 +void ViewImpl::UpdateScrollBar() 193 +{ 194 + ::SetScrollInfo( hwnd_, SB_HORZ, &rlScr_, TRUE ); 195 + ::SetScrollInfo( hwnd_, SB_VERT, &udScr_, TRUE ); 196 +} 197 + 198 +ReDrawType ViewImpl::TextUpdate_ScrollBar 199 + ( const DPos& s, const DPos& e, const DPos& e2 ) 200 +{ 201 + const ulong prevUdMax = udScr_.nMax; 202 + const bool rlScrolled = ReSetScrollInfo(); 203 + const long vl_dif = (udScr_.nMax - prevUdMax); 204 + ReDrawType ans = 205 + (vl_dif!=0 || s.tl!=e2.tl ? AFTER : LINE); 206 + 207 + if( udScr_tl_ < s.tl ) 208 + { 209 + // パターン1:現在の画面上端より下で更新された場合 210 + // スクロールしない 211 + } 212 + else if( udScr_tl_ == s.tl ) 213 + { 214 + // パターン2:現在の画面上端と同じ行で更新された場合 215 + // 出来るだけ同じ位置を表示し続けようと試みる。 216 + 217 + if( static_cast<ulong>(udScr_.nPos) >= vln() ) 218 + { 219 + // パターン2-1:しかしそこはすでにEOFよりも下だ! 220 + // しゃーないので一番下の行を表示 221 + udScr_.nPos = vln()-1; 222 + udScr_tl_ = doc_.tln()-1; 223 + udScr_vrl_ = rln(udScr_tl_)-1; 224 + ans = ALL; 225 + } 226 + else 227 + { 228 + // パターン2-2: 229 + // スクロール無し 230 + while( udScr_vrl_ >= rln(udScr_tl_) ) 231 + { 232 + udScr_vrl_ -= rln(udScr_tl_); 233 + udScr_tl_++; 234 + } 235 + } 236 + } 237 + else 238 + { 239 + // パターン3:現在の画面上端より上で更新された場合 240 + // 表示内容を変えないように頑張る 241 + 242 + if( e.tl < udScr_tl_ ) 243 + { 244 + // パターン3-1:変更範囲の終端も、現在行より上の場合 245 + // 行番号は変わるが表示内容は変わらないで済む 246 + udScr_.nPos += vl_dif; 247 + udScr_tl_ += (e2.tl - e.tl); 248 + ans = LNAREA; 249 + } 250 + else 251 + { 252 + // パターン3-2: 253 + // どうしよーもないので適当な位置にスクロール 254 + ForceScrollTo( e2.tl ); 255 + ans = ALL; 256 + } 257 + } 258 + 259 + // どんな再描画をすればよいか返す 260 + return (rlScrolled ? ALL : ans); 261 +} 262 + 263 +void ViewImpl::ScrollTo( const VPos& vp ) 264 +{ 265 + // 横フォーカス 266 + int dx=0; 267 + if( vp.vx < (signed)rlScr_.nPos ) 268 + { 269 + dx = vp.vx - rlScr_.nPos; 270 + } 271 + else 272 + { 273 + const int W = cvs_.getPainter().W(); 274 + if( rlScr_.nPos + (signed)(rlScr_.nPage-W) <= vp.vx ) 275 + dx = vp.vx - (rlScr_.nPos + rlScr_.nPage) + W; 276 + } 277 + 278 + // 縦フォーカス 279 + int dy=0; 280 + if( vp.vl < (unsigned)udScr_.nPos ) 281 + dy = vp.vl - udScr_.nPos; 282 + else if( udScr_.nPos + (udScr_.nPage-1) <= vp.vl ) 283 + dy = vp.vl - (udScr_.nPos + udScr_.nPage) + 2; 284 + 285 + // スクロール 286 + if( dy!=0 ) UpDown( dy, dx==0 ); 287 + if( dx!=0 ) ScrollView( dx, 0, true ); 288 +} 289 + 290 +void ViewImpl::GetDrawPosInfo( VDrawInfo& v ) const 291 +{ 292 + const int H = cvs_.getPainter().H(); 293 + 294 + long most_under = (vln()-udScr_.nPos)*H; 295 + if( most_under <= v.rc.top ) 296 + { 297 + v.YMIN = v.rc.top; 298 + v.YMAX = most_under; 299 + } 300 + else 301 + { 302 + int y = -(signed)udScr_vrl_; 303 + ulong tl = udScr_tl_; 304 + int top = v.rc.top / H; 305 + while( y + (signed)rln(tl) <= top ) 306 + y += rln( tl++ ); 307 + 308 + // 縦座標 309 + v.YMIN = y * H; 310 + v.YMAX = Min( v.rc.bottom, most_under ); 311 + v.TLMIN = tl; 312 + 313 + // 横座標 314 + v.XBASE = left() - rlScr_.nPos; 315 + v.XMIN = v.rc.left - v.XBASE; 316 + v.XMAX = v.rc.right - v.XBASE; 317 + 318 + // 選択範囲 319 + v.SXB = v.SXE = v.SYB = v.SYE = 0x7fffffff; 320 + 321 + const VPos *bg, *ed; 322 + if( cur_.getCurPos( &bg, &ed ) ) 323 + { 324 + v.SXB = bg->vx - rlScr_.nPos + left(); 325 + v.SXE = ed->vx - rlScr_.nPos + left(); 326 + v.SYB = (bg->vl - udScr_.nPos) * H; 327 + v.SYE = (ed->vl - udScr_.nPos) * H; 328 + } 329 + } 330 +} 331 + 332 +void ViewImpl::ScrollView( int dx, int dy, bool update ) 333 +{ 334 + // スクロール開始通知 335 + cur_.on_scroll_begin(); 336 + 337 + const RECT* clip = (dy==0 ? &cvs_.zone() : NULL); 338 + const int H = cvs_.getPainter().H(); 339 + 340 + // スクロールバー更新 341 + if( dx != 0 ) 342 + { 343 + // 範囲チェック 344 + if( rlScr_.nPos+dx < 0 ) 345 + dx = -rlScr_.nPos; 346 + else if( rlScr_.nMax-(signed)rlScr_.nPage < rlScr_.nPos+dx ) 347 + dx = rlScr_.nMax-rlScr_.nPage-rlScr_.nPos+1; 348 + 349 + rlScr_.nPos += dx; 350 + ::SetScrollInfo( hwnd_, SB_HORZ, &rlScr_, TRUE ); 351 + dx = -dx; 352 + } 353 + if( dy != 0 ) 354 + { 355 + // 範囲チェック…は前処理で終わってる。 356 + 357 + udScr_.nPos += dy; 358 + ::SetScrollInfo( hwnd_, SB_VERT, &udScr_, TRUE ); 359 + dy *= -H; 360 + } 361 + if( dx!=0 || dy!=0 ) 362 + { 363 + if( -dx>=right() || dx>=right() 364 + || -dy>=bottom() || dy>=bottom() ) 365 + { 366 + // 全画面再描画 367 + // ちょうど65536の倍数くらいスクロールしたときに、 368 + // ScrollWindowEx on Win9x だと再描画が変なのを回避。 369 + ::InvalidateRect( hwnd_, NULL, FALSE ); 370 + } 371 + else 372 + { 373 + // 再描画の不要な領域をスクロール 374 + ::ScrollWindowEx( hwnd_, dx, dy, NULL, 375 + clip, NULL, NULL, SW_INVALIDATE ); 376 + 377 + // 即時再描画? 378 + if( update ) 379 + { 380 + // 縦スクロールは高速化したいので一工夫 381 + if( dy != 0 ) 382 + { 383 + // 再描画の必要な領域を自分で計算 384 + RECT rc = {0,0,right(),bottom()}; 385 + if( dy < 0 ) rc.top = rc.bottom + dy; 386 + else rc.bottom = dy; 387 + 388 + // インテリマウスの中ボタンクリックによる 389 + // オートスクロール用カーソルの下の部分を先に描く 390 + // 2回に分けることで、小さな矩形部分二つで済むので高速 391 + ::ValidateRect( hwnd_, &rc ); 392 + ::UpdateWindow( hwnd_ ); 393 + ::InvalidateRect( hwnd_, &rc, FALSE ); 394 + } 395 + ::UpdateWindow( hwnd_ ); 396 + } 397 + } 398 + } 399 + 400 + // スクロール終了通知 401 + cur_.on_scroll_end(); 402 +} 403 + 404 +void ViewImpl::on_hscroll( int code ) 405 +{ 406 + // 変化量を計算 407 + int dx; 408 + switch( code ) 409 + { 410 + default: return; 411 + case SB_LINELEFT: dx= -cvs_.getPainter().W(); break; 412 + case SB_LINERIGHT: dx= +cvs_.getPainter().W(); break; 413 + case SB_PAGELEFT: dx= -(cx()>>1); break; 414 + case SB_PAGERIGHT: dx= +(cx()>>1); break; 415 + case SB_THUMBTRACK: 416 + { 417 + SCROLLINFO si = { sizeof(SCROLLINFO), SIF_TRACKPOS }; 418 + ::GetScrollInfo( hwnd_, SB_HORZ, &si ); 419 + dx = si.nTrackPos - rlScr_.nPos; 420 + break; 421 + } 422 + case SB_LEFT: dx = -rlScr_.nPos; break; 423 + case SB_RIGHT: dx = rlScr_.nMax+1-(signed)rlScr_.nPage-rlScr_.nPos; break; 424 + } 425 + 426 + // スクロール 427 + ScrollView( dx, 0, code!=SB_THUMBTRACK ); 428 +} 429 + 430 +void ViewImpl::on_vscroll( int code ) 431 +{ 432 + // 変化量を計算 433 + int dy; 434 + switch( code ) 435 + { 436 + default: return; 437 + case SB_LINEUP: dy= -1; break; 438 + case SB_LINEDOWN: dy= +1; break; 439 + case SB_PAGEUP: dy= -(cy() / cvs_.getPainter().H()); break; 440 + case SB_PAGEDOWN: dy= +(cy() / cvs_.getPainter().H()); break; 441 + case SB_THUMBTRACK: 442 + { 443 + SCROLLINFO si = { sizeof(SCROLLINFO), SIF_TRACKPOS }; 444 + ::GetScrollInfo( hwnd_, SB_VERT, &si ); 445 + dy = si.nTrackPos - udScr_.nPos; 446 + break; 447 + } 448 + case SB_TOP: dy = -udScr_.nPos; break; 449 + case SB_BOTTOM: dy = udScr_.nMax+1-(signed)udScr_.nPage-udScr_.nPos; break; 450 + } 451 + 452 + // スクロール 453 + UpDown( dy, code==SB_THUMBTRACK ); 454 +} 455 + 456 +void ViewImpl::on_wheel( short delta ) 457 +{ 458 + // スクロール 459 + UpDown( -delta / WHEEL_DELTA * 3, false ); 460 +} 461 + 462 +void ViewImpl::UpDown( int dy, bool thumb ) 463 +{ 464 + // 1.udScr_.nPos + dy が正常範囲に収まるように補正 465 + if( udScr_.nPos+dy < 0 ) 466 + dy = -udScr_.nPos; 467 + else if( udScr_.nMax+1-(signed)udScr_.nPage < udScr_.nPos+dy ) 468 + dy = udScr_.nMax+1-udScr_.nPage-udScr_.nPos; 469 + if( dy==0 ) 470 + return; 471 + 472 + // 2−1.折り返し無しの場合は一気にジャンプ出来る 473 + if( !wrapexists() ) 474 + { 475 + udScr_tl_ = udScr_.nPos + dy; 476 + } 477 + 478 + // 2−2.でなけりゃ、現在位置からの相対サーチ 479 + // ScrollBarを連続的にドラッグせず一度に一気に飛んだ場合は 480 + // 1行目や最終行からの相対サーチの方が有効な可能性があるが、 481 + // その場合は多少速度が遅くなっても描画が引っかかることはないのでOK 482 + else 483 + { 484 + int rl = dy + udScr_vrl_; 485 + ulong tl = udScr_tl_; 486 + 487 + if( dy<0 ) // 上へ戻る場合 488 + { 489 + // ジャンプ先論理行の行頭へDash! 490 + while( rl < 0 ) 491 + rl += rln(--tl); 492 + } 493 + else if( dy>0 ) // 下へ進む場合 494 + { 495 + // ジャンプ先論理行の行頭へDash! 496 + while( rl > 0 ) 497 + rl -= rln(tl++); 498 + if( rl < 0 ) 499 + rl += rln(--tl); //行き過ぎ修正 500 + } 501 + udScr_tl_ = tl; 502 + udScr_vrl_= static_cast<ulong>(rl); 503 + } 504 + 505 + // 4.画面をスクロール 506 + ScrollView( 0, dy, !thumb ); 507 +} 508 + 509 +void ViewImpl::InvalidateView( const DPos& dp, bool afterall ) const 510 +{ 511 + const int H = cvs_.getPainter().H(); 512 + 513 + // 表示域より上での更新 514 + if( dp.tl < udScr_tl_ ) 515 + { 516 + if( afterall ) 517 + ::InvalidateRect( hwnd_, NULL, FALSE ); 518 + return; 519 + } 520 + 521 + // 開始y座標計算 522 + int r=0, yb=-(signed)udScr_vrl_; 523 + for( int t=udScr_tl_, ybe=cy()/H; (unsigned)t<dp.tl; yb+=rln(t++) ) 524 + if( yb >= ybe ) 525 + return; 526 + for( ; dp.ad>rlend(dp.tl,r); ++r,++yb ); 527 + yb = H * Max( yb, -100 ); // 上にはみ出し過ぎないよう調整 528 + if( yb >= cy() ) 529 + return; 530 + 531 + // 1行目を再描画 532 + int rb = (r==0 ? 0 : rlend(dp.tl,r-1)); 533 + int xb = left() + Max( 0UL, 534 + CalcLineWidth(doc_.tl(dp.tl)+rb,dp.ad-rb) -rlScr_.nPos ); 535 + if( xb < right() ) 536 + { 537 + RECT rc={xb,yb,right(),yb+H}; 538 + ::InvalidateRect( hwnd_, &rc, FALSE ); 539 + } 540 + 541 + // 残り 542 + int ye; 543 + yb += H; 544 + if( afterall ) 545 + xb=0, ye=cy(); 546 + else 547 + xb=left(), ye=Min(cy(),yb+(int)(H*(rln(dp.tl)-r-1))); 548 + if( yb < ye ) 549 + { 550 + RECT rc={xb,yb,right(),ye}; 551 + ::InvalidateRect( hwnd_, &rc, FALSE ); 552 + } 553 +}
Added editwing/ip_text.cpp version [0cf9b5928d0aca8a]
1 +#include "stdafx.h" 2 +#include "ip_doc.h" 3 +using namespace editwing; 4 +using namespace editwing::doc; 5 + 6 + 7 + 8 +//========================================================================= 9 +//---- ip_text.cpp 文字列操作・他 10 +// 11 +// 文字列を挿入したり削除したり…という辺りの処理が 12 +// このファイルにまとめてある。外向けのインターフェイスの 13 +// 実装もついでにここで。 14 +// 15 +//---- ip_parse.cpp キーワード解析 16 +//---- ip_wrap.cpp 折り返し 17 +//---- ip_scroll.cpp スクロール 18 +//---- ip_draw.cpp 描画・他 19 +//---- ip_cursor.cpp カーソルコントロール 20 +//========================================================================= 21 + 22 + 23 + 24 +//------------------------------------------------------------------------- 25 +// 公開インターフェイス 26 +//------------------------------------------------------------------------- 27 + 28 +Document::Document() : busy_(false) 29 + { impl_ = new DocImpl( *this ); } 30 + 31 +Document::~Document() 32 + {} 33 + 34 +void Document::Execute( const Command& c ) 35 + { impl_->Execute( c ); } 36 + 37 +void Document::SetKeyword( const unicode* b, ulong s ) 38 + { impl_->SetKeyword( b, s ); } 39 + 40 +void Document::AddHandler( DocEvHandler* h ) 41 + { impl_->AddHandler( h ); } 42 + 43 +void Document::DelHandler( DocEvHandler* h ) 44 + { impl_->DelHandler( h ); } 45 + 46 +void Document::OpenFile( aptr<TextFileR> t ) 47 + { impl_->OpenFile( t ); } 48 + 49 +void Document::SaveFile( TextFileW& t ) 50 + { impl_->SaveFile( t ); } 51 + 52 +void Document::ClearAll() 53 + { impl_->ClearAll(); } 54 + 55 +ulong Document::tln() const 56 + { return impl_->tln(); } 57 + 58 +const unicode* Document::tl( ulong i ) const 59 + { return impl_->tl( i ); } 60 + 61 +ulong Document::len( ulong i ) const 62 + { return impl_->len( i ); } 63 + 64 +ulong Document::getRangeLength( const DPos& s, const DPos& e ) const 65 + { return impl_->getRangeLength( s, e ); } 66 + 67 +void Document::getText( unicode* b, const DPos& s, const DPos& e ) const 68 + { impl_->getText( b, s, e ); } 69 + 70 +bool Document::isUndoAble() const 71 + { return impl_->isUndoAble(); } 72 + 73 +bool Document::isRedoAble() const 74 + { return impl_->isRedoAble(); } 75 + 76 +bool Document::isModified() const 77 + { return impl_->isModified(); } 78 + 79 +void Document::ClearModifyFlag() 80 + { impl_->ClearModifyFlag(); } 81 + 82 +void Document::Undo() 83 + { impl_->Undo(); } 84 + 85 +void Document::Redo() 86 + { impl_->Redo(); } 87 + 88 +void Document::SetUndoLimit( long lim ) 89 + { impl_->SetUndoLimit( lim ); } 90 + 91 + 92 + 93 +//------------------------------------------------------------------------- 94 +// イベントハンドラ処理 95 +//------------------------------------------------------------------------- 96 + 97 +void DocImpl::AddHandler( DocEvHandler* eh ) 98 +{ 99 + // ハンドラ追加 100 + pEvHan_.Add( eh ); 101 +} 102 + 103 +void DocImpl::DelHandler( DocEvHandler* eh ) 104 +{ 105 + // 後ろから見て行って… 106 + const int last = pEvHan_.size() - 1; 107 + 108 + // …見つけたら削除 109 + for( int i=last; i>=0; --i ) 110 + if( pEvHan_[i] == eh ) 111 + { 112 + pEvHan_[i] = pEvHan_[last]; 113 + pEvHan_.ForceSize( last ); 114 + break; 115 + } 116 +} 117 + 118 +void DocImpl::Fire_TEXTUPDATE 119 + ( const DPos& s, const DPos& e, const DPos& e2, bool reparsed, bool nmlcmd ) 120 +{ 121 + AutoLock lk(this); 122 + 123 + // 全部にイベント通知 124 + for( ulong i=0, ie=pEvHan_.size(); i<ie; ++i ) 125 + pEvHan_[i]->on_text_update( s, e, e2, reparsed, nmlcmd ); 126 +} 127 + 128 +void DocImpl::Fire_KEYWORDCHANGE() 129 +{ 130 + AutoLock lk(this); 131 + 132 + // 全部にイベント通知 133 + for( ulong i=0, ie=pEvHan_.size(); i<ie; ++i ) 134 + pEvHan_[i]->on_keyword_change(); 135 +} 136 + 137 +void DocImpl::Fire_MODIFYFLAGCHANGE() 138 +{ 139 + AutoLock lk(this); 140 + 141 + // 全部にイベント通知 142 + bool b = urdo_.isModified(); 143 + for( ulong i=0, ie=pEvHan_.size(); i<ie; ++i ) 144 + pEvHan_[i]->on_dirtyflag_change( b ); 145 +} 146 + 147 + 148 + 149 +//------------------------------------------------------------------------- 150 +// UnDo,ReDo 処理 151 +//------------------------------------------------------------------------- 152 + 153 +UnReDoChain::Node::Node( Command* c, Node* p, Node* n ) 154 + : cmd_ ( c ) 155 + , prev_( p ) 156 + , next_( n ) 157 +{ 158 +} 159 + 160 +UnReDoChain::Node::Node() 161 +{ 162 + next_ = prev_ = this; 163 + cmd_ = NULL; 164 +} 165 + 166 +UnReDoChain::Node::~Node() 167 +{ 168 + delete cmd_; 169 +} 170 + 171 +void UnReDoChain::Node::ResetCommand( Command* cmd ) 172 +{ 173 + delete cmd_; 174 + cmd_ = cmd; 175 +} 176 + 177 +UnReDoChain::UnReDoChain() 178 + : lastOp_ ( &headTail_ ) 179 + , savedPos_( &headTail_ ) 180 + , num_ ( 0 ) 181 + , limit_ ( static_cast<ulong>(-1) ) 182 +{ 183 +} 184 + 185 +UnReDoChain::~UnReDoChain() 186 +{ 187 + Clear(); 188 +} 189 + 190 +ulong UnReDoChain::Node::ChainDelete(Node*& savedPos_ref) 191 +{ 192 + if( cmd_ == NULL ) 193 + return 0; 194 + if( savedPos_ref == this ) 195 + savedPos_ref = NULL; 196 + dptr<Node> d(this); 197 + return 1 + next_->ChainDelete(savedPos_ref); 198 +} 199 + 200 +void UnReDoChain::Clear() 201 +{ 202 + headTail_.next_->ChainDelete(savedPos_); 203 + headTail_.next_ = headTail_.prev_ = lastOp_ = savedPos_ = &headTail_; 204 + num_ = 0; 205 +} 206 + 207 +void UnReDoChain::SetLimit( long lim ) 208 +{ 209 + limit_ = Max( 1UL, ulong(lim) ); 210 +} 211 + 212 +inline void UnReDoChain::Undo( Document& doc ) 213 +{ 214 + lastOp_->ResetCommand( (*lastOp_->cmd_)(doc) ); 215 + lastOp_ = lastOp_->prev_; 216 +} 217 + 218 +inline void UnReDoChain::Redo( Document& doc ) 219 +{ 220 + lastOp_ = lastOp_->next_; 221 + lastOp_->ResetCommand( (*lastOp_->cmd_)(doc) ); 222 +} 223 + 224 +void UnReDoChain::NewlyExec( const Command& cmd, Document& doc ) 225 +{ 226 + Command* nCmd = cmd(doc); 227 + if( nCmd != NULL ) 228 + { 229 + num_ -= (lastOp_->next_->ChainDelete(savedPos_) - 1); 230 + lastOp_ = lastOp_->next_ = new Node(nCmd,lastOp_,&headTail_); 231 + 232 + while( limit_ < num_ ) 233 + { 234 + // 回数制限を越えたので、古い物を削除 235 + Node* old = headTail_.next_; 236 + headTail_.next_ = old->next_; 237 + old->next_->prev_ = &headTail_; 238 + if( old != &headTail_ ) 239 + delete old; 240 + if( savedPos_ == &headTail_ ) 241 + savedPos_ = NULL; 242 + else if( savedPos_ == old ) 243 + savedPos_ = &headTail_; 244 + --num_; 245 + } 246 + } 247 +} 248 + 249 + 250 + 251 +bool DocImpl::isUndoAble() const 252 + { return urdo_.isUndoAble(); } 253 + 254 +bool DocImpl::isRedoAble() const 255 + { return urdo_.isRedoAble(); } 256 + 257 +bool DocImpl::isModified() const 258 + { return urdo_.isModified(); } 259 + 260 +void DocImpl::SetUndoLimit( long lim ) 261 + { urdo_.SetLimit( lim ); } 262 + 263 +void DocImpl::ClearModifyFlag() 264 +{ 265 + bool b = urdo_.isModified(); 266 + urdo_.SavedHere(); 267 + if( b != urdo_.isModified() ) 268 + Fire_MODIFYFLAGCHANGE(); 269 +} 270 + 271 +void DocImpl::Undo() 272 +{ 273 + if( urdo_.isUndoAble() ) 274 + { 275 + bool b = urdo_.isModified(); 276 + urdo_.Undo(doc_); 277 + if( b != urdo_.isModified() ) 278 + Fire_MODIFYFLAGCHANGE(); 279 + } 280 +} 281 + 282 +void DocImpl::Redo() 283 +{ 284 + if( urdo_.isRedoAble() ) 285 + { 286 + bool b = urdo_.isModified(); 287 + urdo_.Redo(doc_); 288 + if( b != urdo_.isModified() ) 289 + Fire_MODIFYFLAGCHANGE(); 290 + } 291 +} 292 + 293 +void DocImpl::Execute( const Command& cmd ) 294 +{ 295 + bool b = urdo_.isModified(); 296 + urdo_.NewlyExec( cmd, doc_ ); 297 + if( b != urdo_.isModified() ) 298 + Fire_MODIFYFLAGCHANGE(); 299 +} 300 + 301 + 302 + 303 +//------------------------------------------------------------------------- 304 +// カーソル移動ヘルパー 305 +//------------------------------------------------------------------------- 306 + 307 +DPos DocImpl::leftOf( const DPos& dp, bool wide ) const 308 +{ 309 + if( dp.ad == 0 ) 310 + { 311 + // 行の先頭だが、ファイルの先頭ではない場合 312 + // 一つ前の行の行末へ 313 + if( dp.tl > 0 ) 314 + return DPos( dp.tl-1, len(dp.tl-1) ); 315 + return dp; 316 + } 317 + else if( !wide ) 318 + { 319 + // 行の途中で、普通に1文字戻る場合 320 + const unicode* l = tl(dp.tl); 321 + if( dp.ad>=2 && isLowSurrogate(l[dp.ad-1]) && isHighSurrogate(l[dp.ad-2]) ) 322 + return DPos( dp.tl, dp.ad-2 ); 323 + return DPos( dp.tl, dp.ad-1 ); 324 + } 325 + else 326 + { 327 + // 行の途中で、1単語分戻る場合 328 + const uchar* f = pl(dp.tl); 329 + ulong s = dp.ad-1; 330 + while( (f[s]>>5)==0 && 0<=s ) 331 + --s; 332 + return DPos( dp.tl, s ); 333 + } 334 +} 335 + 336 +DPos DocImpl::rightOf( const DPos& dp, bool wide ) const 337 +{ 338 + if( dp.ad == len(dp.tl) ) 339 + { 340 + // 行末だが、ファイルの終わりではない場合 341 + // 一つ後の行の先頭へ 342 + if( dp.tl < tln()-1 ) 343 + return DPos( dp.tl+1, 0 ); 344 + return dp; 345 + } 346 + else if( !wide ) 347 + { 348 + // 行の途中で、普通に1文字進む場合 349 + const unicode* l = tl(dp.tl); 350 + // 番兵 0x007f が l の末尾にいるので長さチェックは不要 351 + if( isHighSurrogate(l[dp.ad]) && isLowSurrogate(l[dp.ad+1]) ) 352 + return DPos( dp.tl, dp.ad+2 ); 353 + return DPos( dp.tl, dp.ad+1 ); 354 + } 355 + else 356 + { 357 + // 行の途中で、普通に1単語進む場合 358 + const uchar* f = pl(dp.tl); 359 + const ulong e = len(dp.tl); 360 + ulong s = dp.ad; 361 + const ulong t = (f[s]>>5); 362 + s += t; 363 + if( s >= e ) 364 + s = e; 365 + else if( t==7 || t==0 ) 366 + while( (f[s]>>5)==0 && s<e ) 367 + ++s; 368 + return DPos( dp.tl, s ); 369 + } 370 +} 371 + 372 +DPos DocImpl::wordStartOf( const DPos& dp ) const 373 +{ 374 + if( dp.ad == 0 ) 375 + { 376 + // 行の先頭 377 + return dp; 378 + } 379 + else 380 + { 381 + // 行の途中 382 + const uchar* f = pl(dp.tl); 383 + ulong s = dp.ad; 384 + while( (f[s]>>5)==0 && 0<=s ) 385 + --s; 386 + return DPos( dp.tl, s ); 387 + } 388 +} 389 + 390 + 391 + 392 +//------------------------------------------------------------------------- 393 +// 挿入・削除等の作業用関数群 394 +//------------------------------------------------------------------------- 395 + 396 +ulong DocImpl::getRangeLength( const DPos& s, const DPos& e ) 397 +{ 398 + // とりあえず全部足す 399 + ulong ans=0, tl=s.tl, te=e.tl; 400 + for( ; tl<=te; ++tl ) 401 + ans += len(tl); 402 + // 先頭行の分を引く 403 + ans -= s.ad; 404 + // 最終行の分を引く 405 + ans -= len(te) - e.ad; 406 + // 改行コード(CRLF)の分を加える 407 + ans += (e.tl-s.tl) * 2; 408 + // おしまい 409 + return ans; 410 +} 411 + 412 +void DocImpl::getText( unicode* buf, const DPos& s, const DPos& e ) 413 +{ 414 + if( s.tl == e.tl ) 415 + { 416 + // 一行だけの場合 417 + text_[s.tl].CopyAt( s.ad, e.ad-s.ad, buf ); 418 + buf[e.ad-s.ad] = L'\0'; 419 + } 420 + else 421 + { 422 + // 先頭行の後ろをコピー 423 + buf += text_[s.tl].CopyToTail( s.ad, buf ); 424 + *buf++ = L'\r', *buf++ = L'\n'; 425 + // 途中をコピー 426 + for( ulong i=s.tl+1; i<e.tl; i++ ) 427 + { 428 + buf += text_[i].CopyToTail( 0, buf ); 429 + *buf++ = L'\r', *buf++ = L'\n'; 430 + } 431 + // 終了行の先頭をコピー 432 + buf += text_[e.tl].CopyAt( 0, e.ad, buf ); 433 + *buf = L'\0'; 434 + } 435 +} 436 + 437 +void DocImpl::CorrectPos( DPos& pos ) 438 +{ 439 + // 正常範囲に収まるように修正 440 + pos.tl = Min( pos.tl, tln()-1 ); 441 + pos.ad = Min( pos.ad, len(pos.tl) ); 442 +} 443 + 444 +void DocImpl::CorrectPos( DPos& s, DPos& e ) 445 +{ 446 + // 必ずs<=eになるように修正 447 + if( s > e ) 448 + { 449 + ulong t; 450 + t=s.ad, s.ad=e.ad, e.ad=t; 451 + t=s.tl, s.tl=e.tl, e.tl=t; 452 + } 453 +} 454 + 455 +bool DocImpl::DeletingOperation 456 + ( DPos& s, DPos& e, unicode*& undobuf, ulong& undosiz ) 457 +{ 458 + AutoLock lk( this ); 459 + 460 + // 位置補正 461 + CorrectPos( s ); 462 + CorrectPos( e ); 463 + CorrectPos( s, e ); 464 + 465 + // 削除される量をカウント 466 + undosiz = getRangeLength( s, e ); 467 + 468 + // Undo操作用バッファ確保 469 + undobuf = new unicode[undosiz+1]; 470 + getText( undobuf, s, e ); 471 + 472 + // 削除る 473 + if( s.tl == e.tl ) 474 + { 475 + // 一行内削除 476 + text_[s.tl].RemoveAt( s.ad, e.ad-s.ad ); 477 + } 478 + else 479 + { 480 + // 先頭行の後ろを削除 481 + text_[s.tl].RemoveToTail( s.ad ); 482 + // 終了行の残り部分をくっつける 483 + text_[s.tl].InsertToTail( tl(e.tl)+e.ad, len(e.tl)-e.ad ); 484 + // いらん行を削除 485 + text_.RemoveAt( s.tl+1, e.tl-s.tl ); 486 + } 487 + 488 + // 再解析 489 + return ReParse( s.tl, s.tl ); 490 +} 491 + 492 +bool DocImpl::InsertingOperation 493 + ( DPos& s, const unicode* str, ulong len, DPos& e ) 494 +{ 495 + AutoLock lk( this ); 496 + 497 + // 位置補正 498 + CorrectPos( s ); 499 + 500 + // よーい、どん! 501 + e.ad = s.ad; 502 + e.tl = s.tl; 503 + 504 + // 指定文字列を改行で切り分ける準備 505 + const unicode* lineStr; 506 + ulong lineLen; 507 + UniReader r( str, len, &lineStr, &lineLen ); 508 + 509 + // 一行目… 510 + r.getLine(); 511 + text_[e.tl].InsertAt( e.ad, lineStr, lineLen ); 512 + e.ad += lineLen; 513 + 514 + if( !r.isEmpty() ) 515 + { 516 + // 二行目〜最終行 517 + do 518 + { 519 + r.getLine(); 520 + text_.InsertAt( ++e.tl, new Line(lineStr,lineLen) ); 521 + } while( !r.isEmpty() ); 522 + 523 + // 一行目の最後尾に残ってた文字列を最終行へ 524 + Line& fl = text_[s.tl]; 525 + Line& ed = text_[e.tl]; 526 + const ulong ln = fl.size()-e.ad; 527 + if( ln ) 528 + { 529 + ed.InsertToTail( fl.str()+e.ad, ln ); 530 + fl.RemoveToTail( e.ad ); 531 + } 532 + 533 + // 終了位置記録 534 + e.ad = lineLen; 535 + } 536 + 537 + // 再解析 538 + return ReParse( s.tl, e.tl ); 539 +} 540 + 541 + 542 + 543 +//------------------------------------------------------------------------- 544 +// 挿入コマンド 545 +//------------------------------------------------------------------------- 546 + 547 +Insert::Insert( const DPos& s, const unicode* str, ulong len, bool del ) 548 + : stt_( s ) 549 + , buf_( str ) 550 + , len_( len ) 551 + , del_( del ) 552 +{ 553 +} 554 + 555 +Insert::~Insert() 556 +{ 557 + if( del_ ) 558 + delete const_cast<unicode*>(buf_); 559 +} 560 + 561 +Command* Insert::operator()( Document& d ) const 562 +{ 563 + DocImpl& di = d.impl(); 564 + 565 + // 挿入 566 + DPos s=stt_, e; 567 + bool aa = di.InsertingOperation( s, buf_, len_, e ); 568 + 569 + // イベント発火 570 + di.Fire_TEXTUPDATE( s, s, e, aa, true ); 571 + 572 + // 逆操作オブジェクトを返す 573 + return new Delete( s, e ); 574 +} 575 + 576 + 577 + 578 +//------------------------------------------------------------------------- 579 +// 削除コマンド 580 +//------------------------------------------------------------------------- 581 + 582 +Delete::Delete( const DPos& s, const DPos& e ) 583 + : stt_( s ) 584 + , end_( e ) 585 +{ 586 +} 587 + 588 +Command* Delete::operator()( Document& d ) const 589 +{ 590 + DocImpl& di = d.impl(); 591 + 592 + // 削除 593 + unicode* buf; 594 + ulong siz; 595 + DPos s = stt_, e=end_; 596 + bool aa = di.DeletingOperation( s, e, buf, siz ); 597 + 598 + // イベント発火 599 + di.Fire_TEXTUPDATE( s, e, s, aa, true ); 600 + 601 + // 逆操作オブジェクトを返す 602 + return new Insert( s, buf, siz, true ); 603 +} 604 + 605 + 606 + 607 +//------------------------------------------------------------------------- 608 +// 置換コマンド 609 +//------------------------------------------------------------------------- 610 + 611 +Replace::Replace( 612 + const DPos& s, const DPos& e, const unicode* str, ulong len, bool del ) 613 + : stt_( s ) 614 + , end_( e ) 615 + , buf_( str ) 616 + , len_( len ) 617 + , del_( del ) 618 +{ 619 +} 620 + 621 +Replace::~Replace() 622 +{ 623 + if( del_ ) 624 + delete const_cast<unicode*>(buf_); 625 +} 626 + 627 +Command* Replace::operator()( Document& d ) const 628 +{ 629 + DocImpl& di = d.impl(); 630 + 631 + // 削除 632 + unicode* buf; 633 + ulong siz; 634 + DPos s=stt_, e=end_; 635 + bool aa = di.DeletingOperation( s, e, buf, siz ); 636 + 637 + // 挿入 638 + DPos e2; 639 + aa = (di.InsertingOperation( s, buf_, len_, e2 ) || aa); 640 + 641 + // イベント発火 642 + di.Fire_TEXTUPDATE( s, e, e2, aa, true ); 643 + 644 + // 逆操作オブジェクトを返す 645 + return new Replace( s, e2, buf, siz, true ); 646 +} 647 + 648 + 649 + 650 +//------------------------------------------------------------------------- 651 +// マクロコマンド 652 +//------------------------------------------------------------------------- 653 + 654 +Command* MacroCommand::operator()( Document& doc ) const 655 +{ 656 + doc.setBusyFlag(); 657 + 658 + MacroCommand* undo = new MacroCommand; 659 + undo->arr_.ForceSize( size() ); 660 + for( ulong i=0,e=arr_.size(); i<e; ++i ) 661 + undo->arr_[e-i-1] = (*arr_[i])(doc); 662 + 663 + doc.setBusyFlag(false); 664 + return undo; 665 +} 666 + 667 + 668 + 669 +//------------------------------------------------------------------------- 670 +// ファイルに保存 671 +//------------------------------------------------------------------------- 672 + 673 +void DocImpl::SaveFile( TextFileW& tf ) 674 +{ 675 + urdo_.SavedHere(); 676 + for( ulong i=0,iLast=tln()-1; i<=iLast; ++i ) 677 + tf.WriteLine( tl(i), len(i), i==iLast ); 678 +} 679 + 680 + 681 + 682 +//------------------------------------------------------------------------- 683 +// バッファの内容を全部破棄(暫定) 684 +//------------------------------------------------------------------------- 685 + 686 +void DocImpl::ClearAll() 687 +{ 688 + // 全部削除 689 + Execute( Delete( DPos(0,0), DPos(0xffffffff,0xffffffff) ) ); 690 + 691 + // Undo-Redoチェインをクリア 692 + urdo_.Clear(); 693 + urdo_.SavedHere(); 694 + Fire_MODIFYFLAGCHANGE(); 695 +} 696 + 697 + 698 + 699 +//------------------------------------------------------------------------- 700 +// ファイルを開く(暫定) 701 +//------------------------------------------------------------------------- 702 + 703 +void DocImpl::OpenFile( aptr<TextFileR> tf ) 704 +{ 705 + // ToDo: マルチスレッド化 706 + //currentOpeningFile_ = tf; 707 + //thd().Run( *this ); 708 + 709 + // 挿入 710 + DPos e(0,0); 711 + 712 + unicode buf[1024]; 713 + for( ulong i=0; tf->state(); ) 714 + { 715 + if( size_t L = tf->ReadLine( buf, countof(buf) ) ) 716 + { 717 + DPos p(i,0xffffffff); 718 + InsertingOperation( p, buf, (ulong)L, e ); 719 + i = tln() - 1; 720 + } 721 + if( tf->state() == 1 ) 722 + { 723 + DPos p(i++,0xffffffff); 724 + InsertingOperation( p, L"\n", 1, e ); 725 + } 726 + } 727 + 728 + // イベント発火 729 + Fire_TEXTUPDATE( DPos(0,0), DPos(0,0), e, true, false ); 730 +} 731 + 732 + 733 +void DocImpl::StartThread() 734 +{ 735 +/* 736 + // ToDo: 737 + aptr<TextFileR> tf = currentOpeningFile_; 738 + 739 + // 挿入 740 + unicode buf[1024]; 741 + while( !isExitRequested() && tf->state() ) 742 + { 743 + ulong i, j; 744 + DPos s(i=tln()-1, j=len(i)), e; 745 + if( ulong L = tf->ReadLine( buf, countof(buf) ) ) 746 + InsertingOperation( s, buf, L, e ); 747 + if( tf->state() == 1 ) 748 + InsertingOperation( DPos(i,0xffffffff), L"\n", 1, e ); 749 + 750 + // イベント発火 751 + Fire_TEXTUPDATE( s, s, e, true, false ); 752 + } 753 +*/ 754 +} 755 +
Added editwing/ip_view.h version [a25d583a35063324]
1 +#ifndef _EDITWING_IP_VIEW_H_ 2 +#define _EDITWING_IP_VIEW_H_ 3 +#include "ewView.h" 4 +#include "ip_doc.h" 5 +using namespace ki; 6 +#ifndef __ccdoc__ 7 +namespace editwing { 8 +namespace view { 9 +#endif 10 + 11 + 12 + 13 +using doc::DocImpl; 14 + 15 + 16 + 17 +//========================================================================= 18 +//@{ @pkg editwing.View.Impl //@} 19 +//@{ 20 +// 描画基本ルーチン 21 +// 22 +// 利用するには、Canvasオブジェクトから getPainter して使います。 23 +// 画面用デバイスコンテキストのレイヤです。きちんと書いておけば印刷機能を 24 +// 追加するときに楽なのかもしれませんが、そんなことを考える計画性が 25 +// あるはずもなく極めて適当に…。 26 +//@} 27 +//========================================================================= 28 + 29 +class Painter : public Object 30 +{ 31 +public: 32 + 33 + ~Painter(); 34 + 35 + //@{ 指定位置に一文字出力 //@} 36 + void CharOut( unicode ch, int x, int y ); 37 + 38 + //@{ 指定位置に文字列を出力 //@} 39 + void StringOut( const unicode* str, int len, int x, int y ); 40 + 41 + //@{ 文字色切り替え //@} 42 + void SetColor( int i ); 43 + 44 + //@{ 背景色で塗りつぶし //@} 45 + void Fill( const RECT& rc ); 46 + 47 + //@{ 反転 //@} 48 + void Invert( const RECT& rc ); 49 + 50 + //@{ 線を引く //@} 51 + void DrawLine( int x1, int y1, int x2, int y2 ); 52 + 53 + //@{ クリップ領域設定 //@} 54 + void SetClip( const RECT& rc ); 55 + 56 + //@{ クリップ領域解除 //@} 57 + void ClearClip(); 58 + 59 + //@{ 半角スペース用記号描画 //@} 60 + void DrawHSP( int x, int y, int times ); 61 + 62 + //@{ 全角スペース用記号描画 //@} 63 + void DrawZSP( int x, int y, int times ); 64 + 65 +public: 66 + 67 + //@{ 高さ(pixel) //@} 68 + int H() const { return height_; } 69 + 70 + //@{ 数字幅(pixel) //@} 71 + int F() const { return figWidth_; } 72 + 73 + //@{ 文字幅(pixel) //@} 74 + int Wc( unicode ch ) const 75 + { 76 + if( widthTable_[ ch ] == -1 ) 77 + ::GetCharWidthW( dc_, ch, ch, widthTable_+ch ); 78 + return widthTable_[ ch ]; 79 + } 80 + int W( const unicode* pch ) const // 1.08 サロゲートペア回避 81 + { 82 + unicode ch = *pch; 83 + if( widthTable_[ ch ] == -1 ) 84 + { 85 + if( isHighSurrogate(ch) ) 86 + { 87 + SIZE sz; 88 + if( ::GetTextExtentPoint32W( dc_, pch, 2, &sz ) ) 89 + return sz.cx; 90 + int w = 0; 91 + ::GetCharWidthW( dc_, ch, ch, &w ); 92 + return w; 93 + } 94 + ::GetCharWidthW( dc_, ch, ch, widthTable_+ch ); 95 + } 96 + return widthTable_[ ch ]; 97 + } 98 + 99 + //@{ 標準文字幅(pixel) //@} 100 + int W() const { return widthTable_[ L'x' ]; } 101 + 102 + //@{ 次のタブ揃え位置を計算 //@} 103 + //int nextTab(int x) const { int t=T(); return (x/t+1)*t; } 104 + int nextTab(int x) const { int t=T(); return ((x+4)/t+1)*t; } 105 + private: int T() const { return widthTable_[ L'\t' ]; } public: 106 + 107 + //@{ 現在のフォント情報 //@} 108 + const LOGFONT& LogFont() const { return logfont_; } 109 + 110 + //@{ 特別文字を描画するか否か //@} 111 + bool sc( int i ) const { return scDraw_[i]; } 112 + 113 +private: 114 + 115 + const HDC dc_; 116 + const HFONT font_; 117 + const HPEN pen_; 118 + const HBRUSH brush_; 119 + int height_; 120 + int* widthTable_; 121 + int figWidth_; 122 + LOGFONT logfont_; 123 + COLORREF colorTable_[7]; 124 + bool scDraw_[5]; 125 + 126 +private: 127 + 128 + Painter( HDC hdc, const VConfig& vc ); 129 + HDC getDC() { return dc_; } 130 + friend class Canvas; 131 + NOCOPY(Painter); 132 +}; 133 + 134 + 135 + 136 +//========================================================================= 137 +//@{ 138 +// 描画可能領域 139 +// 140 +// ウインドウサイズの変更や折り返しの有無やフォントの設定などに 141 +// 対応して、描画領域のサイズを適当に管理します。やることは 142 +// とりあえずそれだけ。 143 +//@} 144 +//========================================================================= 145 + 146 +class Canvas : public Object 147 +{ 148 +public: 149 + 150 + Canvas( const View& vw ); 151 + 152 + //@{ Viewの大きさ変更イベント処理 153 + // @return 折り返し幅が変わったらtrue //@} 154 + bool on_view_resize( int cx, int cy ); 155 + 156 + //@{ 行数変更イベント処理 157 + // @return テキスト領域の幅が変わったらtrue //@} 158 + bool on_tln_change( ulong tln ); 159 + 160 + //@{ フォント変更イベント処理 //@} 161 + void on_font_change( const VConfig& vc ); 162 + 163 + //@{ 設定変更イベント処理 //@} 164 + void on_config_change( int wrap, bool showln ); 165 + 166 +public: 167 + 168 + //@{ [行番号を表示するか否か] //@} 169 + bool showLN() const { return showLN_; } 170 + 171 + //@{ [-1:折り返し無し 0:窓右端 else:指定文字数] //@} 172 + int wrapType() const { return wrapType_; } 173 + 174 + //@{ 折り返し幅(pixel) //@} 175 + ulong wrapWidth() const { return wrapWidth_; } 176 + 177 + //@{ 表示領域の位置(pixel) //@} 178 + const RECT& zone() const { return txtZone_; } 179 + 180 + //@{ 描画用オブジェクト //@} 181 + Painter& getPainter() const { return *font_; } 182 + 183 +private: 184 + 185 + int wrapType_; // [ -1:折り返し無し 0:窓右端 else:指定文字数 ] 186 + bool showLN_; // [ 行番号を表示するか否か ] 187 + 188 + dptr<Painter> font_; // 描画用オブジェクト 189 + ulong wrapWidth_; // 折り返し幅(pixel) 190 + RECT txtZone_; // テキスト表示域の位置(pixel) 191 + int figNum_; // 行番号の桁数 192 + 193 +private: 194 + 195 + bool CalcLNAreaWidth(); 196 + void CalcWrapWidth(); 197 + 198 +private: 199 + 200 + NOCOPY(Canvas); 201 +}; 202 + 203 + 204 + 205 +//========================================================================= 206 +//@{ 207 +// 行毎の折り返し情報 208 +//@} 209 +//========================================================================= 210 + 211 +struct WLine : public storage<ulong> 212 +{ 213 + // [0] : その行の折り返し無しでの横幅を格納 214 + // [1-n] : n行目の終端のindexを格納。 215 + // 216 + // 例えば "aaabbb" という論理行を "aaab" "bb" と折るなら 217 + // {48, 4, 6} などという長さ3の配列となる。 218 + 219 + WLine() : storage<ulong>(2) {} 220 + ulong& width() { return (*this)[0]; } 221 + ulong width() const { return (*this)[0]; } 222 + ulong rln() const { return size()-1; } 223 +}; 224 + 225 + 226 + 227 +//========================================================================= 228 +//@{ 229 +// 再描画範囲を指定するためのフラグ 230 +//@} 231 +//========================================================================= 232 + 233 +enum ReDrawType 234 +{ 235 + LNAREA, // 行番号ゾーンのみ 236 + LINE, // 変更のあった一行のみ 237 + AFTER, // 変更のあった行以下全部 238 + ALL // 全画面 239 +}; 240 + 241 + 242 + 243 +//========================================================================= 244 +//@{ 245 +// 描画処理を細かく指定する構造体 246 +//@} 247 +//========================================================================= 248 + 249 +struct VDrawInfo 250 +{ 251 + const RECT rc; // 再描画範囲 252 + int XBASE; // 一番左の文字のx座標 253 + int XMIN; // テキスト再描画範囲左端 254 + int XMAX; // テキスト再描画範囲右端 255 + int YMIN; // テキスト再描画範囲上端 256 + int YMAX; // テキスト再描画範囲下端 257 + ulong TLMIN; // テキスト再描画範囲上端論理行番号 258 + int SXB, SXE; // 選択範囲のx座標 259 + int SYB, SYE; // 選択範囲のy座標 260 + 261 + explicit VDrawInfo( const RECT& r ) : rc(r) {} 262 +}; 263 + 264 + 265 + 266 +//========================================================================= 267 +//@{ 268 +// 折り返しedテキストの管理・表示等 269 +// 270 +// Canvasクラスによって計算された領域サイズを参考に、テキストの 271 +// 折り返し処理を実行する。ここで、スクロール制御、描画処理など 272 +// 主要な処理は全て実行することになる。 273 +//@} 274 +//========================================================================= 275 + 276 +class ViewImpl : public Object 277 +{ 278 +public: 279 + 280 + ViewImpl( View& vw, DocImpl& dc ); 281 + 282 + //@{ 折り返し方式切替 //@} 283 + void SetWrapType( int wt ); 284 + 285 + //@{ 行番号表示/非表示切替 //@} 286 + void ShowLineNo( bool show ); 287 + 288 + //@{ 表示色・フォント切替 //@} 289 + void SetFont( const VConfig& vc ); 290 + 291 + //@{ テキスト領域のサイズ変更イベント //@} 292 + void on_view_resize( int cx, int cy ); 293 + 294 + void DoResize( bool wrapWidthChanged ); 295 + void DoConfigChange(); 296 + 297 + //@{ テキストデータの更新イベント //@} 298 + void on_text_update( const DPos& s, 299 + const DPos& e, const DPos& e2, bool bAft, bool mCur ); 300 + 301 + //@{ 描画処理 //@} 302 + void on_paint( const PAINTSTRUCT& ps ); 303 + 304 +public: 305 + 306 + //@{ 全表示行数 //@} 307 + ulong vln() const { return vlNum_; } 308 + 309 + //@{ 一行の表示行数 //@} 310 + ulong rln( ulong tl ) const { return wrap_[tl].rln(); } 311 + 312 + //@{ 折り返し位置 //@} 313 + ulong rlend( ulong tl, ulong rl ) const { return wrap_[tl][rl+1]; } 314 + 315 + //@{ 一個でも折り返しが存在するか否か //@} 316 + bool wrapexists() const { return doc_.tln() != vln(); } 317 + 318 + //@{ カーソル //@} 319 + Cursor& cur() { return cur_; } 320 + 321 + //@{ フォント //@} 322 + const Painter& fnt() const { return cvs_.getPainter(); } 323 + 324 + 325 + void on_hscroll( int code ); 326 + void on_vscroll( int code ); 327 + void on_wheel( short delta ); 328 + 329 + void GetVPos( int x, int y, VPos* vp, bool linemode=false ) const; 330 + void GetOrigin( int* x, int* y ) const; 331 + void ConvDPosToVPos( DPos dp, VPos* vp, const VPos* base=NULL ) const; 332 + void ScrollTo( const VPos& vp ); 333 + int GetLastWidth( ulong tl ) const; 334 + 335 +public: 336 + 337 + const RECT& zone() const { return cvs_.zone(); } 338 + int left() const { return cvs_.zone().left; } 339 + int right() const { return cvs_.zone().right; } 340 + int bottom()const { return cvs_.zone().bottom; } 341 + int lna() const { return cvs_.zone().left; } 342 + int cx() const { return cvs_.zone().right - cvs_.zone().left; } 343 + int cxAll() const { return cvs_.zone().right; } 344 + int cy() const { return cvs_.zone().bottom; } 345 + 346 +private: 347 + 348 + const DocImpl& doc_; 349 + Canvas cvs_; 350 + Cursor cur_; 351 + gapbufobj<WLine> wrap_; 352 + ulong vlNum_; 353 + ulong textCx_; 354 + 355 +private: 356 + 357 + void DrawLNA( const VDrawInfo& v, Painter& p ); 358 + void DrawTXT( const VDrawInfo v, Painter& p ); 359 + void Inv( int y, int xb, int xe, Painter& p ); 360 + 361 + void CalcEveryLineWidth(); 362 + ulong CalcLineWidth( const unicode* txt, ulong len ) const; 363 + void ModifyWrapInfo( const unicode* txt, ulong len, WLine& wl, ulong stt ); 364 + void ReWrapAll(); 365 + int ReWrapSingle( const DPos& s ); 366 + int InsertMulti( ulong ti_s, ulong ti_e ); 367 + int DeleteMulti( ulong ti_s, ulong ti_e ); 368 + void UpdateTextCx(); 369 + void ReDraw( ReDrawType r, const DPos* s=NULL ); 370 + 371 +private: 372 + 373 + HWND hwnd_; 374 + SCROLLINFO rlScr_; // 横スクロール情報(pixel単位) 375 + SCROLLINFO udScr_; // 縦スクロール情報(行単位) 376 + ulong udScr_tl_; // 一番上に表示される論理行のTLine_Index 377 + ulong udScr_vrl_; // 一番上に表示される表示行のVRLine_Index 378 + 379 +private: 380 + 381 + bool ReSetScrollInfo(); 382 + void ForceScrollTo( ulong tl ); 383 + void UpdateScrollBar(); 384 + ReDrawType TextUpdate_ScrollBar( const DPos& s, const DPos& e, const DPos& e2 ); 385 + 386 + ulong tl2vl( ulong tl ) const; 387 + void GetDrawPosInfo( VDrawInfo& v ) const; 388 + void InvalidateView( const DPos& dp, bool afterall ) const; 389 + void ScrollView( int dx, int dy, bool update ); 390 + void UpDown( int dy, bool thumb ); 391 +}; 392 + 393 + 394 + 395 +//------------------------------------------------------------------------- 396 + 397 +inline void ViewImpl::on_view_resize( int cx, int cy ) 398 + { DoResize( cvs_.on_view_resize( cx, cy ) ); } 399 + 400 +inline void ViewImpl::SetWrapType( int wt ) 401 + { cvs_.on_config_change( wt, cvs_.showLN() ); 402 + DoConfigChange(); } 403 + 404 +inline void ViewImpl::ShowLineNo( bool show ) 405 + { cvs_.on_config_change( cvs_.wrapType(), show ); 406 + DoConfigChange(); } 407 + 408 +inline void ViewImpl::SetFont( const VConfig& vc ) 409 + { cvs_.on_font_change( vc ); 410 + cur_.on_setfocus(); 411 + CalcEveryLineWidth(); // 行幅再計算 412 + DoConfigChange(); } 413 + 414 +inline void ViewImpl::GetOrigin( int* x, int* y ) const 415 + { *x = left()-rlScr_.nPos, *y = -udScr_.nPos*cvs_.getPainter().H(); } 416 + 417 + 418 + 419 +//========================================================================= 420 + 421 +}} // namespace editwing::view 422 +#endif // _EDITWING_IP_VIEW_H_
Added editwing/ip_wrap.cpp version [efe9189ceabe7b50]
1 +#include "stdafx.h" 2 +#include "ip_view.h" 3 +using namespace editwing; 4 +using namespace editwing::view; 5 + 6 + 7 + 8 +//========================================================================= 9 +//---- ip_wrap.cpp 折り返し 10 +// 11 +// Documentで文字列データが更新されるのを受けて 12 +// Viewでは折り返し位置情報を更新する。その処理がココ。 13 +// 14 +//---- ip_text.cpp 文字列操作・他 15 +//---- ip_parse.cpp キーワード解析 16 +//---- ip_scroll.cpp スクロール 17 +//---- ip_draw.cpp 描画・他 18 +//---- ip_cursor.cpp カーソルコントロール 19 +//========================================================================= 20 + 21 + 22 + 23 +//------------------------------------------------------------------------- 24 +// 初期化 25 +//------------------------------------------------------------------------- 26 + 27 +ViewImpl::ViewImpl( View& vw, DocImpl& dc ) 28 + : doc_ ( dc ) 29 + , cvs_ ( vw ) 30 + , cur_ ( vw.hwnd(), *this, dc ) 31 + , hwnd_ ( vw.hwnd() ) 32 + , vlNum_ ( 0 ) 33 + , textCx_( 0 ) 34 +{ 35 + // 適当に折り返し情報初期化 36 + InsertMulti( 0, doc_.tln()-1 ); 37 + 38 + // 適当にスクロール情報初期化 39 + udScr_.cbSize = rlScr_.cbSize = sizeof(udScr_); 40 + udScr_.fMask = rlScr_.fMask = SIF_PAGE | SIF_POS | SIF_RANGE; 41 + udScr_.nMin = rlScr_.nMin = 0; 42 + udScr_.nPos = rlScr_.nPos = 0; 43 + udScr_.fMask |= SIF_DISABLENOSCROLL; 44 + udScr_tl_ = udScr_vrl_ = 0; 45 + ReSetScrollInfo(); 46 +} 47 + 48 + 49 + 50 +//------------------------------------------------------------------------- 51 +// 状態変更への対応 52 +//------------------------------------------------------------------------- 53 + 54 +void ViewImpl::DoResize( bool wrapWidthChanged ) 55 +{ 56 + // 折り返し位置再計算 57 + if( wrapWidthChanged ) 58 + { 59 + ReWrapAll(); 60 + UpdateTextCx(); 61 + } 62 + 63 + // スクロール情報変更 64 + ReSetScrollInfo(); 65 + if( wrapWidthChanged ) 66 + ForceScrollTo( udScr_tl_ ); 67 + 68 + // 再描画 69 + ReDraw( ALL ); 70 + cur_.ResetPos(); 71 +} 72 + 73 +void ViewImpl::DoConfigChange() 74 +{ 75 + // 折り返し位置再計算 76 + ReWrapAll(); 77 + UpdateTextCx(); 78 + 79 + // スクロール情報変更 80 + ReSetScrollInfo(); 81 + ForceScrollTo( udScr_tl_ ); 82 + 83 + // 再描画 84 + ReDraw( ALL ); 85 + cur_.ResetPos(); 86 +} 87 + 88 +void ViewImpl::on_text_update 89 + ( const DPos& s, const DPos& e, const DPos& e2, bool bAft, bool mCur ) 90 +{ 91 + // まず、折り返し位置再計算 92 + 93 + // 置換範囲の先頭行を調整 94 + int r3 = 0, r2 = 1, r1 = ReWrapSingle( s ); 95 + 96 + // 残りを調整 97 + if( s.tl != e.tl ) 98 + r2 = DeleteMulti( s.tl+1, e.tl ); 99 + if( s.tl != e2.tl ) 100 + r3 = InsertMulti( s.tl+1, e2.tl ); 101 + 102 + // この変更で横幅が… 103 + // if( "長くなったなてはいない" AND "短くなっちゃった可能性あり" ) 104 + // 横幅再計算(); 105 + if( !(r1==2 || r3==1) && (r1==0 || r2==0) ) 106 + UpdateTextCx(); 107 + 108 + // スクロールバー修正 109 + ReDrawType t = TextUpdate_ScrollBar( s, e, e2 ); 110 + bool doResize = false; 111 + 112 + // 行数に変化があって、行番号表示域の幅を変えなきゃならん時 113 + if( e.tl!=e2.tl && cvs_.on_tln_change( doc_.tln() ) ) 114 + { 115 + doResize = true; 116 + } 117 + else if( bAft && t!=ALL ) 118 + { 119 + t = AFTER; 120 + } 121 + 122 + // カーソル移動 123 + cur_.on_text_update( s, e, e2, mCur ); 124 + 125 + // 再描画 126 + if( doResize ) 127 + DoResize( true ); 128 + else 129 + { 130 + if( e.tl != e2.tl ) // 行番号領域再描画の必要があるとき 131 + ReDraw( LNAREA, 0 ); 132 + ReDraw( t, &s ); 133 + } 134 +} 135 + 136 + 137 + 138 +//------------------------------------------------------------------------- 139 +// 折り返し位置計算補助ルーチン 140 +//------------------------------------------------------------------------- 141 + 142 +void ViewImpl::UpdateTextCx() 143 +{ 144 + if( cvs_.wrapType() == NOWRAP ) 145 + { 146 + // 折り返しなしなら、数えてみないと横幅はわからない 147 + ulong cx=0; 148 + for( ulong i=0, ie=doc_.tln(); i<ie; ++i ) 149 + if( cx < wrap_[i].width() ) 150 + cx = wrap_[i].width(); 151 + textCx_ = cx; 152 + } 153 + else 154 + { 155 + // 折り返しありなら、横幅:=折り返し幅とする 156 + textCx_ = cvs_.wrapWidth(); 157 + } 158 +} 159 + 160 +ulong ViewImpl::CalcLineWidth( const unicode* txt, ulong len ) const 161 +{ 162 + // 行を折り返さずに書いたときの横幅を計算する 163 + // ほとんどの行が折り返し無しで表示されるテキストの場合、 164 + // この値を計算しておくことで、処理の高速化が可能。 165 + const Painter& p = cvs_.getPainter(); 166 + 167 + ulong w=0; 168 + for( ulong i=0; i<len; ++i ) 169 + if( txt[i] == L'\t' ) 170 + w = p.nextTab(w); 171 + else 172 + w += p.W( &txt[i] ); 173 + return w; 174 +} 175 + 176 +void ViewImpl::CalcEveryLineWidth() 177 +{ 178 + // 全ての行に対してCalcLineWidthを実行 179 + // …するだけ。 180 + for( ulong i=0, ie=doc_.tln(); i<ie; ++i ) 181 + wrap_[i].width() = CalcLineWidth( doc_.tl(i), doc_.len(i) ); 182 +} 183 + 184 +void ViewImpl::ModifyWrapInfo( 185 + const unicode* txt, ulong len, WLine& wl, ulong stt ) 186 +{ 187 + // 設定幅での折り返しを実行する。 188 + // 行の途中からの変更の場合、sttが開始addressを指している 189 + const Painter& p = cvs_.getPainter(); 190 + const ulong ww = cvs_.wrapWidth(); 191 + 192 + while( stt < len ) 193 + { 194 + ulong i, w; 195 + for( w=0,i=stt; i<len; ++i ) 196 + { 197 + if( txt[i] == L'\t' ) 198 + w = p.nextTab(w); 199 + else 200 + w += p.W( &txt[i] ); 201 + 202 + if( w>ww ) 203 + break; // 幅が設定値を超えた所でおしまい 204 + } 205 + wl.Add( stt = (i==stt?i+1:i) ); 206 + } 207 +} 208 + 209 +int ViewImpl::GetLastWidth( ulong tl ) const 210 +{ 211 + if( rln(tl)==1 ) 212 + return wrap_[tl][0]; 213 + 214 + ulong beg = rlend(tl,rln(tl)-2); 215 + return CalcLineWidth( doc_.tl(tl)+beg, doc_.len(tl)-beg ); 216 +} 217 + 218 +void ViewImpl::ReWrapAll() 219 +{ 220 + // 折り返し幅に変更があった場合に、全ての行の 221 + // 折り返し位置情報を変更する。 222 + const ulong ww = cvs_.wrapWidth(); 223 + 224 + ulong vln=0; 225 + for( ulong i=0, ie=doc_.tln(); i<ie; ++i ) 226 + { 227 + WLine& wl = wrap_[i]; 228 + wl.ForceSize(1); 229 + 230 + if( wl.width() < ww ) 231 + { 232 + // 設定した折り返し幅より短い場合は一行で済む。 233 + wl.Add( doc_.len(i) ); 234 + ++vln; 235 + } 236 + else 237 + { 238 + // 複数行になる場合 239 + ModifyWrapInfo( doc_.tl(i), doc_.len(i), wl, 0 ); 240 + vln += wl.rln(); 241 + } 242 + } 243 + vlNum_ = vln; 244 +} 245 + 246 + 247 + 248 +//------------------------------------------------------------------------- 249 +// 折り返し位置計算メインルーチン 250 +//------------------------------------------------------------------------- 251 + 252 +int ViewImpl::ReWrapSingle( const DPos& s ) 253 +{ 254 + // 指定した一行のみ折り返しを修正。 255 + // 256 + // 返値は 257 + // 2: "折り返しあり" or "この行が横に一番長くなった" 258 + // 1: "この行以外のどこかが最長" 259 + // 0: "さっきまでこの行は最長だったが短くなっちゃった" 260 + // で、上位ルーチンにm_TextCx修正の必要性を伝える。 261 + // 262 + // 昔は再描画範囲の計算のために、表示行数の変化を返していたが、 263 + // これは上位ルーチン側で vln() を比較すれば済むし、 264 + // むしろその方が効率的であるため廃止した。 265 + 266 + 267 + // 旧情報保存 268 + WLine& wl = wrap_[s.tl]; 269 + const ulong oldVRNum = wl.rln(); 270 + const ulong oldWidth = wl.width(); 271 + 272 + // 横幅更新 273 + wl.width() = CalcLineWidth( doc_.tl(s.tl), doc_.len(s.tl) ); 274 + 275 + if( wl.width() < cvs_.wrapWidth() ) 276 + { 277 + // 設定した折り返し幅より短い場合は一行で済む。 278 + wl[1] = doc_.len(s.tl); 279 + wl.ForceSize( 2 ); 280 + } 281 + else 282 + { 283 + // 複数行になる場合 284 + ulong vr=1, stt=0; 285 + while( wl[vr] < s.ad ) // while( vr行目は変更箇所より手前 ) 286 + stt = wl[ vr++ ]; // stt = 次の行の行頭のアドレス 287 + 288 + // 変更箇所以降のみ修正 289 + wl.ForceSize( vr ); 290 + ModifyWrapInfo( doc_.tl(s.tl), doc_.len(s.tl), wl, stt ); 291 + } 292 + 293 + // 表示行の総数を修正 294 + vlNum_ += ( wl.rln() - oldVRNum ); 295 + 296 + // 折り返しなしだと総横幅の更新が必要 297 + if( cvs_.wrapType() == NOWRAP ) 298 + if( textCx_ <= wl.width() ) 299 + { 300 + textCx_ = wl.width(); 301 + return 2; 302 + } 303 + else if( textCx_ == oldWidth ) 304 + { 305 + return 0; 306 + } 307 + else 308 + { 309 + return 1; 310 + } 311 + return 2; 312 +} 313 + 314 +int ViewImpl::InsertMulti( ulong ti_s, ulong ti_e ) 315 +{ 316 + // 指定した分だけ新しく行情報を追加。 317 + // &折り返し情報もきちんと計算 318 + // 319 + // 返値は 320 + // 1: "折り返しあり" or "この行が横に一番長くなった" 321 + // 0: "この行以外のどこかが最長" 322 + // 詳しくは ReWrapSingle() を見よ。 323 + 324 + ulong dy=0, cx=0; 325 + for( ulong i=ti_s; i<=ti_e; ++i ) 326 + { 327 + WLine* pwl = new WLine; 328 + pwl->Add( CalcLineWidth( doc_.tl(i), doc_.len(i) ) ); 329 + 330 + if( pwl->width() < cvs_.wrapWidth() ) 331 + { 332 + // 設定した折り返し幅より短い場合は一行で済む。 333 + pwl->Add( doc_.len(i) ); 334 + dy++; 335 + if( cx < pwl->width() ) 336 + cx = pwl->width(); 337 + } 338 + else 339 + { 340 + // 複数行になる場合 341 + ModifyWrapInfo( doc_.tl(i), doc_.len(i), *pwl, 0 ); 342 + dy += pwl->rln(); 343 + } 344 + 345 + wrap_.InsertAt( i, pwl ); 346 + } 347 + 348 + // 表示行の総数を修正 349 + vlNum_ += dy; 350 + 351 + // 折り返しなしだと総横幅の更新が必要 352 + if( cvs_.wrapType() == NOWRAP ) 353 + { 354 + if( textCx_ <= cx ) 355 + { 356 + textCx_ = cx; 357 + return 1; 358 + } 359 + return 0; 360 + } 361 + return 1; 362 +} 363 + 364 +int ViewImpl::DeleteMulti( ulong ti_s, ulong ti_e ) 365 +{ 366 + // 指定した範囲の行情報を削除 367 + // 368 + // 返値は 369 + // 1: "折り返しあり" or "この行以外のどこかが最長" 370 + // 0: "さっきまでこの行は最長だったが短くなっちゃった" 371 + // 詳しくは ReWrapSingle() を見よ。 372 + 373 + bool widthChanged = false; 374 + ulong dy = 0; 375 + 376 + // 情報収集しながら削除 377 + for( ulong cx=textCx_, i=ti_s; i<=ti_e; ++i ) 378 + { 379 + WLine& wl = wrap_[i]; 380 + dy += wl.rln(); 381 + if( cx == wl.width() ) 382 + widthChanged = true; 383 + } 384 + wrap_.RemoveAt( ti_s, (ti_e-ti_s+1) ); 385 + 386 + // 表示行の総数を修正 387 + vlNum_ -= dy; 388 + 389 + // 折り返しなしだと総横幅の更新が必要 390 + return ( cvs_.wrapType()==NOWRAP && widthChanged ) ? 0 : 1; 391 +} 392 + 393 + 394 + 395 +//------------------------------------------------------------------------- 396 +// 座標値変換 397 +//------------------------------------------------------------------------- 398 + 399 +void ViewImpl::ConvDPosToVPos( DPos dp, VPos* vp, const VPos* base ) const 400 +{ 401 + // 補正 402 + dp.tl = Min( dp.tl, doc_.tln()-1 ); 403 + dp.ad = Min( dp.ad, doc_.len(dp.tl) ); 404 + 405 + // 変換の基準点が指定されていなければ、原点を基準とする 406 + VPos topPos(false); // 0クリア 407 + if( base == NULL ) 408 + base = &topPos; 409 + 410 + // とりあえずbase行頭の値を入れておく 411 + ulong vl = base->vl - base->rl; 412 + ulong rl = 0; 413 + int vx; 414 + 415 + // 同じ行内だった場合 416 + //if( dp.tl == base->tl ) 417 + //{ 418 + // 例えば [→] を押したときなど、右隣の文字の横幅を 419 + // 足すだけで次の位置は算出できる。これを使って普通の 420 + // カーソル移動はずっと高速化できるはずであるが、 421 + // とりあえず面倒くさいので、今のところ略。 422 + //} 423 + 424 + // 違う行だった場合 425 + //else 426 + { 427 + // vlを合わせる 428 + ulong tl = base->tl; 429 + if( tl > dp.tl ) // 目的地が基準より上にある場合 430 + do 431 + vl -= rln(--tl); 432 + while( tl > dp.tl ); 433 + else if( tl < dp.tl ) // 目的地が基準より下にある場合 434 + do 435 + vl += rln(tl++); 436 + while( tl < dp.tl ); 437 + 438 + // rlを合わせる 439 + ulong stt=0; 440 + while( wrap_[tl][rl+1] < dp.ad ) 441 + stt = wrap_[tl][++rl]; 442 + vl += rl; 443 + 444 + // x座標計算 445 + vx = CalcLineWidth( doc_.tl(tl)+stt, dp.ad-stt ); 446 + } 447 + 448 + vp->tl = dp.tl; 449 + vp->ad = dp.ad; 450 + vp->vl = vl; 451 + vp->rl = rl; 452 + vp->rx = vp->vx = vx; 453 +} 454 + 455 +void ViewImpl::GetVPos( int x, int y, VPos* vp, bool linemode ) const 456 +{ 457 +// x座標補正 458 + 459 + x = x - lna() + rlScr_.nPos; 460 + 461 +// まず行番号計算 462 + 463 + int tl = udScr_tl_; 464 + int vl = udScr_.nPos - udScr_vrl_; 465 + int rl = y / fnt().H() + udScr_vrl_; 466 + if( rl >= 0 ) // View上端より下の場合、下方向を調べる 467 + while( tl < (int)doc_.tln() && (int)rln(tl) <= rl ) 468 + { 469 + vl += rln(tl); 470 + rl -= rln(tl); 471 + ++tl; 472 + } 473 + else // View上端より上の場合、上方向を調べる 474 + while( 0<=tl && rl<0 ) 475 + { 476 + vl -= rln(tl); 477 + rl += rln(tl); 478 + --tl; 479 + } 480 + 481 + if( tl == (int)doc_.tln() ) // EOFより下に行ってしまう場合の補正 482 + { 483 + --tl, vl-=rln(tl), rl=rln(tl)-1; 484 + if( linemode ) 485 + x = 0x4fffffff; 486 + } 487 + else if( tl == -1 ) // ファイル頭より上に行ってしまう場合の補正 488 + { 489 + tl = vl = rl = 0; 490 + if( linemode ) 491 + x = 0; 492 + } 493 + else 494 + { 495 + if( linemode ) // 行選択モードの場合 496 + { 497 + if( tl == (int)doc_.tln()-1 ) 498 + rl=rln(tl)-1, x=0x4fffffff; 499 + else 500 + vl+=rln(tl), rl=0, ++tl, x=0; 501 + } 502 + } 503 + 504 + vp->tl = tl; 505 + vp->vl = vl + rl; 506 + vp->rl = rl; 507 + 508 +// 次に、横位置を計算 509 + 510 + if( rl < static_cast<int>(wrap_[tl].rln()) ) 511 + { 512 + const unicode* str = doc_.tl(tl); 513 + const ulong adend = rlend(tl,rl); 514 + ulong ad = (rl==0 ? 0 : rlend(tl,rl-1)); 515 + int vx = (rl==0 ? 0 : fnt().W(&str[ad++])); 516 + 517 + while( ad<adend ) 518 + { 519 + int nvx = (str[ad]==L'\t' 520 + ? fnt().nextTab(vx) 521 + : vx + fnt().W(&str[ad]) 522 + ); 523 + if( x+2 < nvx ) 524 + break; 525 + vx = nvx; 526 + ++ad; 527 + } 528 + 529 + vp->ad = ad; 530 + vp->rx = vp->vx = vx; 531 + } 532 + else 533 + { 534 + vp->ad = vp->rx = vp->vx = 0; 535 + } 536 +}
Added kilib.dsp version [76b8624a35f5bd7a]
1 +# Microsoft Developer Studio Project File - Name="kilib" - Package Owner=<4> 2 +# Microsoft Developer Studio Generated Build File, Format Version 6.00 3 +# ** 編集しないでください ** 4 + 5 +# TARGTYPE "Win32 (x86) Application" 0x0101 6 + 7 +CFG=kilib - Win32 Debug 8 +!MESSAGE これは有効なメイクファイルではありません。 このプロジェクトをビルドするためには NMAKE を使用してください。 9 +!MESSAGE [メイクファイルのエクスポート] コマンドを使用して実行してください 10 +!MESSAGE 11 +!MESSAGE NMAKE /f "kilib.mak". 12 +!MESSAGE 13 +!MESSAGE NMAKE の実行時に構成を指定できます 14 +!MESSAGE コマンド ライン上でマクロの設定を定義します。例: 15 +!MESSAGE 16 +!MESSAGE NMAKE /f "kilib.mak" CFG="kilib - Win32 Debug" 17 +!MESSAGE 18 +!MESSAGE 選択可能なビルド モード: 19 +!MESSAGE 20 +!MESSAGE "kilib - Win32 Release" ("Win32 (x86) Application" 用) 21 +!MESSAGE "kilib - Win32 Debug" ("Win32 (x86) Application" 用) 22 +!MESSAGE "kilib - Win32 Unicode Release" ("Win32 (x86) Application" 用) 23 +!MESSAGE 24 + 25 +# Begin Project 26 +# PROP AllowPerConfigDependencies 0 27 +# PROP Scc_ProjName "" 28 +# PROP Scc_LocalPath "" 29 +CPP=cl.exe 30 +MTL=midl.exe 31 +RSC=rc.exe 32 + 33 +!IF "$(CFG)" == "kilib - Win32 Release" 34 + 35 +# PROP BASE Use_MFC 0 36 +# PROP BASE Use_Debug_Libraries 0 37 +# PROP BASE Output_Dir "Release" 38 +# PROP BASE Intermediate_Dir "Release" 39 +# PROP BASE Target_Dir "" 40 +# PROP Use_MFC 0 41 +# PROP Use_Debug_Libraries 0 42 +# PROP Output_Dir "release" 43 +# PROP Intermediate_Dir "OBJ/vc/rel" 44 +# PROP Ignore_Export_Lib 0 45 +# PROP Target_Dir "" 46 +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /c 47 +# ADD CPP /nologo /Gr /Zp4 /W3 /Gi /Og /Oi /Os /Oy /Ob1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "SUPERTINY" /D "USEGLOBALIME" /Yu"stdafx.h" /FD /GF /c 48 +# SUBTRACT CPP /Gf 49 +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 50 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 51 +# ADD BASE RSC /l 0x411 /d "NDEBUG" 52 +# ADD RSC /l 0x411 /d "NDEBUG" 53 +BSC32=bscmake.exe 54 +# ADD BASE BSC32 /nologo 55 +# ADD BSC32 /nologo 56 +LINK32=link.exe 57 +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 58 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib imm32.lib /nologo /subsystem:windows /map /machine:I386 /nodefaultlib /out:"release/GreenPad.exe" 59 +# SUBTRACT LINK32 /pdb:none 60 + 61 +!ELSEIF "$(CFG)" == "kilib - Win32 Debug" 62 + 63 +# PROP BASE Use_MFC 0 64 +# PROP BASE Use_Debug_Libraries 1 65 +# PROP BASE Output_Dir "Debug" 66 +# PROP BASE Intermediate_Dir "Debug" 67 +# PROP BASE Target_Dir "" 68 +# PROP Use_MFC 0 69 +# PROP Use_Debug_Libraries 1 70 +# PROP Output_Dir "OBJ/" 71 +# PROP Intermediate_Dir "OBJ/vc/debug" 72 +# PROP Ignore_Export_Lib 0 73 +# PROP Target_Dir "" 74 +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c 75 +# ADD CPP /nologo /W3 /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "SUPERTINY" /D "USEGLOBALIME" /FR /Yu"stdafx.h" /FD /c 76 +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 77 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 78 +# ADD BASE RSC /l 0x411 /d "_DEBUG" 79 +# ADD RSC /l 0x411 /d "_DEBUG" 80 +BSC32=bscmake.exe 81 +# ADD BASE BSC32 /nologo 82 +# ADD BSC32 /nologo 83 +LINK32=link.exe 84 +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept 85 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib imm32.lib /nologo /subsystem:windows /debug /machine:I386 /out:"OBJ/GreenPad.exe" /pdbtype:sept 86 + 87 +!ELSEIF "$(CFG)" == "kilib - Win32 Unicode Release" 88 + 89 +# PROP BASE Use_MFC 0 90 +# PROP BASE Use_Debug_Libraries 0 91 +# PROP BASE Output_Dir "kilib___Win32_Unicode_Release" 92 +# PROP BASE Intermediate_Dir "kilib___Win32_Unicode_Release" 93 +# PROP BASE Ignore_Export_Lib 0 94 +# PROP BASE Target_Dir "" 95 +# PROP Use_MFC 0 96 +# PROP Use_Debug_Libraries 0 97 +# PROP Output_Dir "release" 98 +# PROP Intermediate_Dir "OBJ/vc/reluni" 99 +# PROP Ignore_Export_Lib 0 100 +# PROP Target_Dir "" 101 +# ADD BASE CPP /nologo /Gr /Zp4 /W3 /Gi /Og /Oi /Os /Oy /Ob1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "SUPERTINY" /D "USEGLOBALIME" /Yu"stdafx.h" /FD /GF /c 102 +# SUBTRACT BASE CPP /Gf 103 +# ADD CPP /nologo /Gr /Zp4 /W3 /Gi /Og /Oi /Os /Oy /Ob1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "SUPERTINY" /D "USEGLOBALIME" /D "UNICODE" /D "_UNICODE" /Yu"stdafx.h" /FD /GF /c 104 +# SUBTRACT CPP /Gf 105 +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 106 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 107 +# ADD BASE RSC /l 0x411 /d "NDEBUG" 108 +# ADD RSC /l 0x411 /d "NDEBUG" 109 +BSC32=bscmake.exe 110 +# ADD BASE BSC32 /nologo 111 +# ADD BSC32 /nologo 112 +LINK32=link.exe 113 +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib imm32.lib /nologo /subsystem:windows /map /machine:I386 /nodefaultlib /out:"release/GreenPad.exe" 114 +# SUBTRACT BASE LINK32 /pdb:none 115 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib imm32.lib /nologo /subsystem:windows /map /machine:I386 /nodefaultlib /out:"release/GreenPad.exe" 116 +# SUBTRACT LINK32 /pdb:none 117 + 118 +!ENDIF 119 + 120 +# Begin Target 121 + 122 +# Name "kilib - Win32 Release" 123 +# Name "kilib - Win32 Debug" 124 +# Name "kilib - Win32 Unicode Release" 125 +# Begin Group "Source Files" 126 + 127 +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" 128 +# Begin Source File 129 + 130 +SOURCE=.\ConfigManager.cpp 131 +# End Source File 132 +# Begin Source File 133 + 134 +SOURCE=.\GpMain.cpp 135 +# End Source File 136 +# Begin Source File 137 + 138 +SOURCE=.\OpenSaveDlg.cpp 139 +# End Source File 140 +# Begin Source File 141 + 142 +SOURCE=.\RSearch.cpp 143 +# End Source File 144 +# Begin Source File 145 + 146 +SOURCE=.\Search.cpp 147 +# End Source File 148 +# End Group 149 +# Begin Group "Header Files" 150 + 151 +# PROP Default_Filter "h;hpp;hxx;hm;inl" 152 +# Begin Source File 153 + 154 +SOURCE=.\ConfigManager.h 155 +# End Source File 156 +# Begin Source File 157 + 158 +SOURCE=.\GpMain.h 159 +# End Source File 160 +# Begin Source File 161 + 162 +SOURCE=.\NSearch.h 163 +# End Source File 164 +# Begin Source File 165 + 166 +SOURCE=.\OpenSaveDlg.h 167 +# End Source File 168 +# Begin Source File 169 + 170 +SOURCE=.\RSearch.h 171 +# End Source File 172 +# Begin Source File 173 + 174 +SOURCE=.\Search.h 175 +# End Source File 176 +# End Group 177 +# Begin Group "Resource Files" 178 + 179 +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" 180 +# Begin Source File 181 + 182 +SOURCE=.\rsrc\exefile.ico 183 +# End Source File 184 +# Begin Source File 185 + 186 +SOURCE=.\rsrc\gp_rsrc.rc 187 +# End Source File 188 +# Begin Source File 189 + 190 +SOURCE=.\rsrc\manifest.xml 191 +# End Source File 192 +# Begin Source File 193 + 194 +SOURCE=.\rsrc\resource.h 195 +# End Source File 196 +# End Group 197 +# Begin Group "kilib" 198 + 199 +# PROP Default_Filter "" 200 +# Begin Group "Source" 201 + 202 +# PROP Default_Filter "cpp" 203 +# Begin Source File 204 + 205 +SOURCE=.\kilib\app.cpp 206 +# End Source File 207 +# Begin Source File 208 + 209 +SOURCE=.\kilib\cmdarg.cpp 210 +# End Source File 211 +# Begin Source File 212 + 213 +SOURCE=.\kilib\ctrl.cpp 214 +# End Source File 215 +# Begin Source File 216 + 217 +SOURCE=.\kilib\file.cpp 218 +# End Source File 219 +# Begin Source File 220 + 221 +SOURCE=.\kilib\find.cpp 222 +# End Source File 223 +# Begin Source File 224 + 225 +SOURCE=.\kilib\log.cpp 226 +# End Source File 227 +# Begin Source File 228 + 229 +SOURCE=.\kilib\memory.cpp 230 +# End Source File 231 +# Begin Source File 232 + 233 +SOURCE=.\kilib\path.cpp 234 +# End Source File 235 +# Begin Source File 236 + 237 +SOURCE=.\kilib\registry.cpp 238 +# End Source File 239 +# Begin Source File 240 + 241 +SOURCE=.\kilib\stdafx.cpp 242 +# ADD CPP /Yc"stdafx.h" 243 +# End Source File 244 +# Begin Source File 245 + 246 +SOURCE=.\kilib\string.cpp 247 +# End Source File 248 +# Begin Source File 249 + 250 +SOURCE=.\kilib\textfile.cpp 251 +# End Source File 252 +# Begin Source File 253 + 254 +SOURCE=.\kilib\thread.cpp 255 +# End Source File 256 +# Begin Source File 257 + 258 +SOURCE=.\kilib\window.cpp 259 +# End Source File 260 +# Begin Source File 261 + 262 +SOURCE=.\kilib\winutil.cpp 263 +# End Source File 264 +# End Group 265 +# Begin Group "Header" 266 + 267 +# PROP Default_Filter "h" 268 +# Begin Source File 269 + 270 +SOURCE=.\kilib\app.h 271 +# End Source File 272 +# Begin Source File 273 + 274 +SOURCE=.\kilib\cmdarg.h 275 +# End Source File 276 +# Begin Source File 277 + 278 +SOURCE=.\kilib\ctrl.h 279 +# End Source File 280 +# Begin Source File 281 + 282 +SOURCE=.\kilib\file.h 283 +# End Source File 284 +# Begin Source File 285 + 286 +SOURCE=.\kilib\find.h 287 +# End Source File 288 +# Begin Source File 289 + 290 +SOURCE=.\kilib\log.h 291 +# End Source File 292 +# Begin Source File 293 + 294 +SOURCE=.\kilib\memory.h 295 +# End Source File 296 +# Begin Source File 297 + 298 +SOURCE=.\kilib\path.h 299 +# End Source File 300 +# Begin Source File 301 + 302 +SOURCE=.\kilib\registry.h 303 +# End Source File 304 +# Begin Source File 305 + 306 +SOURCE=.\kilib\string.h 307 +# End Source File 308 +# Begin Source File 309 + 310 +SOURCE=.\kilib\textfile.h 311 +# End Source File 312 +# Begin Source File 313 + 314 +SOURCE=.\kilib\thread.h 315 +# End Source File 316 +# Begin Source File 317 + 318 +SOURCE=.\kilib\types.h 319 +# End Source File 320 +# Begin Source File 321 + 322 +SOURCE=.\kilib\window.h 323 +# End Source File 324 +# Begin Source File 325 + 326 +SOURCE=.\kilib\winutil.h 327 +# End Source File 328 +# End Group 329 +# Begin Group "KTL" 330 + 331 +# PROP Default_Filter "" 332 +# Begin Source File 333 + 334 +SOURCE=.\kilib\ktlaptr.h 335 +# End Source File 336 +# Begin Source File 337 + 338 +SOURCE=.\kilib\ktlarray.h 339 +# End Source File 340 +# Begin Source File 341 + 342 +SOURCE=.\kilib\ktlgap.h 343 +# End Source File 344 +# End Group 345 +# Begin Source File 346 + 347 +SOURCE=.\kilib\kilib.h 348 +# End Source File 349 +# Begin Source File 350 + 351 +SOURCE=.\kilib\stdafx.h 352 +# End Source File 353 +# End Group 354 +# Begin Group "editwing" 355 + 356 +# PROP Default_Filter "" 357 +# Begin Group "public" 358 + 359 +# PROP Default_Filter "" 360 +# Begin Source File 361 + 362 +SOURCE=.\editwing\ewCommon.h 363 +# End Source File 364 +# Begin Source File 365 + 366 +SOURCE=.\editwing\ewCtrl1.h 367 +# End Source File 368 +# Begin Source File 369 + 370 +SOURCE=.\editwing\ewDoc.h 371 +# End Source File 372 +# Begin Source File 373 + 374 +SOURCE=.\editwing\ewView.h 375 +# End Source File 376 +# End Group 377 +# Begin Group "private" 378 + 379 +# PROP Default_Filter "" 380 +# Begin Source File 381 + 382 +SOURCE=.\editwing\ip_ctrl1.cpp 383 +# End Source File 384 +# Begin Source File 385 + 386 +SOURCE=.\editwing\ip_cursor.cpp 387 +# End Source File 388 +# Begin Source File 389 + 390 +SOURCE=.\editwing\ip_doc.h 391 +# End Source File 392 +# Begin Source File 393 + 394 +SOURCE=.\editwing\ip_draw.cpp 395 +# End Source File 396 +# Begin Source File 397 + 398 +SOURCE=.\editwing\ip_parse.cpp 399 +# End Source File 400 +# Begin Source File 401 + 402 +SOURCE=.\editwing\ip_scroll.cpp 403 +# End Source File 404 +# Begin Source File 405 + 406 +SOURCE=.\editwing\ip_text.cpp 407 +# End Source File 408 +# Begin Source File 409 + 410 +SOURCE=.\editwing\ip_view.h 411 +# End Source File 412 +# Begin Source File 413 + 414 +SOURCE=.\editwing\ip_wrap.cpp 415 +# End Source File 416 +# End Group 417 +# Begin Source File 418 + 419 +SOURCE=.\editwing\editwing.h 420 +# End Source File 421 +# End Group 422 +# End Target 423 +# End Project
Added kilib.dsw version [c4ca1b453ed7697f]
1 +Microsoft Developer Studio Workspace File, Format Version 6.00 2 +# 警告: このワークスペース ファイル を編集または削除しないでください! 3 + 4 +############################################################################### 5 + 6 +Project: "kilib"=.\kilib.dsp - Package Owner=<4> 7 + 8 +Package=<5> 9 +{{{ 10 +}}} 11 + 12 +Package=<4> 13 +{{{ 14 +}}} 15 + 16 +############################################################################### 17 + 18 +Global: 19 + 20 +Package=<5> 21 +{{{ 22 +}}} 23 + 24 +Package=<3> 25 +{{{ 26 +}}} 27 + 28 +############################################################################### 29 +
Added kilib.sln version [ccff6918dad9ce62]
1 +サソ 2 +Microsoft Visual Studio Solution File, Format Version 9.00 3 +# Visual Studio 2005 4 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "kilib", "kilib.vcproj", "{910E868F-4E52-4D55-9C4E-4563F5934517}" 5 +EndProject 6 +Global 7 + GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 + Debug|Win32 = Debug|Win32 9 + Release|Win32 = Release|Win32 10 + Unicode Release|Win32 = Unicode Release|Win32 11 + EndGlobalSection 12 + GlobalSection(ProjectConfigurationPlatforms) = postSolution 13 + {910E868F-4E52-4D55-9C4E-4563F5934517}.Debug|Win32.ActiveCfg = Debug|Win32 14 + {910E868F-4E52-4D55-9C4E-4563F5934517}.Debug|Win32.Build.0 = Debug|Win32 15 + {910E868F-4E52-4D55-9C4E-4563F5934517}.Release|Win32.ActiveCfg = Release|Win32 16 + {910E868F-4E52-4D55-9C4E-4563F5934517}.Release|Win32.Build.0 = Release|Win32 17 + {910E868F-4E52-4D55-9C4E-4563F5934517}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 18 + {910E868F-4E52-4D55-9C4E-4563F5934517}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 19 + EndGlobalSection 20 + GlobalSection(SolutionProperties) = preSolution 21 + HideSolutionNode = FALSE 22 + EndGlobalSection 23 +EndGlobal
Added kilib.vcproj version [29090dda11bda79d]
1 +<?xml version="1.0" encoding="shift_jis"?> 2 +<VisualStudioProject 3 + ProjectType="Visual C++" 4 + Version="8.00" 5 + Name="kilib" 6 + ProjectGUID="{910E868F-4E52-4D55-9C4E-4563F5934517}" 7 + RootNamespace="kilib" 8 + > 9 + <Platforms> 10 + <Platform 11 + Name="Win32" 12 + /> 13 + </Platforms> 14 + <ToolFiles> 15 + </ToolFiles> 16 + <Configurations> 17 + <Configuration 18 + Name="Unicode Release|Win32" 19 + OutputDirectory=".\release" 20 + IntermediateDirectory=".\OBJ/vc/reluni" 21 + ConfigurationType="1" 22 + InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" 23 + UseOfMFC="0" 24 + ATLMinimizesCRunTimeLibraryUsage="false" 25 + CharacterSet="1" 26 + WholeProgramOptimization="1" 27 + > 28 + <Tool 29 + Name="VCPreBuildEventTool" 30 + /> 31 + <Tool 32 + Name="VCCustomBuildTool" 33 + /> 34 + <Tool 35 + Name="VCXMLDataGeneratorTool" 36 + /> 37 + <Tool 38 + Name="VCWebServiceProxyGeneratorTool" 39 + /> 40 + <Tool 41 + Name="VCMIDLTool" 42 + PreprocessorDefinitions="NDEBUG" 43 + MkTypLibCompatible="true" 44 + SuppressStartupBanner="true" 45 + TargetEnvironment="1" 46 + TypeLibraryName=".\release/kilib.tlb" 47 + /> 48 + <Tool 49 + Name="VCCLCompilerTool" 50 + Optimization="3" 51 + InlineFunctionExpansion="1" 52 + EnableIntrinsicFunctions="true" 53 + FavorSizeOrSpeed="2" 54 + OmitFramePointers="true" 55 + EnableFiberSafeOptimizations="true" 56 + WholeProgramOptimization="false" 57 + PreprocessorDefinitions="WIN32,NDEBUG,_WINDOWS,UNICODE,SUPERTINY,USEGLOBALIME," 58 + StringPooling="true" 59 + ExceptionHandling="0" 60 + RuntimeLibrary="0" 61 + StructMemberAlignment="0" 62 + BufferSecurityCheck="false" 63 + EnableFunctionLevelLinking="true" 64 + TreatWChar_tAsBuiltInType="true" 65 + RuntimeTypeInfo="false" 66 + UsePrecompiledHeader="2" 67 + PrecompiledHeaderThrough="stdafx.h" 68 + PrecompiledHeaderFile=".\OBJ/vc/reluni/kilib.pch" 69 + AssemblerListingLocation=".\OBJ/vc/reluni/" 70 + ObjectFile=".\OBJ/vc/reluni/" 71 + ProgramDataBaseFileName=".\OBJ/vc/reluni/" 72 + WarningLevel="3" 73 + SuppressStartupBanner="true" 74 + DebugInformationFormat="0" 75 + CallingConvention="1" 76 + /> 77 + <Tool 78 + Name="VCManagedResourceCompilerTool" 79 + /> 80 + <Tool 81 + Name="VCResourceCompilerTool" 82 + PreprocessorDefinitions="NDEBUG" 83 + Culture="1041" 84 + /> 85 + <Tool 86 + Name="VCPreLinkEventTool" 87 + /> 88 + <Tool 89 + Name="VCLinkerTool" 90 + AdditionalOptions="/MACHINE:I386 /merge:.rdata=.text" 91 + AdditionalDependencies="kernel32.lib user32.lib comctl32.lib shell32.lib gdi32.lib comctl32.lib comdlg32.lib ole32.lib advapi32.lib imm32.lib uuid.lib" 92 + OutputFile="release/GreenPad.exe" 93 + LinkIncremental="1" 94 + SuppressStartupBanner="true" 95 + GenerateManifest="false" 96 + IgnoreAllDefaultLibraries="true" 97 + GenerateDebugInformation="false" 98 + ProgramDatabaseFile=".\release/GreenPad.pdb" 99 + GenerateMapFile="true" 100 + MapFileName=".\OBJ/vc/reluni/GreenPad.map" 101 + SubSystem="2" 102 + OptimizeReferences="2" 103 + EnableCOMDATFolding="2" 104 + OptimizeForWindows98="1" 105 + LinkTimeCodeGeneration="0" 106 + /> 107 + <Tool 108 + Name="VCALinkTool" 109 + /> 110 + <Tool 111 + Name="VCManifestTool" 112 + /> 113 + <Tool 114 + Name="VCXDCMakeTool" 115 + /> 116 + <Tool 117 + Name="VCBscMakeTool" 118 + /> 119 + <Tool 120 + Name="VCFxCopTool" 121 + /> 122 + <Tool 123 + Name="VCAppVerifierTool" 124 + /> 125 + <Tool 126 + Name="VCWebDeploymentTool" 127 + /> 128 + <Tool 129 + Name="VCPostBuildEventTool" 130 + /> 131 + </Configuration> 132 + <Configuration 133 + Name="Debug|Win32" 134 + OutputDirectory=".\OBJ" 135 + IntermediateDirectory=".\OBJ/vc/debug" 136 + ConfigurationType="1" 137 + InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" 138 + UseOfMFC="0" 139 + ATLMinimizesCRunTimeLibraryUsage="false" 140 + CharacterSet="1" 141 + > 142 + <Tool 143 + Name="VCPreBuildEventTool" 144 + /> 145 + <Tool 146 + Name="VCCustomBuildTool" 147 + /> 148 + <Tool 149 + Name="VCXMLDataGeneratorTool" 150 + /> 151 + <Tool 152 + Name="VCWebServiceProxyGeneratorTool" 153 + /> 154 + <Tool 155 + Name="VCMIDLTool" 156 + PreprocessorDefinitions="_DEBUG" 157 + MkTypLibCompatible="true" 158 + SuppressStartupBanner="true" 159 + TargetEnvironment="1" 160 + TypeLibraryName=".\OBJ/kilib.tlb" 161 + /> 162 + <Tool 163 + Name="VCCLCompilerTool" 164 + Optimization="0" 165 + PreprocessorDefinitions="WIN32,_DEBUG,_WINDOWS,SUPERTINY,USEGLOBALIME" 166 + RuntimeLibrary="1" 167 + UsePrecompiledHeader="2" 168 + PrecompiledHeaderThrough="stdafx.h" 169 + PrecompiledHeaderFile=".\OBJ/vc/debug/kilib.pch" 170 + AssemblerListingLocation=".\OBJ/vc/debug/" 171 + ObjectFile=".\OBJ/vc/debug/" 172 + ProgramDataBaseFileName=".\OBJ/vc/debug/" 173 + BrowseInformation="1" 174 + WarningLevel="3" 175 + SuppressStartupBanner="true" 176 + DebugInformationFormat="4" 177 + /> 178 + <Tool 179 + Name="VCManagedResourceCompilerTool" 180 + /> 181 + <Tool 182 + Name="VCResourceCompilerTool" 183 + PreprocessorDefinitions="_DEBUG" 184 + Culture="1041" 185 + /> 186 + <Tool 187 + Name="VCPreLinkEventTool" 188 + /> 189 + <Tool 190 + Name="VCLinkerTool" 191 + AdditionalOptions="/MACHINE:I386" 192 + AdditionalDependencies="kernel32.lib user32.lib comctl32.lib shell32.lib gdi32.lib comctl32.lib comdlg32.lib ole32.lib advapi32.lib imm32.lib uuid.lib" 193 + OutputFile="OBJ/GreenPad.exe" 194 + LinkIncremental="2" 195 + SuppressStartupBanner="true" 196 + GenerateManifest="false" 197 + IgnoreAllDefaultLibraries="false" 198 + GenerateDebugInformation="true" 199 + ProgramDatabaseFile=".\OBJ/GreenPad.pdb" 200 + SubSystem="2" 201 + /> 202 + <Tool 203 + Name="VCALinkTool" 204 + /> 205 + <Tool 206 + Name="VCManifestTool" 207 + /> 208 + <Tool 209 + Name="VCXDCMakeTool" 210 + /> 211 + <Tool 212 + Name="VCBscMakeTool" 213 + /> 214 + <Tool 215 + Name="VCFxCopTool" 216 + /> 217 + <Tool 218 + Name="VCAppVerifierTool" 219 + /> 220 + <Tool 221 + Name="VCWebDeploymentTool" 222 + /> 223 + <Tool 224 + Name="VCPostBuildEventTool" 225 + /> 226 + </Configuration> 227 + <Configuration 228 + Name="Release|Win32" 229 + OutputDirectory=".\release" 230 + IntermediateDirectory=".\OBJ/vc/rel" 231 + ConfigurationType="1" 232 + InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" 233 + UseOfMFC="0" 234 + ATLMinimizesCRunTimeLibraryUsage="false" 235 + CharacterSet="2" 236 + WholeProgramOptimization="1" 237 + > 238 + <Tool 239 + Name="VCPreBuildEventTool" 240 + /> 241 + <Tool 242 + Name="VCCustomBuildTool" 243 + /> 244 + <Tool 245 + Name="VCXMLDataGeneratorTool" 246 + /> 247 + <Tool 248 + Name="VCWebServiceProxyGeneratorTool" 249 + /> 250 + <Tool 251 + Name="VCMIDLTool" 252 + PreprocessorDefinitions="NDEBUG" 253 + MkTypLibCompatible="true" 254 + SuppressStartupBanner="true" 255 + TargetEnvironment="1" 256 + TypeLibraryName=".\release/kilib.tlb" 257 + /> 258 + <Tool 259 + Name="VCCLCompilerTool" 260 + Optimization="3" 261 + InlineFunctionExpansion="1" 262 + EnableIntrinsicFunctions="true" 263 + FavorSizeOrSpeed="2" 264 + OmitFramePointers="true" 265 + EnableFiberSafeOptimizations="true" 266 + WholeProgramOptimization="false" 267 + PreprocessorDefinitions="WIN32,NDEBUG,_WINDOWS,SUPERTINY,USE_ORIGINAL_MEMMAN,USEGLOBALIME" 268 + StringPooling="true" 269 + ExceptionHandling="0" 270 + RuntimeLibrary="0" 271 + StructMemberAlignment="0" 272 + BufferSecurityCheck="false" 273 + EnableFunctionLevelLinking="true" 274 + RuntimeTypeInfo="false" 275 + UsePrecompiledHeader="2" 276 + PrecompiledHeaderThrough="stdafx.h" 277 + PrecompiledHeaderFile=".\OBJ/vc/rel/kilib.pch" 278 + AssemblerListingLocation=".\OBJ/vc/rel/" 279 + ObjectFile=".\OBJ/vc/rel/" 280 + ProgramDataBaseFileName=".\OBJ/vc/rel/" 281 + WarningLevel="3" 282 + SuppressStartupBanner="true" 283 + Detect64BitPortabilityProblems="false" 284 + DebugInformationFormat="0" 285 + CallingConvention="1" 286 + /> 287 + <Tool 288 + Name="VCManagedResourceCompilerTool" 289 + /> 290 + <Tool 291 + Name="VCResourceCompilerTool" 292 + PreprocessorDefinitions="NDEBUG" 293 + Culture="1041" 294 + /> 295 + <Tool 296 + Name="VCPreLinkEventTool" 297 + /> 298 + <Tool 299 + Name="VCLinkerTool" 300 + AdditionalOptions="/MACHINE:I386 /merge:.rdata=.text" 301 + AdditionalDependencies="kernel32.lib user32.lib comctl32.lib shell32.lib gdi32.lib comctl32.lib comdlg32.lib ole32.lib advapi32.lib imm32.lib uuid.lib" 302 + OutputFile="release/GreenPad.exe" 303 + LinkIncremental="1" 304 + SuppressStartupBanner="true" 305 + GenerateManifest="false" 306 + IgnoreAllDefaultLibraries="true" 307 + GenerateDebugInformation="false" 308 + ProgramDatabaseFile=".\release/GreenPad.pdb" 309 + GenerateMapFile="true" 310 + MapFileName=".\OBJ/vc/rel/GreenPad.map" 311 + SubSystem="2" 312 + OptimizeReferences="2" 313 + EnableCOMDATFolding="2" 314 + OptimizeForWindows98="1" 315 + LinkTimeCodeGeneration="0" 316 + EntryPointSymbol="" 317 + /> 318 + <Tool 319 + Name="VCALinkTool" 320 + /> 321 + <Tool 322 + Name="VCManifestTool" 323 + EmbedManifest="true" 324 + /> 325 + <Tool 326 + Name="VCXDCMakeTool" 327 + /> 328 + <Tool 329 + Name="VCBscMakeTool" 330 + /> 331 + <Tool 332 + Name="VCFxCopTool" 333 + /> 334 + <Tool 335 + Name="VCAppVerifierTool" 336 + /> 337 + <Tool 338 + Name="VCWebDeploymentTool" 339 + /> 340 + <Tool 341 + Name="VCPostBuildEventTool" 342 + /> 343 + </Configuration> 344 + </Configurations> 345 + <References> 346 + </References> 347 + <Files> 348 + <Filter 349 + Name="Source Files" 350 + Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" 351 + > 352 + <File 353 + RelativePath=".\ConfigManager.cpp" 354 + > 355 + </File> 356 + <File 357 + RelativePath=".\GpMain.cpp" 358 + > 359 + </File> 360 + <File 361 + RelativePath="kilib\log.cpp" 362 + > 363 + </File> 364 + <File 365 + RelativePath=".\OpenSaveDlg.cpp" 366 + > 367 + </File> 368 + <File 369 + RelativePath=".\RSearch.cpp" 370 + > 371 + </File> 372 + <File 373 + RelativePath=".\Search.cpp" 374 + > 375 + </File> 376 + </Filter> 377 + <Filter 378 + Name="Header Files" 379 + Filter="h;hpp;hxx;hm;inl" 380 + > 381 + <File 382 + RelativePath=".\ConfigManager.h" 383 + > 384 + </File> 385 + <File 386 + RelativePath=".\GpMain.h" 387 + > 388 + </File> 389 + <File 390 + RelativePath="kilib\log.h" 391 + > 392 + </File> 393 + <File 394 + RelativePath=".\NSearch.h" 395 + > 396 + </File> 397 + <File 398 + RelativePath=".\OpenSaveDlg.h" 399 + > 400 + </File> 401 + <File 402 + RelativePath=".\RSearch.h" 403 + > 404 + </File> 405 + <File 406 + RelativePath=".\Search.h" 407 + > 408 + </File> 409 + </Filter> 410 + <Filter 411 + Name="Resource Files" 412 + Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" 413 + > 414 + <File 415 + RelativePath=".\rsrc\exefile.ico" 416 + > 417 + </File> 418 + <File 419 + RelativePath=".\rsrc\gp_rsrc.rc" 420 + > 421 + </File> 422 + <File 423 + RelativePath=".\rsrc\manifest.xml" 424 + > 425 + </File> 426 + <File 427 + RelativePath=".\rsrc\resource.h" 428 + > 429 + </File> 430 + </Filter> 431 + <Filter 432 + Name="kilib" 433 + > 434 + <File 435 + RelativePath=".\kilib\kilib.h" 436 + > 437 + </File> 438 + <File 439 + RelativePath=".\kilib\stdafx.h" 440 + > 441 + </File> 442 + <Filter 443 + Name="Source" 444 + Filter="cpp" 445 + > 446 + <File 447 + RelativePath=".\kilib\app.cpp" 448 + > 449 + </File> 450 + <File 451 + RelativePath=".\kilib\cmdarg.cpp" 452 + > 453 + </File> 454 + <File 455 + RelativePath=".\kilib\ctrl.cpp" 456 + > 457 + </File> 458 + <File 459 + RelativePath=".\kilib\file.cpp" 460 + > 461 + </File> 462 + <File 463 + RelativePath=".\kilib\find.cpp" 464 + > 465 + </File> 466 + <File 467 + RelativePath=".\kilib\memory.cpp" 468 + > 469 + <FileConfiguration 470 + Name="Unicode Release|Win32" 471 + > 472 + <Tool 473 + Name="VCCLCompilerTool" 474 + Optimization="1" 475 + EnableIntrinsicFunctions="false" 476 + WholeProgramOptimization="false" 477 + /> 478 + </FileConfiguration> 479 + <FileConfiguration 480 + Name="Release|Win32" 481 + > 482 + <Tool 483 + Name="VCCLCompilerTool" 484 + Optimization="1" 485 + EnableIntrinsicFunctions="false" 486 + /> 487 + </FileConfiguration> 488 + </File> 489 + <File 490 + RelativePath=".\kilib\path.cpp" 491 + > 492 + </File> 493 + <File 494 + RelativePath=".\kilib\registry.cpp" 495 + > 496 + </File> 497 + <File 498 + RelativePath=".\kilib\stdafx.cpp" 499 + > 500 + <FileConfiguration 501 + Name="Unicode Release|Win32" 502 + > 503 + <Tool 504 + Name="VCCLCompilerTool" 505 + EnableIntrinsicFunctions="true" 506 + UsePrecompiledHeader="1" 507 + /> 508 + </FileConfiguration> 509 + <FileConfiguration 510 + Name="Debug|Win32" 511 + > 512 + <Tool 513 + Name="VCCLCompilerTool" 514 + UsePrecompiledHeader="1" 515 + /> 516 + </FileConfiguration> 517 + <FileConfiguration 518 + Name="Release|Win32" 519 + > 520 + <Tool 521 + Name="VCCLCompilerTool" 522 + UsePrecompiledHeader="1" 523 + /> 524 + </FileConfiguration> 525 + </File> 526 + <File 527 + RelativePath=".\kilib\string.cpp" 528 + > 529 + </File> 530 + <File 531 + RelativePath=".\kilib\textfile.cpp" 532 + > 533 + </File> 534 + <File 535 + RelativePath=".\kilib\thread.cpp" 536 + > 537 + </File> 538 + <File 539 + RelativePath=".\kilib\window.cpp" 540 + > 541 + </File> 542 + <File 543 + RelativePath=".\kilib\winutil.cpp" 544 + > 545 + </File> 546 + </Filter> 547 + <Filter 548 + Name="Header" 549 + Filter="h" 550 + > 551 + <File 552 + RelativePath=".\kilib\app.h" 553 + > 554 + </File> 555 + <File 556 + RelativePath=".\kilib\cmdarg.h" 557 + > 558 + </File> 559 + <File 560 + RelativePath=".\kilib\ctrl.h" 561 + > 562 + </File> 563 + <File 564 + RelativePath=".\kilib\file.h" 565 + > 566 + </File> 567 + <File 568 + RelativePath=".\kilib\find.h" 569 + > 570 + </File> 571 + <File 572 + RelativePath=".\kilib\memory.h" 573 + > 574 + </File> 575 + <File 576 + RelativePath=".\kilib\path.h" 577 + > 578 + </File> 579 + <File 580 + RelativePath=".\kilib\registry.h" 581 + > 582 + </File> 583 + <File 584 + RelativePath=".\kilib\string.h" 585 + > 586 + </File> 587 + <File 588 + RelativePath=".\kilib\textfile.h" 589 + > 590 + </File> 591 + <File 592 + RelativePath=".\kilib\thread.h" 593 + > 594 + </File> 595 + <File 596 + RelativePath=".\kilib\types.h" 597 + > 598 + </File> 599 + <File 600 + RelativePath=".\kilib\window.h" 601 + > 602 + </File> 603 + <File 604 + RelativePath=".\kilib\winutil.h" 605 + > 606 + </File> 607 + </Filter> 608 + <Filter 609 + Name="KTL" 610 + > 611 + <File 612 + RelativePath=".\kilib\ktlaptr.h" 613 + > 614 + </File> 615 + <File 616 + RelativePath=".\kilib\ktlarray.h" 617 + > 618 + </File> 619 + <File 620 + RelativePath=".\kilib\ktlgap.h" 621 + > 622 + </File> 623 + </Filter> 624 + </Filter> 625 + <Filter 626 + Name="editwing" 627 + > 628 + <File 629 + RelativePath=".\editwing\editwing.h" 630 + > 631 + </File> 632 + <Filter 633 + Name="public" 634 + > 635 + <File 636 + RelativePath=".\editwing\ewCommon.h" 637 + > 638 + </File> 639 + <File 640 + RelativePath=".\editwing\ewCtrl1.h" 641 + > 642 + </File> 643 + <File 644 + RelativePath=".\editwing\ewDoc.h" 645 + > 646 + </File> 647 + <File 648 + RelativePath=".\editwing\ewView.h" 649 + > 650 + </File> 651 + </Filter> 652 + <Filter 653 + Name="private" 654 + > 655 + <File 656 + RelativePath=".\editwing\ip_ctrl1.cpp" 657 + > 658 + </File> 659 + <File 660 + RelativePath=".\editwing\ip_cursor.cpp" 661 + > 662 + </File> 663 + <File 664 + RelativePath=".\editwing\ip_doc.h" 665 + > 666 + </File> 667 + <File 668 + RelativePath=".\editwing\ip_draw.cpp" 669 + > 670 + </File> 671 + <File 672 + RelativePath=".\editwing\ip_parse.cpp" 673 + > 674 + </File> 675 + <File 676 + RelativePath=".\editwing\ip_scroll.cpp" 677 + > 678 + </File> 679 + <File 680 + RelativePath=".\editwing\ip_text.cpp" 681 + > 682 + </File> 683 + <File 684 + RelativePath=".\editwing\ip_view.h" 685 + > 686 + </File> 687 + <File 688 + RelativePath=".\editwing\ip_wrap.cpp" 689 + > 690 + </File> 691 + </Filter> 692 + </Filter> 693 + </Files> 694 + <Globals> 695 + </Globals> 696 +</VisualStudioProject>
Added kilib/app.cpp version [280129b06e0f3905]
1 +#include "stdafx.h" 2 +#include "app.h" 3 +#include "log.h" 4 +#include "memory.h" 5 +#include "thread.h" 6 +#include "window.h" 7 +#include "string.h" 8 +using namespace ki; 9 + 10 + 11 + 12 +//========================================================================= 13 + 14 +App* App::pUniqueInstance_; 15 + 16 +inline App::App() 17 + : exitcode_ (-1) 18 + , loadedModule_(0) 19 + , hInst_ (::GetModuleHandle(NULL)) 20 +{ 21 + // 唯一のインスタンスは私です。 22 + pUniqueInstance_ = this; 23 +} 24 + 25 +#pragma warning( disable : 4722 ) // 警告:デストラクタに値が戻りません 26 +App::~App() 27 +{ 28 + // ロード済みモジュールがあれば閉じておく 29 + if( loadedModule_ & COM ) 30 + ::CoUninitialize(); 31 + if( loadedModule_ & OLE ) 32 + ::OleUninitialize(); 33 + 34 + // 終〜了〜 35 + ::ExitProcess( exitcode_ ); 36 +} 37 + 38 +inline void App::SetExitCode( int code ) 39 +{ 40 + // 終了コードを設定 41 + exitcode_ = code; 42 +} 43 + 44 +void App::InitModule( imflag what ) 45 +{ 46 + // 初期化済みでなければ初期化する 47 + if( !(loadedModule_ & what) ) 48 + switch( what ) 49 + { 50 + case CTL: ::InitCommonControls(); break; 51 + case COM: ::CoInitialize( NULL ); break; 52 + case OLE: ::OleInitialize( NULL );break; 53 + } 54 + 55 + // 今回初期化したモノを記憶 56 + loadedModule_ |= what; 57 +} 58 + 59 +void App::Exit( int code ) 60 +{ 61 + // 終了コードを設定して 62 + SetExitCode( code ); 63 + 64 + // 自殺 65 + this->~App(); 66 +} 67 + 68 + 69 + 70 +//------------------------------------------------------------------------- 71 + 72 +const OSVERSIONINFO& App::osver() 73 +{ 74 + static OSVERSIONINFO s_osVer; 75 + if( s_osVer.dwOSVersionInfoSize == 0 ) 76 + { 77 + // 初回だけは情報取得 78 + s_osVer.dwOSVersionInfoSize = sizeof( s_osVer ); 79 + ::GetVersionEx( &s_osVer ); 80 + } 81 + return s_osVer; 82 +} 83 + 84 +bool App::isNewTypeWindows() 85 +{ 86 + static const OSVERSIONINFO& v = osver(); 87 + return ( 88 + ( v.dwPlatformId==VER_PLATFORM_WIN32_NT && v.dwMajorVersion>=5 ) 89 + || ( v.dwPlatformId==VER_PLATFORM_WIN32_WINDOWS && 90 + v.dwMajorVersion*100+v.dwMinorVersion>=410 ) 91 + ); 92 +} 93 + 94 +bool App::isWin95() 95 +{ 96 + static const OSVERSIONINFO& v = osver(); 97 + return ( 98 + v.dwPlatformId==VER_PLATFORM_WIN32_WINDOWS && 99 + v.dwMajorVersion==4 && 100 + v.dwMinorVersion==0 101 + ); 102 +} 103 + 104 +bool App::isNT() 105 +{ 106 + static const OSVERSIONINFO& v = osver(); 107 + return v.dwPlatformId==VER_PLATFORM_WIN32_NT; 108 +} 109 + 110 + 111 + 112 +//========================================================================= 113 + 114 +extern int kmain(); 115 + 116 +namespace ki 117 +{ 118 + void APIENTRY Startup() 119 + { 120 + // Startup : 121 + // プログラム開始すると、真っ先にここに来ます。 122 + 123 + // C++のローカルオブジェクトの破棄順序の仕様に 124 + // 自信がないので(^^;、スコープを利用して順番を強制 125 + // たぶん宣言の逆順だとは思うんだけど… 126 + 127 + LOGGER( "StartUp" ); 128 + App myApp; 129 + { 130 + LOGGER( "StartUp app ok" ); 131 + ThreadManager myThr; 132 + { 133 + LOGGER( "StartUp thr ok" ); 134 + MemoryManager myMem; 135 + { 136 + LOGGER( "StartUp mem ok" ); 137 + IMEManager myIME; 138 + { 139 + LOGGER( "StartUp ime ok" ); 140 + String::LibInit(); 141 + { 142 + const int r = kmain(); 143 + myApp.SetExitCode( r ); 144 + } 145 + } 146 + } 147 + } 148 + } 149 + } 150 +} 151 + 152 +#ifdef SUPERTINY 153 + 154 + extern "C" int __cdecl _purecall(){return 0;} 155 + #ifdef _DEBUG 156 + int main(){return 0;} 157 + #endif 158 + #pragma comment(linker, "/entry:\"Startup\"") 159 + 160 +#else 161 + 162 + // VS2005でビルドしてもWin95で動くようにするため 163 + #if _MSC_VER >= 1400 164 + extern "C" BOOL WINAPI _imp__IsDebuggerPresent() { return FALSE; } 165 + #endif 166 + 167 + int APIENTRY WinMain( HINSTANCE, HINSTANCE, LPSTR, int ) 168 + { 169 + ki::Startup(); 170 + return 0; 171 + } 172 + 173 +#endif
Added kilib/app.h version [6f13d2b44d31dee8]
1 +#ifndef _KILIB_APP_H_ 2 +#define _KILIB_APP_H_ 3 +#include "types.h" 4 +#include "log.h" 5 +#ifndef __ccdoc__ 6 +namespace ki { 7 +#endif 8 + 9 + 10 + 11 +//========================================================================= 12 +//@{ @pkg ki.Core //@} 13 +//@{ 14 +// アプリケーション全体の統括 15 +// 16 +// アプリ起動/終了用処理を担当します。 17 +// 旧kilibと違って、ユーザー側のアプリケーションクラスを 18 +// ここから派生させることは出来ません。ユーザーのコードは、 19 +// 必ず kmain() というグローバル関数から実行開始されます。 20 +// このAppクラス自体は、主にHINSTANCEの管理を行うだけ。 21 +//@} 22 +//========================================================================= 23 + 24 +class App 25 +{ 26 +public: 27 + 28 + enum imflag { CTL=1, COM=2, OLE=4 }; 29 + 30 + //@{ 31 + // 種々のモジュールを初期化する 32 + // 33 + // これで初期化しておくと、App終了時に自動で 34 + // 終了処理が行われるので簡単便利でございます。 35 + // @param what CTL(コモンコントロール)、COM、OLE 36 + //@} 37 + void InitModule( imflag what ); 38 + 39 + //@{ プロセス強制終了 //@} 40 + void Exit( int code ); 41 + 42 + //@{ リソース //@} 43 + HACCEL LoadAccel( LPCTSTR name ); 44 + 45 + //@{ リソース //@} 46 + HACCEL LoadAccel( UINT id ); 47 + 48 + //@{ リソース //@} 49 + HBITMAP LoadBitmap( LPCTSTR name ); 50 + 51 + //@{ リソース //@} 52 + HBITMAP LoadBitmap( UINT id ); 53 + 54 + //@{ リソース(OBM_XXXX) //@} 55 + HBITMAP LoadOemBitmap( LPCTSTR obm ); 56 + 57 + //@{ リソース //@} 58 + HCURSOR LoadCursor( LPCTSTR name ); 59 + 60 + //@{ リソース //@} 61 + HCURSOR LoadCursor( UINT id ); 62 + 63 + //@{ リソース(IDC_XXXX) //@} 64 + HCURSOR LoadOemCursor( LPCTSTR idc ); 65 + 66 + //@{ リソース //@} 67 + HICON LoadIcon( LPCTSTR name ); 68 + 69 + //@{ リソース //@} 70 + HICON LoadIcon( UINT id ); 71 + 72 + //@{ リソース(IDI_XXXX) //@} 73 + HICON LoadOemIcon( LPCTSTR idi ); 74 + 75 + //@{ リソース //@} 76 + HMENU LoadMenu( LPCTSTR name ); 77 + 78 + //@{ リソース //@} 79 + HMENU LoadMenu( UINT id ); 80 + 81 + //@{ リソース //@} 82 + int LoadString( UINT id, LPTSTR buf, int siz ); 83 + 84 +public: 85 + 86 + //@{ インスタンスハンドル //@} 87 + HINSTANCE hinst() const; 88 + 89 + //@{ Windowsのバージョン //@} 90 + static const OSVERSIONINFO& osver(); 91 + static bool isWin95(); 92 + static bool isNT(); 93 + static bool isNewTypeWindows(); 94 + 95 +private: 96 + 97 + App(); 98 + ~App(); 99 + void SetExitCode( int code ); 100 + 101 +private: 102 + 103 + int exitcode_; 104 + ulong loadedModule_; 105 + const HINSTANCE hInst_; 106 + static App* pUniqueInstance_; 107 + 108 +private: 109 + 110 + friend void APIENTRY Startup(); 111 + friend inline App& app(); 112 + NOCOPY(App); 113 +}; 114 + 115 + 116 + 117 +//------------------------------------------------------------------------- 118 + 119 +//@{ 唯一のアプリ情報オブジェクトを返す //@} 120 +inline App& app() 121 + { return *App::pUniqueInstance_; } 122 + 123 +inline HACCEL App::LoadAccel( LPCTSTR name ) 124 + { return ::LoadAccelerators( hInst_, name ); } 125 + 126 +inline HACCEL App::LoadAccel( UINT id ) 127 + { return ::LoadAccelerators( hInst_, MAKEINTRESOURCE(id) ); } 128 + 129 +inline HBITMAP App::LoadBitmap( LPCTSTR name ) 130 + { return ::LoadBitmap( hInst_, name ); } 131 + 132 +inline HBITMAP App::LoadBitmap( UINT id ) 133 + { return ::LoadBitmap( hInst_, MAKEINTRESOURCE(id) ); } 134 + 135 +inline HBITMAP App::LoadOemBitmap( LPCTSTR obm ) 136 + { return ::LoadBitmap( NULL, obm ); } 137 + 138 +inline HCURSOR App::LoadCursor( LPCTSTR name ) 139 + { return ::LoadCursor( hInst_, name ); } 140 + 141 +inline HCURSOR App::LoadCursor( UINT id ) 142 + { return ::LoadCursor( hInst_, MAKEINTRESOURCE(id) ); } 143 + 144 +inline HCURSOR App::LoadOemCursor( LPCTSTR idc ) 145 + { return ::LoadCursor( NULL, idc ); } 146 + 147 +inline HICON App::LoadIcon( LPCTSTR name ) 148 + { return ::LoadIcon( hInst_, name ); } 149 + 150 +inline HICON App::LoadIcon( UINT id ) 151 + { return ::LoadIcon( hInst_, MAKEINTRESOURCE(id) ); } 152 + 153 +inline HICON App::LoadOemIcon( LPCTSTR idi ) 154 + { return ::LoadIcon( NULL, idi ); } 155 + 156 +inline HMENU App::LoadMenu( LPCTSTR name ) 157 + { return ::LoadMenu( hInst_, name ); } 158 + 159 +inline HMENU App::LoadMenu( UINT id ) 160 + { return ::LoadMenu( hInst_, MAKEINTRESOURCE(id) ); } 161 + 162 +inline int App::LoadString( UINT id, LPTSTR buf, int siz ) 163 + { return ::LoadString( hInst_, id, buf, siz ); } 164 + 165 +inline HINSTANCE App::hinst() const 166 + { return hInst_; } 167 + 168 + 169 + 170 +//========================================================================= 171 + 172 +} // namespace ki 173 +#endif // _KILIB_APP_H_
Added kilib/cmdarg.cpp version [ea1908bbabe7d2df]
1 +#include "stdafx.h" 2 +#include "cmdarg.h" 3 +#include "string.h" 4 +using namespace ki; 5 + 6 + 7 + 8 +//========================================================================= 9 + 10 +Argv::Argv( const TCHAR* cmd ) 11 +{ 12 + TCHAR *p, endc; 13 + 14 + buf_ = (p=new TCHAR[::lstrlen(cmd)+1]); 15 + ::lstrcpy( p, cmd ); 16 + 17 + while( *p != TEXT('\0') ) 18 + { 19 + // 引数を区切る空白をスキップ 20 + while( *p == TEXT(' ') ) 21 + ++p; 22 + 23 + // " だったら、その旨記録してさらに一個進める 24 + if( *p == TEXT('\"') ) 25 + endc=TEXT('\"'), ++p; 26 + else 27 + endc=TEXT(' '); 28 + 29 + // 文字列終端なら終了 30 + if( *p == TEXT('\0') ) 31 + break; 32 + 33 + // 引数リストへ保存 34 + arg_.Add( p ); 35 + 36 + // 引数の終わりへ… 37 + while( *p!=endc && *p!=TEXT('\0') ) 38 + ++p; 39 + 40 + // 終わりは'\0'にすることによって、引数を区切る 41 + if( *p != TEXT('\0') ) 42 + *p++ = TEXT('\0'); 43 + } 44 +}
Added kilib/cmdarg.h version [d905908ecc5c2d31]
1 +#ifndef _KILIB_CMDARG_H_ 2 +#define _KILIB_CMDARG_H_ 3 +#include "types.h" 4 +#include "memory.h" 5 +#include "ktlaptr.h" 6 +#include "ktlarray.h" 7 +#ifndef __ccdoc__ 8 +namespace ki { 9 +#endif 10 + 11 + 12 + 13 +//========================================================================= 14 +//@{ @pkg ki.StdLib //@} 15 +//@{ 16 +// コマンドライン文字列の分割 17 +// 18 +// ただ単にスペースと二重引用符を考慮して区切るだけです。 19 +//@} 20 +//========================================================================= 21 + 22 +class Argv : public Object 23 +{ 24 +public: 25 + 26 + //@{ 指定された文字列を分割する //@} 27 + Argv( const TCHAR* cmd = GetCommandLine() ); 28 + 29 + //@{ 引数Get //@} 30 + const TCHAR* operator[]( ulong i ) const; 31 + 32 + //@{ 引数の個数 //@} 33 + ulong size() const; 34 + 35 +private: 36 + 37 + darr<TCHAR> buf_; 38 + storage<const TCHAR*> arg_; 39 + 40 +private: 41 + 42 + NOCOPY(Argv); 43 +}; 44 + 45 + 46 + 47 +//------------------------------------------------------------------------- 48 +#ifndef __ccdoc__ 49 + 50 +inline const TCHAR* Argv::operator []( ulong i ) const 51 + { return arg_[i]; } 52 + 53 +inline ulong Argv::size() const 54 + { return arg_.size(); } 55 + 56 + 57 + 58 +//========================================================================= 59 + 60 +#endif // __ccdoc__ 61 +} // namespace ki 62 +#endif // _KILIB_CMDARG_H_
Added kilib/ctrl.cpp version [6c0d29e2f223490b]
1 +#include "stdafx.h" 2 +#include "app.h" 3 +#include "ctrl.h" 4 +using namespace ki; 5 + 6 + 7 + 8 +//========================================================================= 9 + 10 +StatusBar::StatusBar() 11 +{ 12 + app().InitModule( App::CTL ); 13 +} 14 + 15 +bool StatusBar::Create( HWND parent ) 16 +{ 17 + HWND h = ::CreateStatusWindow( 18 + WS_CHILD|WS_VISIBLE|SBARS_SIZEGRIP, 19 + TEXT(""), parent, 1787 ); 20 + if( h == NULL ) 21 + return false; 22 + 23 + SetStatusBarVisible(); 24 + SetHwnd( h ); 25 + AutoResize( false ); 26 + return true; 27 +} 28 + 29 +int StatusBar::AutoResize( bool maximized ) 30 +{ 31 + // サイズ自動変更 32 + SendMsg( WM_SIZE ); 33 + 34 + // 変更後のサイズを取得 35 + RECT rc; 36 + getPos( &rc ); 37 + width_ = rc.right - rc.left; 38 + if( !maximized ) 39 + width_ -= 15; 40 + return (isStatusBarVisible() ? rc.bottom - rc.top : 0); 41 +} 42 + 43 +bool StatusBar::PreTranslateMessage( MSG* ) 44 +{ 45 + // 何もしない 46 + return false; 47 +} 48 + 49 + 50 + 51 +//========================================================================= 52 + 53 +void ComboBox::Select( const TCHAR* str ) 54 +{ 55 + // SELECTSTRING は先頭が合ってる物に全てにマッチするので使えない。 56 + // おそらくインクリメンタルサーチとかに使うべきものなのだろう。 57 + size_t i = 58 + SendMsg( CB_FINDSTRINGEXACT, ~0, reinterpret_cast<LPARAM>(str) ); 59 + if( i != CB_ERR ) 60 + SendMsg( CB_SETCURSEL, i ); 61 +} 62 + 63 +bool ComboBox::PreTranslateMessage( MSG* ) 64 +{ 65 + return false; 66 +}
Added kilib/ctrl.h version [21ba63c586f76d54]
1 +#ifndef _KILIB_CTRL_H_ 2 +#define _KILIB_CTRL_H_ 3 +#include "window.h" 4 +#ifndef __ccdoc__ 5 +namespace ki { 6 +#endif 7 + 8 + 9 + 10 +//========================================================================= 11 +//@{ @pkg ki.Window //@} 12 +//@{ 13 +// ステータスバー 14 +//@} 15 +//========================================================================= 16 + 17 +class StatusBar : public Window 18 +{ 19 +public: 20 + 21 + StatusBar(); 22 + bool Create( HWND parent ); 23 + int AutoResize( bool maximized ); 24 + void SetText( const TCHAR* str, int part=0 ); 25 + void SetTipText( const TCHAR* tip, int part=0 ); 26 + void SetParts( int n, int* parts ); 27 + void SetStatusBarVisible(bool b=true); 28 + 29 +public: 30 + 31 + int width() const; 32 + bool isStatusBarVisible() const; 33 + 34 +private: 35 + 36 + virtual bool PreTranslateMessage( MSG* ); 37 + 38 +private: 39 + 40 + int width_; 41 + bool visible_; 42 +}; 43 + 44 + 45 + 46 +//------------------------------------------------------------------------- 47 +#ifndef __ccdoc__ 48 + 49 +inline int StatusBar::width() const 50 + { return width_; } 51 + 52 +inline bool StatusBar::isStatusBarVisible() const 53 + { return visible_; } 54 + 55 +inline void StatusBar::SetParts( int n, int* parts ) 56 + { SendMsg( SB_SETPARTS, n, reinterpret_cast<LPARAM>(parts) ); } 57 + 58 +inline void StatusBar::SetText( const TCHAR* str, int part ) 59 + { SendMsg( SB_SETTEXT, part, reinterpret_cast<LPARAM>(str) ); } 60 + 61 +inline void StatusBar::SetStatusBarVisible(bool b) 62 + { ::ShowWindow( hwnd(), b?SW_SHOW:SW_HIDE ); visible_=b; } 63 + 64 + 65 + 66 +#endif // __ccdoc__ 67 +//========================================================================= 68 +//@{ 69 +// コンボボックス 70 +//@} 71 +//========================================================================= 72 + 73 +class ComboBox : public Window 74 +{ 75 +public: 76 + explicit ComboBox( HWND cb ); 77 + explicit ComboBox( HWND dlg, UINT id ); 78 + void Add( const TCHAR* str ); 79 + void Select( const TCHAR* str ); 80 + int GetCurSel(); 81 +private: 82 + virtual bool PreTranslateMessage( MSG* ); 83 +}; 84 + 85 + 86 + 87 +//------------------------------------------------------------------------- 88 +#ifndef __ccdoc__ 89 + 90 +inline ComboBox::ComboBox( HWND cb ) 91 + { SetHwnd(cb); } 92 + 93 +inline ComboBox::ComboBox( HWND dlg, UINT id ) 94 + { SetHwnd( ::GetDlgItem(dlg,id) ); } 95 + 96 +inline void ComboBox::Add( const TCHAR* str ) 97 + { SendMsg( CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(str) ); } 98 + 99 +inline int ComboBox::GetCurSel() 100 + { return (int) SendMsg( CB_GETCURSEL ); } 101 + 102 + 103 + 104 +//========================================================================= 105 + 106 +#endif // __ccdoc__ 107 +} // namespace ki 108 +#endif // _KILIB_CTRL_H_
Added kilib/file.cpp version [41942e064e293875]
1 +#include "stdafx.h" 2 +#include "file.h" 3 +using namespace ki; 4 + 5 + 6 + 7 +//========================================================================= 8 + 9 +FileR::FileR() 10 + : handle_ ( INVALID_HANDLE_VALUE ) 11 + , fmo_ ( NULL ) 12 + , basePtr_( NULL ) 13 +{ 14 +} 15 + 16 +FileR::~FileR() 17 +{ 18 + Close(); 19 +} 20 + 21 +bool FileR::Open( const TCHAR* fname ) 22 +{ 23 + Close(); 24 + 25 + // ファイルを読みとり専用で開く 26 + handle_ = ::CreateFile( 27 + fname, GENERIC_READ, 28 + FILE_SHARE_READ|FILE_SHARE_WRITE, 29 + NULL, OPEN_EXISTING, 30 + FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN, NULL 31 + ); 32 + if( handle_ == INVALID_HANDLE_VALUE ) 33 + return false; 34 + 35 + // サイズを取得 36 + size_ = ::GetFileSize( handle_, NULL ); 37 + 38 + if( size_==0 ) 39 + { 40 + // 0バイトのファイルはマッピング出来ないので適当に回避 41 + basePtr_ = &size_; 42 + } 43 + else 44 + { 45 + // マッピングオブジェクトを作る 46 + fmo_ = ::CreateFileMapping( 47 + handle_, NULL, PAGE_READONLY, 0, 0, NULL ); 48 + if( fmo_ == NULL ) 49 + { 50 + ::CloseHandle( handle_ ); 51 + handle_ = INVALID_HANDLE_VALUE; 52 + return false; 53 + } 54 + 55 + // ビュー 56 + basePtr_ = ::MapViewOfFile( fmo_, FILE_MAP_READ, 0, 0, 0 ); 57 + if( basePtr_ == NULL ) 58 + { 59 + ::CloseHandle( fmo_ ); 60 + ::CloseHandle( handle_ ); 61 + handle_ = INVALID_HANDLE_VALUE; 62 + return false; 63 + } 64 + } 65 + return true; 66 +} 67 + 68 +void FileR::Close() 69 +{ 70 + if( handle_ != INVALID_HANDLE_VALUE ) 71 + { 72 + // ヘンテコマッピングをしてなければここで解放 73 + if( basePtr_ != &size_ ) 74 + ::UnmapViewOfFile( const_cast<void*>(basePtr_) ); 75 + basePtr_ = NULL; 76 + 77 + if( fmo_ != NULL ) 78 + ::CloseHandle( fmo_ ); 79 + fmo_ = NULL; 80 + 81 + ::CloseHandle( handle_ ); 82 + handle_ = INVALID_HANDLE_VALUE; 83 + } 84 +} 85 + 86 + 87 + 88 +//========================================================================= 89 + 90 +FileW::FileW() 91 + : BUFSIZE( 65536 ) 92 + , handle_( INVALID_HANDLE_VALUE ) 93 + , buf_ ( new uchar[BUFSIZE] ) 94 +{ 95 +} 96 + 97 +FileW::~FileW() 98 +{ 99 + Close(); 100 + delete [] buf_; 101 +} 102 + 103 +inline void FileW::Flush() 104 +{ 105 + DWORD dummy; 106 + ::WriteFile( handle_, buf_, bPos_, &dummy, NULL ); 107 + bPos_ = 0; 108 +} 109 + 110 +bool FileW::Open( const TCHAR* fname, bool creat ) 111 +{ 112 + Close(); 113 + 114 + // ファイルを書き込み専用で開く 115 + handle_ = ::CreateFile( fname, 116 + GENERIC_WRITE, FILE_SHARE_READ, NULL, 117 + creat ? CREATE_ALWAYS : OPEN_EXISTING, 118 + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL ); 119 + if( handle_ == INVALID_HANDLE_VALUE ) 120 + return false; 121 + 122 + bPos_ = 0; 123 + return true; 124 +} 125 + 126 +void FileW::Close() 127 +{ 128 + if( handle_ != INVALID_HANDLE_VALUE ) 129 + { 130 + Flush(); 131 + ::CloseHandle( handle_ ); 132 + handle_ = INVALID_HANDLE_VALUE; 133 + } 134 +} 135 + 136 +void FileW::Write( const void* dat, ulong siz ) 137 +{ 138 + const uchar* udat = static_cast<const uchar*>(dat); 139 + 140 + while( (BUFSIZE-bPos_) <= siz ) 141 + { 142 + memmove( buf_+bPos_, udat, BUFSIZE-bPos_ ); 143 + siz -= (BUFSIZE-bPos_); 144 + udat += (BUFSIZE-bPos_); 145 + bPos_ = BUFSIZE; 146 + Flush(); 147 + } 148 + 149 + memmove( buf_+bPos_, udat, siz ); 150 + bPos_ += siz; 151 +} 152 + 153 +void FileW::WriteC( uchar ch ) 154 +{ 155 + if( (BUFSIZE-bPos_) <= 1 ) 156 + Flush(); 157 + 158 + buf_[bPos_++] = ch; 159 +} 160 +
Added kilib/file.h version [f917f310296a724b]
1 +#ifndef _KILIB_FILE_H_ 2 +#define _KILIB_FILE_H_ 3 +#include "types.h" 4 +#include "memory.h" 5 +#ifndef __ccdoc__ 6 +namespace ki { 7 +#endif 8 + 9 + 10 + 11 +//========================================================================= 12 +//@{ @pkg ki.StdLib //@} 13 +//@{ 14 +// 簡易ファイル読込 15 +// 16 +// ファイルマッピングを用いるので、扱いが簡単でわりと高速です。 17 +// ただし困ったことに、4GBまでしか開けません。 18 +//@} 19 +//========================================================================= 20 + 21 +class FileR : public Object 22 +{ 23 +public: 24 + 25 + FileR(); 26 + ~FileR(); 27 + 28 + //@{ 29 + // 開く 30 + // @param fname ファイル名 31 + // @return 開けたかどうか 32 + //@} 33 + bool Open( const TCHAR* fname ); 34 + 35 + //@{ 36 + // 閉じる 37 + //@} 38 + void Close(); 39 + 40 +public: 41 + 42 + //@{ ファイルサイズ //@} 43 + ulong size() const; 44 + 45 + //@{ ファイル内容をマップしたアドレス取得 //@} 46 + const uchar* base() const; 47 + 48 +private: 49 + 50 + HANDLE handle_; 51 + HANDLE fmo_; 52 + ulong size_; 53 + const void* basePtr_; 54 + 55 +private: 56 + 57 + NOCOPY(FileR); 58 +}; 59 + 60 + 61 + 62 +//------------------------------------------------------------------------- 63 + 64 +inline ulong FileR::size() const 65 + { return size_; } 66 + 67 +inline const uchar* FileR::base() const 68 + { return static_cast<const uchar*>(basePtr_); } 69 + 70 + 71 + 72 +//========================================================================= 73 +//@{ 74 +// 簡易ファイル書き込み 75 +// 76 +// てきとーにバッファリングしつつ。 77 +//@} 78 +//========================================================================= 79 + 80 +class FileW : public Object 81 +{ 82 +public: 83 + 84 + FileW(); 85 + ~FileW(); 86 + 87 + //@{ 開く //@} 88 + bool Open( const TCHAR* fname, bool creat=true ); 89 + 90 + //@{ 閉じる //@} 91 + void Close(); 92 + 93 + //@{ 書く //@} 94 + void Write( const void* buf, ulong siz ); 95 + 96 + //@{ 一文字書く //@} 97 + void WriteC( uchar ch ); 98 + 99 +public: 100 + 101 + void Flush(); 102 + 103 +private: 104 + 105 + const int BUFSIZE; 106 + HANDLE handle_; 107 + uchar* const buf_; 108 + ulong bPos_; 109 + 110 +private: 111 + 112 + NOCOPY(FileW); 113 +}; 114 + 115 + 116 + 117 +//========================================================================= 118 + 119 +} // namespace ki 120 +#endif // _KILIB_FILE_H_
Added kilib/find.cpp version [b12e88bb918155c8]
1 +#include "stdafx.h" 2 +#include "find.h" 3 +using namespace ki; 4 + 5 + 6 + 7 +//========================================================================= 8 + 9 +namespace { 10 +static inline bool isDots(const TCHAR* p) 11 +{ 12 + return (*p=='.' && (p[1]=='\0' || (p[1]=='.' && p[2]=='\0'))); 13 +} 14 +} 15 + 16 +bool FindFile::FindFirst( const TCHAR* wild, WIN32_FIND_DATA* pfd ) 17 +{ 18 + HANDLE xh = ::FindFirstFile( wild, pfd ); 19 + if( xh==INVALID_HANDLE_VALUE ) 20 + return false; 21 + while( isDots(pfd->cFileName) ) 22 + if( !::FindNextFile( xh, pfd ) ) 23 + { 24 + ::FindClose( xh ); 25 + return false; 26 + } 27 + ::FindClose( xh ); 28 + return true; 29 +} 30 + 31 +void FindFile::Close() 32 +{ 33 + first_ = true; 34 + if( han_ != INVALID_HANDLE_VALUE ) 35 + ::FindClose( han_ ), han_ = INVALID_HANDLE_VALUE; 36 +} 37 + 38 +bool FindFile::Begin( const TCHAR* wild ) 39 +{ 40 + Close(); 41 + 42 + han_ = ::FindFirstFile( wild, &fd_ ); 43 + if( han_ == INVALID_HANDLE_VALUE ) 44 + return false; 45 + 46 + while( isDots(fd_.cFileName) ) 47 + if( !::FindNextFile( han_, &fd_ ) ) 48 + { 49 + Close(); 50 + return false; 51 + } 52 + return true; 53 +} 54 + 55 +bool FindFile::Next( WIN32_FIND_DATA* pfd ) 56 +{ 57 + if( han_ == INVALID_HANDLE_VALUE ) 58 + return false; 59 + 60 + if( first_ ) 61 + { 62 + first_ = false; 63 + memmove( pfd, &fd_, sizeof(fd_) ); 64 + return true; 65 + } 66 + if( !::FindNextFile( han_, pfd ) ) 67 + return false; 68 + while( isDots(fd_.cFileName) ) 69 + if( !::FindNextFile( han_, pfd ) ) 70 + return false; 71 + return true; 72 +} 73 + 74 +#undef isDots
Added kilib/find.h version [3273f24ee839c505]
1 +#ifndef _KILIB_FIND_H_ 2 +#define _KILIB_FIND_H_ 3 +#include "types.h" 4 +#include "memory.h" 5 +#include "path.h" 6 +#ifndef __ccdoc__ 7 +namespace ki { 8 +#endif 9 + 10 + 11 + 12 +//========================================================================= 13 +//@{ @pkg ki.WinUtil //@} 14 +//@{ 15 +// ファイル検索 16 +// 17 +// Win32 APIのFindFirstFile等を用いて、ディレクトリ内の 18 +// ファイルリストアップを行います。 19 +//@} 20 +//========================================================================= 21 + 22 +class FindFile : public Object 23 +{ 24 +public: 25 + 26 + //@{ コンストラクタ //@} 27 + FindFile(); 28 + 29 + //@{ デストラクタ //@} 30 + ~FindFile(); 31 + 32 + //@{ 検索終了処理 //@} 33 + void Close(); 34 + 35 +public: //-- 外向きインターフェイス -------------------------- 36 + 37 + bool Begin( const TCHAR* wild ); 38 + bool Next( WIN32_FIND_DATA* pfd ); 39 + 40 +public: 41 + 42 + //@{ static版。マッチする最初のファイルを取得 //@} 43 + static bool FindFirst( const TCHAR* wild, WIN32_FIND_DATA* pfd ); 44 + 45 +private: 46 + 47 + HANDLE han_; 48 + bool first_; 49 + WIN32_FIND_DATA fd_; 50 + 51 +private: 52 + 53 + NOCOPY(FindFile); 54 +}; 55 + 56 + 57 + 58 +//------------------------------------------------------------------------- 59 + 60 +inline FindFile::FindFile() 61 + : han_( INVALID_HANDLE_VALUE ) {} 62 + 63 +inline FindFile::~FindFile() 64 + { Close(); } 65 + 66 + 67 + 68 +//========================================================================= 69 + 70 +} // namespace ki 71 +#endif // _KILIB_FIND_H_
Added kilib/kilib.h version [28c7016319731f23]
1 +#ifndef _KILIB_KILIB_H_ 2 +#define _KILIB_KILIB_H_ 3 + 4 +#include "types.h" 5 +#include "app.h" 6 +#include "thread.h" 7 +#include "memory.h" 8 +#include "window.h" 9 +#include "string.h" 10 +#include "cmdarg.h" 11 +#include "path.h" 12 +#include "file.h" 13 +#include "ctrl.h" 14 +#include "textfile.h" 15 +#include "winutil.h" 16 +#include "find.h" 17 +#include "registry.h" 18 +#include "log.h" 19 + 20 +#include "ktlaptr.h" 21 +#include "ktlarray.h" 22 +#include "ktlgap.h" 23 + 24 +#endif // _KILIB_KILIB_H_
Added kilib/ktlaptr.h version [287ca367e86ae8f1]
1 +#ifndef _KILIB_KTL_APTR_H_ 2 +#define _KILIB_KTL_APTR_H_ 3 +#include "types.h" 4 +#ifdef _MSC_VER 5 +#pragma warning( disable : 4284 ) // 警告:->のリターン型がうにゃうにゃ 6 +#pragma warning( disable : 4150 ) // 警告:deleteの定義がうにょうにょ 7 +#endif 8 +#ifndef __ccdoc__ 9 +namespace ki { 10 +#endif 11 + 12 + 13 + 14 +//========================================================================= 15 +//@{ @pkg ki.KTL //@} 16 +//@{ 17 +// 自動ポインタ 18 +// 19 +// 私の期待する範囲では概ね std::auto_ptr と同じ動作をすると思う…。 20 +// 車輪の最発明ばんざーい! 21 +//@} 22 +//========================================================================= 23 + 24 +template<class T> 25 +class aptr 26 +{ 27 +public: 28 + 29 + //@{ コンストラクタ //@} 30 + explicit aptr( T* p = NULL ) 31 + : obj_( p ) {} 32 + 33 + //@{ デストラクタ //@} 34 + ~aptr() 35 + { delete obj_; } 36 + 37 + //@{ 所有権移動 //@} 38 + aptr( aptr<T>& r ) 39 + : obj_ ( r.release() ) {} 40 + 41 + //@{ 所有権移動 //@} 42 + aptr<T>& operator=( aptr<T>& r ) 43 + { 44 + if( obj_ != r.obj_ ) 45 + { 46 + delete obj_; 47 + obj_ = r.release(); 48 + } 49 + return *this; 50 + } 51 + 52 +public: 53 + 54 + //@{ 間接演算子 //@} 55 + T& operator*() const 56 + { return *obj_; } 57 + 58 + //@{ メンバ参照 //@} 59 + T* operator->() const 60 + { return obj_; } 61 + 62 + //@{ ポインタ取得 //@} 63 + T* get() const 64 + { return obj_; } 65 + 66 + //@{ 所有権解放 //@} 67 + T* release() 68 + { 69 + T* ptr = obj_; 70 + obj_ = NULL; 71 + return ptr; 72 + } 73 + 74 + //@{ 有効かどうか //@} 75 + bool isValid() const 76 + { 77 + return (obj_ != NULL); 78 + } 79 + 80 +private: 81 + 82 + mutable T* obj_; 83 +}; 84 + 85 + 86 + 87 +//========================================================================= 88 +//@{ 89 +// 自動ポインタ(配列版) 90 +//@} 91 +//========================================================================= 92 + 93 +template<class T> 94 +class aarr 95 +{ 96 +public: 97 + 98 + //@{ コンストラクタ //@} 99 + explicit aarr( T* p = NULL ) 100 + : obj_( p ) {} 101 + 102 + //@{ デストラクタ //@} 103 + ~aarr() 104 + { delete [] obj_; } 105 + 106 + //@{ 所有権移動 何故かbccで上手く行かない部分があるのでconst付き //@} 107 + aarr( const aarr<T>& r ) 108 + : obj_ ( const_cast<aarr<T>&>(r).release() ) {} 109 + 110 + //@{ 所有権移動 //@} 111 + aarr<T>& operator=( aarr<T>& r ) 112 + { 113 + if( obj_ != r.obj_ ) 114 + { 115 + delete [] obj_; 116 + obj_ = r.release(); 117 + } 118 + return *this; 119 + } 120 + 121 +public: 122 + 123 + //@{ ポインタ取得 //@} 124 + T* get() const 125 + { return obj_; } 126 + 127 + //@{ 所有権解放 //@} 128 + T* release() 129 + { 130 + T* ptr = obj_; 131 + obj_ = NULL; 132 + return ptr; 133 + } 134 + 135 + //@{ 有効かどうか //@} 136 + bool isValid() const 137 + { 138 + return (obj_ != NULL); 139 + } 140 + 141 +public: 142 + 143 + //@{ 配列要素アクセス //@} 144 + T& operator[]( int i ) const 145 + { return obj_[i]; } 146 + 147 +private: 148 + 149 + mutable T* obj_; 150 +}; 151 + 152 + 153 + 154 +//========================================================================= 155 +//@{ 156 +// 削除権専有ポインタ 157 +// 158 +// 「リソースの獲得はコンストラクタで・解放はデストラクタで」を 159 +// 徹底できるならこんなの使わずに、迷わず const auto_ptr を用いる 160 +// べきです。べきですが、メンバ初期化リストで this を使うとVC++の 161 +// コンパイラに怒られるのが気持悪いので、ついこっちを使ってコンストラクタ 162 +// 関数内で初期化してしまうのでふ…(^^; 163 +//@} 164 +//========================================================================= 165 + 166 +template<class T> 167 +class dptr 168 +{ 169 +public: 170 + 171 + //@{ コンストラクタ //@} 172 + explicit dptr( T* p = NULL ) 173 + : obj_( p ) {} 174 + 175 + //@{ デストラクタ //@} 176 + ~dptr() 177 + { delete obj_; } 178 + 179 + //@{ 新しいオブジェクトを所有。古いのは削除 //@} 180 + void operator=( T* p ) 181 + { 182 + delete obj_; // 古いのは削除 183 + obj_ = p; 184 + } 185 + 186 + //@{ 有効かどうか //@} 187 + bool isValid() const 188 + { 189 + return (obj_ != NULL); 190 + } 191 + 192 +public: 193 + 194 + //@{ 間接演算子 //@} 195 + T& operator*() const 196 + { return *obj_; } 197 + 198 + //@{ メンバ参照 //@} 199 + T* operator->() const 200 + { return obj_; } 201 + 202 + //@{ ポインタ取得 //@} 203 + T* get() const 204 + { return obj_; } 205 + 206 +private: 207 + 208 + T* obj_; 209 + 210 +private: 211 + 212 + NOCOPY(dptr<T>); 213 +}; 214 + 215 + 216 + 217 +//========================================================================= 218 +//@{ 219 +// 削除権専有ポインタ(配列版) 220 +//@} 221 +//========================================================================= 222 + 223 +template<class T> 224 +class darr 225 +{ 226 +public: 227 + 228 + //@{ コンストラクタ //@} 229 + explicit darr( T* p = NULL ) 230 + : obj_( p ) {} 231 + 232 + //@{ デストラクタ //@} 233 + ~darr() 234 + { delete [] obj_; } 235 + 236 + //@{ 新しいオブジェクトを所有。古いのは削除 //@} 237 + void operator=( T* p ) 238 + { 239 + delete [] obj_; // 古いのは削除 240 + obj_ = p; 241 + } 242 + 243 + //@{ 有効かどうか //@} 244 + bool isValid() const 245 + { 246 + return (obj_ != NULL); 247 + } 248 + 249 +public: 250 + 251 + //@{ 配列要素アクセス //@} 252 + T& operator[]( int i ) const 253 + { return obj_[i]; } 254 + 255 +private: 256 + 257 + T* obj_; 258 + 259 +private: 260 + 261 + NOCOPY(darr<T>); 262 +}; 263 + 264 + 265 + 266 +//========================================================================= 267 + 268 +#ifdef _MSC_VER 269 +#pragma warning( default : 4150 ) 270 +#pragma warning( default : 4284 ) 271 +#endif 272 +} // namespace ki 273 +#endif // _KILIB_KTL_APTR_H_
Added kilib/ktlarray.h version [4098f71530c2f376]
1 +#ifndef _KILIB_KTL_ARRAY_H_ 2 +#define _KILIB_KTL_ARRAY_H_ 3 +#include "types.h" 4 +#include "memory.h" 5 +#ifndef __ccdoc__ 6 +namespace ki { 7 +#endif 8 + 9 + 10 + 11 +//========================================================================= 12 +//@{ @pkg ki.KTL //@} 13 +//@{ 14 +// 基本型専用の可変長配列 15 +// 16 +// 非常に簡素な作りです。アクセスは好きなところへ自由に可能ですが、 17 +// 要素の追加・削除は末尾に対してのみ。ビット毎のコピーだとか、 18 +// 色々エキセントリックな作業をしてますので、そういうことをして良い 19 +// 型以外には使わないでください。 20 +//@} 21 +//========================================================================= 22 + 23 +template <typename T> 24 +class storage : public Object 25 +{ 26 +public: 27 + 28 + //@{ 29 + // コンストラクタ 30 + // 31 + // @param alloc_size 32 + // 最初に確保する"メモリの"サイズ。 33 + // "配列の"サイズではないことに注意。 34 + //@} 35 + explicit storage( ulong allocSize=20 ) 36 + : alen_( Max( allocSize, 1UL ) ) 37 + , len_ ( 0 ) 38 + , buf_ ( static_cast<T*>(mem().Alloc(alen_*sizeof(T))) ) 39 + {} 40 + 41 + ~storage() 42 + { mem().DeAlloc( buf_, alen_*sizeof(T) ); } 43 + 44 + //@{ 末尾に要素を追加 //@} 45 + void Add( const T& obj ) 46 + { 47 + if( len_ >= alen_ ) 48 + ReAllocate( alen_<<2 ); 49 + buf_[ len_++ ] = obj; 50 + } 51 + 52 + //@{ 53 + // 配列サイズを強制変更 54 + // 55 + // 縮小/拡大のどちらも可能。コンストラクタと違い、 56 + // 指定した値に基づき最大indexが変化します。 57 + // @param new_size 新しいサイズ。 58 + //@} 59 + void ForceSize( ulong newSize ) 60 + { 61 + if( newSize > alen_ ) 62 + ReAllocate( newSize ); 63 + len_ = newSize; 64 + } 65 + 66 +public: 67 + 68 + //@{ 要素数 //@} 69 + ulong size() const 70 + { return len_; } 71 + 72 + //@{ 要素取得 //@} 73 + T& operator[]( size_t i ) 74 + { return buf_[i]; } 75 + 76 + //@{ 要素取得(const) //@} 77 + const T& operator[]( size_t i ) const 78 + { return buf_[i]; } 79 + 80 + //@{ 配列先頭のポインタを返す //@} 81 + const T* head() const 82 + { return buf_; } 83 + 84 +private: 85 + 86 + void ReAllocate( ulong siz ) 87 + { 88 + ulong p = alen_*sizeof(T); 89 + T* newbuf = static_cast<T*> 90 + (mem().Alloc( (alen_=siz)*sizeof(T) )); 91 + memmove( newbuf, buf_, len_*sizeof(T) ); 92 + mem().DeAlloc( buf_, p ); 93 + buf_ = newbuf; 94 + } 95 + 96 +private: 97 + 98 + ulong alen_; 99 + ulong len_; 100 + T* buf_; 101 + 102 +private: 103 + 104 + NOCOPY(storage<T>); 105 +}; 106 + 107 + 108 + 109 +//========================================================================= 110 +//@{ 111 +// オブジェクト型にも使える単方向リスト 112 +// 113 +// ほとんど何も出来ません。出来るのは末尾への追加と、独自の 114 +// iteratorによるシーケンシャルなアクセスのみ。 115 +//@} 116 +//========================================================================= 117 + 118 +template <class T> 119 +class olist : public Object 120 +{ 121 +private: 122 + 123 + struct Node { 124 + Node( const T& obj ) 125 + : obj_ ( obj ), next_( NULL ) {} 126 + ~Node() 127 + { delete next_; } 128 + Node* Add( Node* pN ) 129 + { return next_==NULL ? next_=pN : next_->Add(pN); } 130 + T obj_; 131 + Node* next_; 132 + }; 133 + 134 +public: 135 + 136 + struct iterator { 137 + iterator( Node* p=NULL ) : ptr_(p) {} 138 + T& operator*() { return ptr_->obj_; } 139 + T* operator->() const { return &ptr_->obj_; } 140 + bool operator==( const iterator& i ) { return i.ptr_==ptr_; } 141 + bool operator!=( const iterator& i ) { return i.ptr_!=ptr_; } 142 + iterator& operator++() { ptr_=ptr_->next_; return *this; } 143 + private: 144 + Node* ptr_; 145 + }; 146 + 147 +public: 148 + 149 + //@{ コンストラクタ //@} 150 + olist() 151 + : top_( NULL ) {} 152 + 153 + //@{ デストラクタ //@} 154 + ~olist() 155 + { empty(); } 156 + 157 + //@{ 空にする //@} 158 + void empty() 159 + { delete top_; top_ = NULL; } 160 + 161 + //@{ 先頭 //@} 162 + iterator begin() 163 + { return iterator(top_); } 164 + 165 + //@{ 末尾 //@} 166 + iterator end() 167 + { return iterator(); } 168 + 169 + //@{ 末尾に要素を追加 //@} 170 + void Add( const T& obj ) 171 + { 172 + Node* pN = new Node( obj ); 173 + (top_ == NULL) ? top_=pN : top_->Add( pN ); 174 + } 175 + 176 + //@{ 指定要素を削除 //@} 177 + void Del( iterator d ) 178 + { 179 + if( d != end() ) 180 + { 181 + Node *p=top_, *q=NULL; 182 + for( ; p!=NULL; q=p,p=p->next_ ) 183 + if( &p->obj_ == &*d ) 184 + break; 185 + if( q != NULL ) 186 + q->next_ = p->next_; 187 + else 188 + top_ = p->next_; 189 + p->next_ = NULL; 190 + delete p; 191 + } 192 + } 193 + 194 + //@{ 指定要素以降全てを削除 //@} 195 + void DelAfter( iterator d ) 196 + { 197 + if( d != end() ) 198 + if( d == begin() ) 199 + { 200 + empty(); 201 + } 202 + else 203 + { 204 + Node *p=top_, *q=NULL; 205 + for( ; p!=NULL; q=p,p=p->next_ ) 206 + if( &p->obj_ == &*d ) 207 + break; 208 + delete p; 209 + q->next_ = NULL; 210 + } 211 + } 212 + 213 +private: 214 + 215 + Node* top_; 216 + NOCOPY(olist<T>); 217 +}; 218 + 219 + 220 + 221 +//========================================================================= 222 + 223 +} // namespace ki 224 +#endif // _KILIB_KTL_ARRAY_H_
Added kilib/ktlgap.h version [871ef62fc27e27a1]
1 +#ifndef _KILIB_KTL_GAP_H_ 2 +#define _KILIB_KTL_GAP_H_ 3 +#include "types.h" 4 +#include "memory.h" 5 +#ifndef __ccdoc__ 6 +namespace ki { 7 +#endif 8 + 9 + 10 + 11 +//========================================================================= 12 +//@{ @pkg ki.KTL //@} 13 +//@{ 14 +// 基本型専用ギャップバッファ 15 +// 16 +// 小耳に挟んだギャップバッファというもの。 17 +// ものすごい勘違いをして別物ができているかもしれませんが、 18 +// 細かいことはあまり気にしないでください。 19 +// 配列のようにランダムアクセス可能で、 20 +// 同一箇所への連続した挿入/削除が速いというデータ構造です。 21 +// ( 下の図で言うと、gap_startへの挿入/削除にはデータの移動が必要ない ) 22 +// <pre> 23 +//@@ D <--0 24 +//@@ D 25 +//@@ | <--gap_start 26 +//@@ | 27 +//@@ D <--gap_end 28 +//@@ D 29 +//@@ <--array_end 30 +// </pre> 31 +// メモリイメージをそのままコピーしてる実装なので、 32 +// プリミティブ型以外では絶対に使わないこと。 33 +//@} 34 +//========================================================================= 35 + 36 +template<class T> 37 +class gapbuf : public Object 38 +{ 39 +public: 40 + 41 + //@{ 42 + // コンストラクタ 43 + // @param alloc_size 44 + // 最初に確保する"メモリの"サイズ。 45 + // "配列の"サイズではないことに注意。 46 + //@} 47 + explicit gapbuf( ulong alloc_size=40 ) 48 + : alen_( Max(alloc_size, 10UL) ) 49 + , gs_ ( 0 ) 50 + , ge_ ( alen_ ) 51 + , buf_ ( new T[alen_] ) 52 + {} 53 + ~gapbuf() 54 + { delete [] buf_; } 55 + 56 + //@{ 要素挿入 //@} 57 + void InsertAt( ulong i, const T& x ) 58 + { 59 + MakeGapAt( i ); 60 + buf_[gs_++] = x; 61 + 62 + if( gs_==ge_ ) 63 + Reallocate( alen_<<1 ); 64 + } 65 + 66 + //@{ 要素挿入(複数) //@} 67 + void InsertAt( ulong i, const T* x, ulong len ) 68 + { 69 + MakeGapAt( size() ); 70 + MakeGapAt( i ); 71 + if( ge_-gs_ <= len ) 72 + Reallocate( Max(alen_+len+1, alen_<<1) ); 73 + 74 + memmove( buf_+gs_, x, len*sizeof(T) ); 75 + gs_ += len; 76 + } 77 + 78 + //@{ 末尾に要素を追加 //@} 79 + void Add( const T& x ) 80 + { InsertAt( size(), x ); } 81 + 82 + //@{ 末尾に要素を追加(複数) //@} 83 + void Add( const T* x, ulong len ) 84 + { InsertAt( size(), x, len ); } 85 + 86 + //@{ 要素削除 //@} 87 + void RemoveAt( ulong i, ulong len=1 ) 88 + { 89 + if( i <= gs_ && gs_ <= i+len ) 90 + { 91 + // この場合はメモリ移動の必要がない 92 + // まず前半を削除 93 + len -= (gs_-i); 94 + gs_ = i; 95 + } 96 + else 97 + { 98 + MakeGapAt( i ); 99 + } 100 + 101 + // 後半を削除 102 + ge_ += len; 103 + } 104 + 105 + //@{ 要素削除(全部) //@} 106 + void RemoveAll() 107 + { RemoveAt( 0, size() ); } 108 + 109 + //@{ 要素削除(指定index以降全部) //@} 110 + void RemoveToTail( ulong i ) 111 + { RemoveAt( i, size()-i ); } 112 + 113 + //@{ 要素コピー(指定index以降全部) //@} 114 + ulong CopyToTail( ulong i, T* x ) 115 + { return CopyAt( i, size()-i, x ); } 116 + 117 + //@{ 要素コピー //@} 118 + ulong CopyAt( ulong i, ulong len, T* x ) 119 + { 120 + ulong copyed=0; 121 + if( i < gs_ ) 122 + { 123 + // 前半 124 + copyed += Min( len, gs_-i ); 125 + memmove( x, buf_+i, copyed*sizeof(T) ); 126 + x += copyed; 127 + len -= copyed; 128 + i += copyed; 129 + } 130 + 131 + // 後半 132 + memmove( x, buf_+(i-gs_)+ge_, len*sizeof(T) ); 133 + return copyed + len; 134 + } 135 + 136 +public: 137 + 138 + //@{ 要素数 //@} 139 + ulong size() const 140 + { return alen_ - (ge_-gs_); } 141 + 142 + //@{ 要素取得 //@} 143 + T& operator[]( ulong i ) 144 + { return buf_[ ( i<gs_ ) ? i : i+(ge_-gs_) ]; } 145 + 146 + //@{ 要素取得(const) //@} 147 + const T& operator[]( ulong i ) const 148 + { return buf_[ ( i<gs_ ) ? i : i+(ge_-gs_) ]; } 149 + 150 +protected: 151 + 152 + ulong alen_; 153 + ulong gs_; 154 + ulong ge_; 155 + T* buf_; 156 + 157 +protected: 158 + 159 + void MakeGapAt( ulong i ) 160 + { 161 + if( i<gs_ ) 162 + { 163 + ge_ -= (gs_-i); 164 + memmove( buf_+ge_, buf_+i, (gs_-i)*sizeof(T) ); 165 + } 166 + else if( i>gs_ ) 167 + { 168 + int j = i+(ge_-gs_); 169 + memmove( buf_+gs_, buf_+ge_, (j-ge_)*sizeof(T) ); 170 + ge_ = j; 171 + } 172 + gs_ = i; 173 + } 174 + 175 + void Reallocate( ulong newalen ) 176 + { 177 + T *tmp = new T[newalen], *old=buf_; 178 + const ulong tail = alen_-ge_; 179 + 180 + memmove( tmp, old, gs_*sizeof(T) ); 181 + memmove( tmp+newalen-tail, old+ge_, tail*sizeof(T) ); 182 + delete [] old; 183 + 184 + buf_ = tmp; 185 + ge_ = newalen-tail; 186 + alen_ = newalen; 187 + } 188 + 189 +private: 190 + 191 + NOCOPY(gapbuf<T>); 192 +}; 193 + 194 + 195 + 196 +//========================================================================= 197 +//@{ 198 +// gapbuf + smartptr のふり 199 +// 200 +// 要素削除時にdeleteを実行しっちゃったりするバージョン。 201 +// 任意オブジェクトをギャップバッファで使いたいときは 202 +// これでてきとーに代用すべし。 203 +//@} 204 +//========================================================================= 205 + 206 +template<class T> 207 +class gapbufobj : public gapbuf<T*> 208 +{ 209 +public: 210 + 211 + explicit gapbufobj( ulong alloc_size=40 ) 212 + : gapbuf<T*>( alloc_size ) 213 + { } 214 + 215 + void RemoveAt( ulong i, ulong len=1 ) 216 + { 217 + ulong& gs_ = gapbuf<T*>::gs_; 218 + ulong& ge_ = gapbuf<T*>::ge_; 219 + T**& buf_= gapbuf<T*>::buf_; 220 + 221 + if( i <= gs_ && gs_ <= i+len ) 222 + { 223 + // 前半を削除 224 + for( ulong j=i, ed=gs_; j<ed; ++j ) 225 + delete buf_[j]; 226 + 227 + len -= (gs_-i); 228 + gs_ = i; 229 + } 230 + else 231 + { 232 + gapbuf<T*>::MakeGapAt( i ); 233 + } 234 + 235 + // 後半を削除 236 + for( ulong j=ge_, ed=ge_+len; j<ed; ++j ) 237 + delete buf_[j]; 238 + ge_ = ge_+len; 239 + } 240 + 241 + ~gapbufobj() 242 + { RemoveAt( 0, gapbuf<T*>::size() ); } 243 + 244 + void RemoveAll( ulong i ) 245 + { RemoveAt( 0, gapbuf<T*>::size() ); } 246 + 247 + void RemoveToTail( ulong i ) 248 + { RemoveAt( i, gapbuf<T*>::size()-i ); } 249 + 250 +public: 251 + 252 + T& operator[]( ulong i ) 253 + { return *gapbuf<T*>::operator[](i); } 254 + 255 + const T& operator[]( ulong i ) const 256 + { return *gapbuf<T*>::operator[](i); } 257 + 258 +private: 259 + 260 + NOCOPY(gapbufobj<T>); 261 +}; 262 + 263 + 264 + 265 +//========================================================================= 266 + 267 +} // namespace ki 268 +#endif // _KILIB_KTL_GAP_H_
Added kilib/log.cpp version [56a918c7773d65a4]
1 +#include "stdafx.h" 2 +#include "log.h" 3 +#include "app.h" 4 +#include "string.h" 5 +using namespace ki; 6 + 7 + 8 + 9 +//========================================================================= 10 + 11 +void Logger::WriteLine( const String& str ) 12 +{ 13 + WriteLine( str.c_str(), str.len()*sizeof(TCHAR) ); 14 +} 15 + 16 +void Logger::WriteLine( const TCHAR* str ) 17 +{ 18 + WriteLine( str, ::lstrlen(str)*sizeof(TCHAR) ); 19 +} 20 + 21 +void Logger::WriteLine( const TCHAR* str, int siz ) 22 +{ 23 +#ifdef DO_LOGGING 24 + // Fileクラス自体のデバッグに使うかもしれないので、 25 + // Fileクラスを使用することは出来ない。API直叩き 26 + static bool st_firsttime = true; 27 + DWORD dummy; 28 + 29 + // ファイル名 30 + TCHAR fname[MAX_PATH]; 31 + ::GetModuleFileName( ::GetModuleHandle(NULL), fname, countof(fname) ); 32 + ::lstrcat( fname, TEXT("_log") ); 33 + 34 + // ファイルを書き込み専用で開く 35 + HANDLE h = ::CreateFile( fname, 36 + GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, 37 + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL ); 38 + if( h == INVALID_HANDLE_VALUE ) 39 + return; 40 + 41 + // 初回限定処理 42 + if( st_firsttime ) 43 + { 44 + ::SetEndOfFile( h ); 45 + #ifdef _UNICODE 46 + ::WriteFile( h, "\xff\xfe", 2, &dummy, NULL ); 47 + #endif 48 + st_firsttime = false; 49 + } 50 + else 51 + { 52 + ::SetFilePointer( h, 0, NULL, FILE_END ); 53 + } 54 + 55 + // 書く 56 + ::WriteFile( h, str, siz, &dummy, NULL ); 57 + ::WriteFile( h, TEXT("\r\n"), sizeof(TEXT("\r")), &dummy, NULL ); 58 + 59 + // 閉じる 60 + ::CloseHandle( h ); 61 + 62 +#endif 63 +}
Added kilib/log.h version [41bb51ff408369b0]
1 +#ifndef _KILIB_LOG_H_ 2 +#define _KILIB_LOG_H_ 3 +#include "types.h" 4 +#ifndef __ccdoc__ 5 +namespace ki { 6 +#endif 7 + 8 + 9 + 10 +class String; 11 + 12 +//========================================================================= 13 +//@{ @pkg ki.Core //@} 14 +//@{ 15 +// ログ取り機能(デバッグ用) 16 +// 17 +// アプリ起動/終了用処理を担当します。 18 +// 旧kilibと違って、ユーザー側のアプリケーションクラスを 19 +// ここから派生させることは出来ません。ユーザーのコードは、 20 +// 必ず kmain() というグローバル関数から実行開始されます。 21 +// このAppクラス自体は、主にHINSTANCEの管理を行うだけ。 22 +//@} 23 +//========================================================================= 24 + 25 +class Logger 26 +{ 27 +public: 28 + 29 + Logger() {} 30 + void WriteLine( const String& str ); 31 + void WriteLine( const TCHAR* str ); 32 + void WriteLine( const TCHAR* str, int siz ); 33 + 34 +private: 35 + 36 + NOCOPY(Logger); 37 +}; 38 + 39 +#ifdef DO_LOGGING 40 + #define LOGGER(str) Logger().WriteLine(TEXT(str)) 41 +#else 42 + #define LOGGER(x) 43 +#endif 44 + 45 +//========================================================================= 46 + 47 +} // namespace ki 48 +#endif // _KILIB_LOG_H_
Added kilib/memory.cpp version [4b76ca1a670e139d]
1 +#include "stdafx.h" 2 +#include "memory.h" 3 +using namespace ki; 4 + 5 + 6 + 7 +//========================================================================= 8 + 9 +#ifdef SUPERTINY 10 + 11 + static HANDLE g_heap; 12 + 13 + #ifndef _DEBUG 14 + 15 + void* __cdecl operator new( size_t siz ) 16 + { 17 + return ::HeapAlloc( g_heap, HEAP_GENERATE_EXCEPTIONS, siz ); 18 + } 19 + 20 + void __cdecl operator delete( void* ptr ) 21 + { 22 + ::HeapFree( g_heap, 0, ptr ); 23 + } 24 + 25 + #else 26 + 27 + // デバッグ用に回数計測版(^^; 28 + static int allocCounter = 0; 29 + void* __cdecl operator new( size_t siz ) 30 + { 31 + ++allocCounter; 32 + return ::HeapAlloc( g_heap, HEAP_GENERATE_EXCEPTIONS, siz ); 33 + } 34 + void __cdecl operator delete( void* ptr ) 35 + { 36 + ::HeapFree( g_heap, 0, ptr ); 37 + if( ptr != NULL ) 38 + --allocCounter; 39 + } 40 + 41 + #endif 42 + 43 + extern "C" 44 + void* __cdecl memset( void* buf, int ch, size_t n ) 45 + { 46 + BYTE v = BYTE(ch&0xff); 47 + BYTE* ptr = (BYTE*)buf; 48 + DWORD vvvv = (v<<24) | (v<<16) | (v<<8) | v; 49 + for(;n>3;n-=4,ptr+=4) *(DWORD*)ptr = vvvv; 50 + for(;n;--n,++ptr) *ptr = v; 51 + return buf; 52 + } 53 + 54 + void* __cdecl memmove( void* dst, const void* src, size_t cnt ) 55 + { 56 + __asm { 57 + mov esi, [src] ;U esi = const void* src 58 + mov edx, [cnt] ;V edx = void* cnt 59 + mov edi, [dst] ;U edi = ulong dst 60 + mov ebx, edx ;V 61 + mov eax, 03h ;U eax = const ulong 3 (for masking) 62 + add ebx, esi ;V ebx = const void* src+cnt 63 + 64 + cmp edi, esi ; 65 + jbe CopyUp ; 66 + cmp edi, ebx ; if( src < dst < src+cnt ) 67 + jb CopyDown ; downward copy 68 + 69 + CopyUp: 70 + cmp edx, eax ; if( cnt<=3 ) 71 + jbe MiniCopy ; byte by byte copy 72 + 73 + mov ebx, edi ;U 74 + mov ecx, eax ;V 75 + and ebx, eax ;U ebx = (dst&3) 76 + inc ecx ;V 77 + sub ecx, ebx ; ecx = (4-(dst&3)) 78 + and ecx, eax ; ecx = {dst%4 0->0 1->3 2->2 3->1} 79 + sub edx, ecx ; 80 + rep movsb ;N BYTE MOVE (align dst) 81 + 82 + mov ecx, edx ; 83 + shr ecx, 2 ; ecx = [rest bytes]/4 84 + and edx, eax ; edx = [rest bytes]%4 85 + rep movsd ;N DWORD MOVE 86 + jmp MiniCopy ; 87 + 88 + CopyDown: 89 + std ; 90 + lea esi,[esi+edx-1] ; 91 + lea edi,[edi+edx-1] ; 92 + 93 + cmp edx, 4 ; if( cnt<=4 ) 94 + jbe MiniCopy ; byte by byte copy 95 + 96 + mov ecx, edi ; 97 + and ecx, eax ; 98 + inc ecx ; ecx = {dst%4 0->1 1->2 2->3 3->4} 99 + sub edx, ecx ; 100 + rep movsb ;N BYTE MOVE (align dst @ dword) 101 + 102 + sub edi, eax ;U 103 + mov ecx, edx ;V 104 + sub esi, eax ;U 105 + shr ecx, 2 ;V ecx = [rest bytes]/4 106 + and edx, eax ; edx = [rest bytes]%4 107 + rep movsd ;N DWORD MOVE 108 + add edi, eax ;U 109 + add esi, eax ;V 110 + 111 + MiniCopy: 112 + mov ecx, edx ; 113 + rep movsb ;N BYTE MOVE 114 + 115 + cld ;U 116 + mov eax, [dst] ;V return dst 117 + } 118 + return dst; 119 + } 120 + 121 +#endif 122 + 123 + 124 + 125 +#ifdef USE_ORIGINAL_MEMMAN 126 +//========================================================================= 127 +// 効率的なメモリ管理を目指すアロケータ 128 +//========================================================================= 129 + 130 +// 131 +// メモリブロック 132 +// 「sizバイト * num個」分の領域を一括確保するのが仕事 133 +// 134 +// 空きブロックには、先頭バイトに [次の空きブロックのindex] を格納。 135 +// これを用いて、先頭への出し入れのみが可能な単方向リストとして扱う。 136 +// 137 + 138 +struct ki::MemBlock 139 +{ 140 +public: 141 + void Construct( byte siz, byte num ); 142 + void Destruct(); 143 + void* Alloc( byte siz ); 144 + void DeAlloc( void* ptr, byte siz ); 145 + bool isAvail(); 146 + bool isEmpty( byte num ); 147 + bool hasThisPtr( void* ptr, size_t len ); 148 +private: 149 + byte* buf_; 150 + byte first_, avail_; 151 +}; 152 + 153 +void MemBlock::Construct( byte siz, byte num ) 154 +{ 155 + // 確保 156 + buf_ = ::new byte[siz*num]; 157 + first_ = 0; 158 + avail_ = num; 159 + 160 + // 連結リスト初期化 161 + for( byte i=0,*p=buf_; i<num; p+=siz ) 162 + *p = ++i; 163 +} 164 + 165 +inline void MemBlock::Destruct() 166 +{ 167 + // 解放 168 + ::delete [] buf_; 169 +} 170 + 171 +void* MemBlock::Alloc( byte siz ) 172 +{ 173 + // メモリ切り出し 174 + // ( avail==0 等のチェックは上位層に任せる ) 175 + byte* blk = buf_ + siz*first_; 176 + first_ = *blk; 177 + --avail_; 178 + return blk; 179 +} 180 + 181 +void MemBlock::DeAlloc( void* ptr, byte siz ) 182 +{ 183 + // メモリ戻す 184 + // ( 変なポインタ渡されたらだ〜め〜 ) 185 + byte* blk = static_cast<byte*>(ptr); 186 + *blk = first_; 187 + first_ = static_cast<byte>((blk-buf_)/siz); 188 + ++avail_; 189 +} 190 + 191 +inline bool MemBlock::isAvail() 192 +{ 193 + // 空きがある? 194 + return (avail_ != 0); 195 +} 196 + 197 +inline bool MemBlock::isEmpty( byte num ) 198 +{ 199 + // 完全に空? 200 + return (avail_ == num); 201 +} 202 + 203 +inline bool MemBlock::hasThisPtr( void* ptr, size_t len ) 204 +{ 205 + // このブロックのポインタ? 206 + return ( buf_<=ptr && ptr<buf_+len ); 207 +} 208 + 209 + 210 + 211 +//------------------------------------------------------------------------- 212 + 213 +// 214 +// 固定サイズ確保人 215 +// 「sizバイト」の領域を毎回確保するのが仕事 216 +// 217 +// メモリブロックのリストを保持し、空いているブロックを使って 218 +// メモリ要求に応えていく。空きがなくなったら新しくMemBlockを 219 +// 作ってリストに加える。 220 +// 221 +// 最後にメモリ割り当て/解放を行ったBlockをそれぞれ記憶しておき、 222 +// 最初にそこを調べることで高速化を図る。 223 +// 224 + 225 +void MemoryManager::FixedSizeMemBlockPool::Construct( byte siz ) 226 +{ 227 + // メモリマネージャが初期化されるまでは、 228 + // 普通のauto_ptrも使わない方が無難… 229 + struct AutoDeleter 230 + { 231 + AutoDeleter( MemBlock* p ) : ptr_(p) {} 232 + ~AutoDeleter() { ::delete [] ptr_; } 233 + void Release() { ptr_ = NULL; } 234 + MemBlock* ptr_; 235 + }; 236 + 237 + // メモリブロック情報域をちょこっと確保 238 + AutoDeleter a( blocks_ = ::new MemBlock[4] ); 239 + 240 + // ブロックサイズ等計算 241 + int npb = BLOCK_SIZ/siz; 242 + numPerBlock_ = static_cast<byte>( Min( npb, 255 ) ); 243 + fixedSize_ = siz; 244 + 245 + // 一個だけブロック作成 246 + blocks_[0].Construct( fixedSize_, numPerBlock_ ); 247 + 248 + a.Release(); 249 + lastA_ = 0; 250 + lastDA_ = 0; 251 + blockNum_ = 1; 252 + blockNumReserved_ = 4; 253 +} 254 + 255 +void MemoryManager::FixedSizeMemBlockPool::Destruct() 256 +{ 257 + // 各ブロックを解放 258 + for( int i=0; i<blockNum_; ++i ) 259 + blocks_[i].Destruct(); 260 + 261 + // ブロック情報保持領域のメモリも解放 262 + ::delete [] blocks_; 263 + blockNum_ = 0; 264 +} 265 + 266 +void* MemoryManager::FixedSizeMemBlockPool::Alloc() 267 +{ 268 + // ここでlastA_がValidかどうかチェックしないとまずい。 269 + // DeAllocされてなくなってるかもしらないので。 270 + 271 + // 前回メモリを切り出したブロックに 272 + // まだ空きがあるかどうかチェック 273 + if( !blocks_[lastA_].isAvail() ) 274 + { 275 + // 無かった場合、リストの末尾から順に線形探索 276 + for( int i=blockNum_;; ) 277 + { 278 + if( blocks_[--i].isAvail() ) 279 + { 280 + // 空きブロック発見〜! 281 + lastA_ = i; 282 + break; 283 + } 284 + if( i == 0 ) 285 + { 286 + // 全部埋まってた... 287 + if( blockNum_ == blockNumReserved_ ) 288 + { 289 + // しかも作業領域も満杯なので拡張 290 + MemBlock* nb = ::new MemBlock[ blockNum_*2 ]; 291 + memmove( nb, blocks_, sizeof(MemBlock)*(blockNum_) ); 292 + ::delete [] blocks_; 293 + blocks_ = nb; 294 + blockNumReserved_ *= 2; 295 + } 296 + 297 + // 新しくブロック構築 298 + blocks_[ blockNum_ ].Construct( fixedSize_, numPerBlock_ ); 299 + lastA_ = blockNum_++; 300 + break; 301 + } 302 + } 303 + } 304 + 305 + // ブロックから切り出し割り当て 306 + return blocks_[lastA_].Alloc( fixedSize_ ); 307 +} 308 + 309 +void MemoryManager::FixedSizeMemBlockPool::DeAlloc( void* ptr ) 310 +{ 311 + // 該当ブロックを探索 312 + const int mx=blockNum_, ln=fixedSize_*numPerBlock_; 313 + for( int u=lastDA_, d=lastDA_-1;; ) 314 + { 315 + if( u>=0 ) 316 + if( blocks_[u].hasThisPtr(ptr,ln) ) 317 + { 318 + lastDA_ = u; 319 + break; 320 + } 321 + else if( u==mx ) 322 + { 323 + u = -1; 324 + } 325 + else 326 + { 327 + ++u; 328 + } 329 + if( d>=0 ) 330 + if( blocks_[d].hasThisPtr(ptr,ln) ) 331 + { 332 + lastDA_ = d; 333 + break; 334 + } 335 + else 336 + { 337 + --d; 338 + } 339 + } 340 + 341 + // 解放を実行 342 + blocks_[lastDA_].DeAlloc( ptr, fixedSize_ ); 343 + 344 + // この削除でブロックが完全に空になった場合 345 + if( blocks_[lastDA_].isEmpty( numPerBlock_ ) ) 346 + { 347 + // しかも一番後ろのブロックでなかったら 348 + int end = blockNum_-1; 349 + if( lastDA_ != end ) 350 + { 351 + // 一番後ろが空だったら解放 352 + if( blocks_[end].isEmpty( numPerBlock_ ) ) 353 + { 354 + blocks_[end].Destruct(); 355 + --blockNum_; 356 + if( lastA_ > --end ) 357 + lastA_ = end; 358 + } 359 + 360 + // 後ろと交換 361 + MemBlock tmp( blocks_[lastDA_] ); 362 + blocks_[lastDA_] = blocks_[end]; 363 + blocks_[end] = tmp; 364 + } 365 + } 366 +} 367 + 368 +inline bool MemoryManager::FixedSizeMemBlockPool::isValid() 369 +{ 370 + // 既に使用開始されているか? 371 + return (blockNum_ != 0); 372 +} 373 + 374 + 375 + 376 +//------------------------------------------------------------------------- 377 + 378 +// 379 +// 最上位層 380 +// 指定サイズにあった FixedSizeMemBlockPool に処理をまわす 381 +// 382 +// lokiの実装では固定サイズアロケータも、必要に応じて 383 +// 動的確保していたが、それは面倒なのでやめました。(^^; 384 +// 最初に64個確保したからと言って、そんなにメモリも喰わないし…。 385 +// 386 + 387 +MemoryManager* MemoryManager::pUniqueInstance_; 388 + 389 +MemoryManager::MemoryManager() 390 +{ 391 + g_heap = ::GetProcessHeap(); 392 + 393 + // メモリプールをZEROクリア 394 + mem00( pools_, sizeof(pools_) ); 395 + 396 + // 唯一のインスタンスは私です 397 + pUniqueInstance_ = this; 398 +} 399 + 400 +MemoryManager::~MemoryManager() 401 +{ 402 + // 構築済みメモリプールを全て解放 403 + for( int i=0; i<SMALL_MAX; ++i ) 404 + if( pools_[i].isValid() ) 405 + pools_[i].Destruct(); 406 + 407 +#if defined(SUPERTINY) && defined(_DEBUG) 408 + // リーク検出用 409 + if( allocCounter != 0 ) 410 + ::MessageBox( NULL, TEXT("MemoryLeak!"), NULL, MB_OK ); 411 +#endif 412 +} 413 + 414 + 415 +void* MemoryManager::Alloc( size_t siz ) 416 +{ 417 +#if defined(SUPERTINY) && defined(_DEBUG) 418 + ++allocCounter; 419 +#endif 420 + 421 + // サイズが零か大きすぎるなら 422 + // デフォルトの new 演算子に任せる 423 + uint i = static_cast<uint>( siz-1 ); 424 + if( i >= SMALL_MAX ) 425 + return ::operator new( siz ); 426 + 427 + // マルチスレッド対応 428 + AutoLock al(this); 429 + 430 + // このサイズのメモリ確保が初めてなら 431 + // ここでメモリプールを作成する。 432 + if( !pools_[i].isValid() ) 433 + pools_[i].Construct( static_cast<byte>(siz) ); 434 + 435 + // ここで割り当て 436 + return pools_[i].Alloc(); 437 +} 438 + 439 +void MemoryManager::DeAlloc( void* ptr, size_t siz ) 440 +{ 441 +#if defined(SUPERTINY) && defined(_DEBUG) 442 + --allocCounter; 443 +#endif 444 + 445 + // サイズが零か大きすぎるなら 446 + // デフォルトの delete 演算子に任せる 447 + uint i = static_cast<uint>( siz-1 ); 448 + if( i >= SMALL_MAX ) 449 + { 450 + ::operator delete( ptr ); 451 + return; // VCで return void が出来ないとは… 452 + } 453 + 454 + // マルチスレッド対応 455 + AutoLock al(this); 456 + 457 + // ここで解放 458 + pools_[i].DeAlloc( ptr ); 459 +} 460 + 461 +#else // USE_ORIGNAL_MEMMAN 462 + 463 +MemoryManager* MemoryManager::pUniqueInstance_; 464 + 465 +MemoryManager::MemoryManager() 466 +{ 467 + g_heap = ::GetProcessHeap(); 468 + 469 + // 唯一のインスタンスは私です 470 + pUniqueInstance_ = this; 471 +} 472 + 473 +MemoryManager::~MemoryManager() 474 +{ 475 +#if defined(SUPERTINY) && defined(_DEBUG) 476 + // リーク検出用 477 + if( allocCounter != 0 ) 478 + ::MessageBox( NULL, TEXT("MemoryLeak!"), NULL, MB_OK ); 479 +#endif 480 +} 481 + 482 +void* MemoryManager::Alloc( size_t siz ) 483 +{ 484 + return ::operator new(siz); 485 +} 486 + 487 +void MemoryManager::DeAlloc( void* ptr, size_t siz ) 488 +{ 489 + ::operator delete(ptr); 490 +} 491 + 492 +#endif
Added kilib/memory.h version [191649d03470b28c]
1 +#ifndef _KILIB_MEMORY_H_ 2 +#define _KILIB_MEMORY_H_ 3 +#include "types.h" 4 +#include "thread.h" 5 +#ifndef __ccdoc__ 6 +namespace ki { 7 +#endif 8 + 9 + 10 +// W版ではHeapAllocを直接呼び出すバージョンを使う 11 +//#if !defined(_UNICODE) && defined(SUPERTINY) 12 +// #define USE_ORIGINAL_MEMMAN 13 +//#endif 14 + 15 +// 小規模と見なすオブジェクトの最大サイズ 16 +#define SMALL_MAX 64 17 +// 一度に確保するヒープブロックのサイズ 18 +#define BLOCK_SIZ 4096 19 +// 内部実装 20 +struct MemBlock; 21 + 22 + 23 + 24 +//========================================================================= 25 +//@{ @pkg ki.Memory //@} 26 +//@{ 27 +// メモリ割り当て・解放機構 28 +// 29 +// SUPERTINYオプションを付けてコンパイルすると、標準の 30 +// mallocやfreeを使えなくなるため、HeapAlloc等のAPIを 31 +// 直接呼び出す必要が出てきます。しかし、こいつらを本当に 32 +// 毎回直に呼んでいると、遅い。もうアホかと、バカかと、 33 +// って勢いで遅い。そこで、主にnewで動的に小規模メモリを 34 +// 確保することに主眼を据えた簡単なアロケータを使うことにしました。 35 +// 36 +// <a href="http://cseng.aw.com/book/0,3828,0201704315,00.html">loki</a> 37 +// ライブラリほぼそのまんまな実装です。 38 +//@} 39 +//========================================================================= 40 + 41 +class MemoryManager : public EzLockable 42 +{ 43 +public: 44 + 45 + //@{ メモリ割り当て //@} 46 + void* Alloc( size_t siz ); 47 + 48 + //@{ メモリ解放 //@} 49 + void DeAlloc( void* ptr, size_t siz ); 50 + 51 +#ifdef USE_ORIGINAL_MEMMAN 52 +private: 53 + struct FixedSizeMemBlockPool 54 + { 55 + void Construct( byte siz ); 56 + void Destruct(); 57 + void* Alloc(); 58 + void DeAlloc( void* ptr ); 59 + bool isValid(); 60 + private: 61 + MemBlock* blocks_; 62 + int blockNum_; 63 + int blockNumReserved_; 64 + byte fixedSize_; 65 + byte numPerBlock_; 66 + int lastA_; 67 + int lastDA_; 68 + }; 69 + FixedSizeMemBlockPool pools_[ SMALL_MAX ]; 70 +#endif 71 + 72 +private: 73 + 74 + MemoryManager(); 75 + ~MemoryManager(); 76 + 77 +private: 78 + 79 + static MemoryManager* pUniqueInstance_; 80 + 81 +private: 82 + 83 + friend void APIENTRY Startup(); 84 + friend inline MemoryManager& mem(); 85 + NOCOPY(MemoryManager); 86 +}; 87 + 88 + 89 + 90 +//------------------------------------------------------------------------- 91 + 92 +//@{ 唯一のメモリ管理オブジェクトを返す //@} 93 +inline MemoryManager& mem() 94 + { return *MemoryManager::pUniqueInstance_; } 95 + 96 +//@{ ゼロ埋め作業 //@} 97 +inline void mem00( void* ptrv, int siz ) 98 + { BYTE* ptr = (BYTE*)ptrv; 99 + for(;siz>3;siz-=4,ptr+=4) *(DWORD*)ptr = 0x00000000; 100 + for(;siz;--siz,++ptr) *ptr = 0x00; } 101 + 102 +//@{ FF埋め作業 //@} 103 +inline void memFF( void* ptrv, int siz ) 104 + { BYTE* ptr = (BYTE*)ptrv; 105 + for(;siz>3;siz-=4,ptr+=4) *(DWORD*)ptr = 0xffffffff; 106 + for(;siz;--siz,++ptr) *ptr = 0xff; } 107 + 108 + 109 + 110 +//========================================================================= 111 +//@{ 112 +// 標準基底クラス 113 +// 114 +// JavaのObject や MFCのCObject みたいに使う…わけではなく、 115 +// 単にここから派生すると自動で operator new/delete が高速版に 116 +// なるので便利だよ、という使い方のための基底クラスです。 117 +//@} 118 +//========================================================================= 119 + 120 +class Object 121 +{ 122 +#ifdef USE_ORIGINAL_MEMMAN 123 +public: 124 + 125 + static void* operator new( size_t siz ) 126 + { return mem().Alloc( siz ); } 127 + 128 + static void operator delete( void* ptr, size_t siz ) 129 + { mem().DeAlloc( ptr, siz ); } 130 +#endif 131 + 132 +protected: 133 + virtual ~Object() 134 + {} 135 +}; 136 + 137 + 138 + 139 +//========================================================================= 140 + 141 +} // namespace ki 142 +#endif // _KILIB_MEMORY_H_
Added kilib/path.cpp version [a6dcd62277a4d8c5]
1 +#include "stdafx.h" 2 +#include "path.h" 3 +using namespace ki; 4 + 5 + 6 + 7 +//========================================================================= 8 + 9 +Path& Path::BeSpecialPath( int nPATH, bool bs ) 10 +{ 11 + TCHAR* buf = AllocMem( MAX_PATH+1 ); 12 + 13 + switch( nPATH ) 14 + { 15 + case Win: ::GetWindowsDirectory( buf, MAX_PATH ); break; 16 + case Sys: ::GetSystemDirectory( buf, MAX_PATH ); break; 17 + case Tmp: ::GetTempPath( MAX_PATH, buf ); break; 18 + case Cur: ::GetCurrentDirectory( MAX_PATH, buf ); break; 19 + case Exe: 20 + case ExeName: ::GetModuleFileName( NULL, buf, MAX_PATH ); break; 21 + default: 22 + *buf = TEXT('\0'); 23 + { 24 + LPITEMIDLIST il; 25 + if( NOERROR==::SHGetSpecialFolderLocation( NULL, nPATH, &il ) ) 26 + { 27 + ::SHGetPathFromIDList( il, buf ); 28 + ::CoTaskMemFree( il ); 29 + } 30 + } 31 + } 32 + 33 + UnlockMem(); 34 + if( nPATH != ExeName ) 35 + { 36 + if( nPATH == Exe ) 37 + BeDirOnly(); 38 + BeBackSlash( bs ); 39 + } 40 + return *this; 41 +} 42 + 43 +Path& Path::BeBackSlash( bool add ) 44 +{ 45 + // 最後の一文字を得る 46 + const TCHAR* last=c_str(); 47 + for( const TCHAR *p=last; *p!=TEXT('\0'); p=next(p) ) 48 + last = p; 49 + 50 + if( *last==TEXT('\\') || *last==TEXT('/') ) 51 + { 52 + if( !add ) 53 + TrimRight( 1 ); 54 + } 55 + else if( add && *last!=TEXT('\0') ) 56 + { 57 + *this += TEXT('\\'); 58 + } 59 + 60 + return *this; 61 +} 62 + 63 +Path& Path::BeDirOnly() 64 +{ 65 + const TCHAR* lastslash = c_str()-1; 66 + for( const TCHAR* p=lastslash+1; *p!=TEXT('\0'); p=next(p) ) 67 + if( *p==TEXT('\\') || *p==TEXT('/') ) 68 + lastslash = p; 69 + 70 + TrimRight( len() - ulong((lastslash+1)-c_str()) ); 71 + return *this; 72 +} 73 + 74 +Path& Path::BeDriveOnly() 75 +{ 76 + if( len() > 2 ) 77 + { 78 + const TCHAR* p = c_str()+2; 79 + for( ; *p!=TEXT('\0'); p=next(p) ) 80 + if( *p==TEXT('\\') || *p==TEXT('/') ) 81 + break; 82 + if( *p!=TEXT('\0') ) 83 + TrimRight( len() - ulong((p+1)-c_str()) ); 84 + } 85 + return *this; 86 +} 87 + 88 +Path& Path::BeShortStyle() 89 +{ 90 + TCHAR* buf = ReallocMem( len()+1 ); 91 + ::GetShortPathName( buf, buf, len()+1 ); 92 + UnlockMem(); 93 + return *this; 94 +} 95 + 96 +Path& Path::BeShortLongStyle() 97 +{ 98 + WIN32_FIND_DATA fd; 99 + HANDLE h = ::FindFirstFile( c_str(), &fd ); 100 + if( h == INVALID_HANDLE_VALUE ) 101 + return *this; 102 + ::FindClose( h ); 103 + 104 + TCHAR t; 105 + TCHAR* buf = ReallocMem( MAX_PATH*2 ); 106 + TCHAR* nam = const_cast<TCHAR*>(name(buf)); 107 + 108 + if( nam != buf ) 109 + t = *(nam-1), *(nam-1) = TEXT('\0'); 110 + ::lstrcpy( nam, fd.cFileName ); 111 + if( nam != buf ) 112 + *(nam-1) = t; 113 + 114 + UnlockMem(); 115 + return *this; 116 +} 117 + 118 +String Path::CompactIfPossible( int Mx ) 119 +{ 120 + HMODULE hshl = ::LoadLibrary( TEXT("shlwapi.dll") ); 121 + if( !hshl ) return *this; 122 + 123 + typedef BOOL (STDAPICALLTYPE *PCPE_t)( LPTSTR, LPCTSTR, UINT, DWORD ); 124 +#ifdef _UNICODE 125 + PCPE_t MyPathCompactPathEx = (PCPE_t)::GetProcAddress( hshl, "PathCompactPathExW" ); 126 +#else 127 + PCPE_t MyPathCompactPathEx = (PCPE_t)::GetProcAddress( hshl, "PathCompactPathExA" ); 128 +#endif 129 + if( !MyPathCompactPathEx ) return *this; 130 + 131 + TCHAR* buf = new TCHAR[Mx+2]; 132 + MyPathCompactPathEx( buf, c_str(), Mx+1, 0 ); 133 + ::FreeLibrary( hshl ); 134 + 135 + String ans = buf; 136 + delete [] buf; 137 + return ans; 138 +} 139 + 140 +const TCHAR* Path::name( const TCHAR* str ) 141 +{ 142 + const TCHAR* ans = str - 1; 143 + for( const TCHAR* p=str; *p!=TEXT('\0'); p=next(p) ) 144 + if( *p==TEXT('\\') || *p==TEXT('/') ) 145 + ans = p; 146 + return (ans+1); 147 +} 148 + 149 +const TCHAR* Path::ext( const TCHAR* str ) 150 +{ 151 + const TCHAR *ans = NULL, *p; 152 + for( p=name(str); *p!=TEXT('\0'); p=next(p) ) 153 + if( *p==TEXT('.') ) 154 + ans = p; 155 + return ans ? (ans+1) : p; 156 +} 157 + 158 +const TCHAR* Path::ext_all( const TCHAR* str ) 159 +{ 160 + const TCHAR* p; 161 + for( p=name(str); *p!=TEXT('\0'); p=next(p) ) 162 + if( *p==TEXT('.') ) 163 + return (p+1); 164 + return p; 165 +} 166 + 167 +Path Path::body() const 168 +{ 169 + const TCHAR* nm = name(); 170 + const TCHAR* ex = ext() - 1; 171 + TCHAR t = *ex; 172 + *const_cast<TCHAR*>(ex) = TEXT('\0'); 173 + Path ans = nm; 174 + *const_cast<TCHAR*>(ex) = t; 175 + return ans; 176 +} 177 + 178 +Path Path::body_all() const 179 +{ 180 + const TCHAR* nm = name(); 181 + const TCHAR* ex = ext_all() - 1; 182 + TCHAR t = *ex; 183 + *const_cast<TCHAR*>(ex) = TEXT('\0'); 184 + Path ans = nm; 185 + *const_cast<TCHAR*>(ex) = t; 186 + return ans; 187 +} 188 +
Added kilib/path.h version [7bb4e3d9e7ec55cc]
1 +#ifndef _KILIB_PATH_H_ 2 +#define _KILIB_PATH_H_ 3 +#include "types.h" 4 +#include "string.h" 5 +#ifndef __ccdoc__ 6 +namespace ki { 7 +#endif 8 + 9 + 10 + 11 +//========================================================================= 12 +//@{ @pkg ki.StdLib //@} 13 +//@{ 14 +// ファイル名処理 15 +// 16 +// 基本的には文字列ですが、特にファイル名として扱うときに便利な 17 +// クラスです。名前部分のみ取り出しとか拡張子のみ取り出しとか、 18 +// 属性を取ってくるとか色々。 19 +//@} 20 +//========================================================================= 21 + 22 +class Path : public String 23 +{ 24 +public: 25 + 26 + Path() {} 27 + 28 + //@{ 別のPathのコピー //@} 29 + Path( const Path& s ) : String( s ){} 30 + Path( const String& s ) : String( s ){} 31 + Path( const TCHAR* s, long siz=-1 ) : String( s, siz ){} 32 + 33 + //@{ 単純代入 //@} 34 + Path& operator=( const Path& s ) 35 + { return static_cast<Path&>(String::operator=(s)); } 36 + Path& operator=( const String& s ) 37 + { return static_cast<Path&>(String::operator=(s)); } 38 + Path& operator=( const TCHAR* s ) 39 + { return static_cast<Path&>(String::operator=(s)); } 40 + 41 + //@{ 加算代入 //@} 42 + Path& operator+=( const Path& s ) 43 + { return static_cast<Path&>(String::operator+=(s)); } 44 + Path& operator+=( const String& s ) 45 + { return static_cast<Path&>(String::operator+=(s)); } 46 + Path& operator+=( const TCHAR* s ) 47 + { return static_cast<Path&>(String::operator+=(s)); } 48 + Path& operator+=( TCHAR c ) 49 + { return static_cast<Path&>(String::operator+=(c)); } 50 + 51 + //@{ 特殊パス取得して初期化 //@} 52 + explicit Path( int nPATH, bool bs=true ) 53 + { BeSpecialPath( nPATH, bs ); } 54 + 55 + //@{ 特殊パス取得 //@} 56 + Path& BeSpecialPath( int nPATH, bool bs=true ); 57 + 58 + //@{ 特殊パス指定用定数 //@} 59 + enum { Win=0x1787, Sys, Tmp, Exe, Cur, ExeName, 60 + Snd=CSIDL_SENDTO, Dsk=CSIDL_DESKTOPDIRECTORY }; 61 + 62 + //@{ 最後にバックスラッシュを入れる(true)/入れない(false) //@} 63 + Path& BeBackSlash( bool add ); 64 + 65 + //@{ ドライブ名ないしルートのみ //@} 66 + Path& BeDriveOnly(); 67 + 68 + //@{ ディレクトリ名のみ //@} 69 + Path& BeDirOnly(); 70 + 71 + //@{ 短いパス名 //@} 72 + Path& BeShortStyle(); 73 + 74 + //@{ ファイル名だけは確実に長く //@} 75 + Path& BeShortLongStyle(); 76 + 77 + //@{ ...とかを入れて短く //@} 78 + String CompactIfPossible(int Mx); 79 + 80 + //@{ ディレクトリ情報以外 //@} 81 + const TCHAR* name() const; 82 + 83 + //@{ 最後の拡張子 //@} 84 + const TCHAR* ext() const; 85 + 86 + //@{ 最初の.以降全部と見なした拡張子 //@} 87 + const TCHAR* ext_all() const; 88 + 89 + //@{ ディレクトリ情報と最後の拡張子を除いた名前部分 //@} 90 + Path body() const; 91 + 92 + //@{ ディレクトリ情報と最初の.以降全部を除いた名前部分 //@} 93 + Path body_all() const; 94 + 95 +public: 96 + 97 + //@{ ファイルかどうか //@} 98 + bool isFile() const; 99 + 100 + //@{ ディレクトリかどうか //@} 101 + bool isDirectory() const; 102 + 103 + //@{ 存在するかどうか。isFile() || isDirectory() //@} 104 + bool exist() const; 105 + 106 + //@{ 読み取り専用かどうか //@} 107 + bool isReadOnly() const; 108 + 109 +public: 110 + 111 + static const TCHAR* name( const TCHAR* str ); 112 + static const TCHAR* ext( const TCHAR* str ); 113 + static const TCHAR* ext_all( const TCHAR* str ); 114 +}; 115 + 116 + 117 + 118 +//------------------------------------------------------------------------- 119 + 120 +inline bool Path::isFile() const 121 + { return 0==(::GetFileAttributes(c_str())&FILE_ATTRIBUTE_DIRECTORY); } 122 + 123 +inline bool Path::isDirectory() const 124 + { DWORD x=::GetFileAttributes(c_str()); 125 + return x!=0xffffffff && (x&FILE_ATTRIBUTE_DIRECTORY)!=0; } 126 + 127 +inline bool Path::exist() const 128 + { return 0xffffffff != ::GetFileAttributes(c_str()); } 129 + 130 +inline bool Path::isReadOnly() const 131 + { DWORD x=::GetFileAttributes(c_str()); 132 + return x!=0xffffffff && (x&FILE_ATTRIBUTE_READONLY)!=0; } 133 + 134 +inline const TCHAR* Path::name() const 135 + { return name(c_str()); } 136 + 137 +inline const TCHAR* Path::ext() const 138 + { return ext(c_str()); } 139 + 140 +inline const TCHAR* Path::ext_all() const 141 + { return ext_all(c_str()); } 142 + 143 + 144 + 145 +//========================================================================= 146 + 147 +} // namespace ki 148 +#endif // _KILIB_PATH_H_
Added kilib/registry.cpp version [19acfb259dd8987f]
1 +#include "stdafx.h" 2 +#include "registry.h" 3 +using namespace ki; 4 + 5 + 6 + 7 +//========================================================================= 8 + 9 +void IniFile::SetFileName( const TCHAR* ini, bool exepath ) 10 +{ 11 + iniName_ = 12 + (exepath ? iniName_.BeSpecialPath(Path::Exe) : Path(TEXT(""))); 13 + if( ini != NULL ) 14 + iniName_ += ini; 15 + else 16 + iniName_ += (Path(Path::ExeName).body()+=TEXT(".ini")); 17 +} 18 + 19 +void IniFile::SetSectionAsUserName() 20 +{ 21 + TCHAR usr[256]; 22 + DWORD siz = countof(usr); 23 + if( !::GetUserName( usr, &siz ) ) 24 + ::lstrcpy( usr, TEXT("Default") ); 25 + SetSection( usr ); 26 +} 27 + 28 +bool IniFile::HasSectionEnabled( const TCHAR* section ) const 29 +{ 30 + return (0!=::GetPrivateProfileInt( 31 + section, TEXT("Enable"), 0, iniName_.c_str() )); 32 +} 33 + 34 +int IniFile::GetInt ( const TCHAR* key, int defval ) const 35 +{ 36 + return ::GetPrivateProfileInt( 37 + section_.c_str(), key, defval, iniName_.c_str() ); 38 +} 39 + 40 +bool IniFile::GetBool( const TCHAR* key, bool defval ) const 41 +{ 42 + return (0!=::GetPrivateProfileInt( 43 + section_.c_str(), key, defval?1:0, iniName_.c_str() )); 44 +} 45 + 46 +String IniFile::GetStr ( const TCHAR* key, const String& defval ) const 47 +{ 48 + RawString str; 49 + ulong l=256, s; 50 + for(;;) 51 + { 52 + TCHAR* x = str.AllocMem(l); 53 + s = ::GetPrivateProfileString( section_.c_str(), key, 54 + defval.c_str(), x, l, iniName_.c_str() ); 55 + if( s < l-1 ) 56 + break; 57 + l <<= 1; 58 + } 59 + str.UnlockMem(); 60 + return str; 61 +} 62 + 63 +Path IniFile::GetPath( const TCHAR* key, const Path& defval ) const 64 +{ 65 +#ifdef _UNICODE 66 + String s = GetStr( key, defval ); 67 + if( s.len()==0 || s[0]!='#' ) 68 + return s; 69 + 70 + // UTF-decoder 71 + String buf; 72 + for(uint i=0; 4*i+4<s.len(); ++i) 73 + { 74 + unsigned short v = 0; 75 + for(int j=1; j<=4; ++j) 76 + { 77 + int ch = s[4*i+j]; 78 + if( '0'<=ch && ch<='9' ) v = 16*v + ch-'0'; 79 + if( 'a'<=ch && ch<='z' ) v = 16*v + ch-'a'+10; 80 + if( 'A'<=ch && ch<='Z' ) v = 16*v + ch-'A'+10; 81 + } 82 + buf += (wchar_t) v; 83 + } 84 + return buf; 85 +#else 86 + return GetStr( key, defval ); 87 +#endif 88 +} 89 + 90 + 91 +bool IniFile::PutStr ( const TCHAR* key, const TCHAR* val ) 92 +{ 93 + if( val[0]==TEXT('"') && val[::lstrlen(val)-1]==TEXT('"') ) 94 + { 95 + // 両端に " があると勝手に削られるので対処 96 + String nval; 97 + nval += TEXT('"'); 98 + nval += val; 99 + nval += TEXT('"'); 100 + return (FALSE != ::WritePrivateProfileString( 101 + section_.c_str(), key, nval.c_str(), iniName_.c_str() ) ); 102 + } 103 + else 104 + { 105 + return (FALSE != ::WritePrivateProfileString( 106 + section_.c_str(), key, val, iniName_.c_str() ) ); 107 + } 108 +} 109 + 110 +bool IniFile::PutInt ( const TCHAR* key, int val ) 111 +{ 112 + TCHAR buf[20]; 113 + ::wsprintf( buf, TEXT("%d"), val ); 114 + return PutStr( key, buf ); 115 +} 116 + 117 +bool IniFile::PutBool( const TCHAR* key, bool val ) 118 +{ 119 + return PutStr( key, val ? TEXT("1") : TEXT("0") ); 120 +} 121 + 122 +bool IniFile::PutPath( const TCHAR* key, const Path& val ) 123 +{ 124 +#ifdef _UNICODE 125 + BOOL err = FALSE; 126 + ::WideCharToMultiByte( CP_ACP, 0, val.c_str(), -1, NULL, 0, NULL, &err ); 127 + if( !err ) 128 + return PutStr( key , val.c_str() ); 129 + 130 + // UTF-encoder 131 + const TCHAR* hex = TEXT("0123456789abcdef"); 132 + String buf = TEXT("#"); 133 + for(int i=0; i!=val.len(); ++i) 134 + { 135 + unsigned short u = (unsigned short) val[i]; 136 + buf += hex[(u>>12) & 0xf]; 137 + buf += hex[(u>> 8) & 0xf]; 138 + buf += hex[(u>> 4) & 0xf]; 139 + buf += hex[(u>> 0) & 0xf]; 140 + } 141 + return PutStr( key, buf.c_str() ); 142 +#else 143 + return PutStr( key, val.c_str() ); 144 +#endif 145 +} 146 + 147 +
Added kilib/registry.h version [017afe9c288f9f71]
1 +#ifndef _KILIB_REGISTRY_H_ 2 +#define _KILIB_REGISTRY_H_ 3 +#include "types.h" 4 +#include "memory.h" 5 +#include "path.h" 6 +#ifndef __ccdoc__ 7 +namespace ki { 8 +#endif 9 + 10 + 11 + 12 +//========================================================================= 13 +//@{ @pkg ki.WinUtil //@} 14 +//@{ 15 +// INIファイル読み込み 16 +// 17 +//@} 18 +//========================================================================= 19 + 20 +class IniFile : public Object 21 +{ 22 +public: 23 + 24 + //@{ コンストラクタ //@} 25 + IniFile( const TCHAR* ini=NULL, bool exeppath=true ); 26 + 27 + //@{ iniファイル名を設定 //@} 28 + void SetFileName( const TCHAR* ini=NULL, bool exepath=true ); 29 + 30 + //@{ セクション名を設定 //@} 31 + void SetSection( const TCHAR* section ); 32 + 33 + //@{ セクション名をユーザー名に設定 //@} 34 + void SetSectionAsUserName(); 35 + 36 + //@{ ある特定の名前のセクションがあるかどうか? //@} 37 + bool HasSectionEnabled( const TCHAR* section ) const; 38 + 39 + //@{ 整数値読み込み //@} 40 + int GetInt ( const TCHAR* key, int defval ) const; 41 + //@{ 真偽値読み込み //@} 42 + bool GetBool( const TCHAR* key, bool defval ) const; 43 + //@{ 文字列読み込み //@} 44 + String GetStr ( const TCHAR* key, const String& defval ) const; 45 + //@{ パス文字列読み込み //@} 46 + Path GetPath ( const TCHAR* key, const Path& defval ) const; 47 + 48 + //@{ 整数値書き込み //@} 49 + bool PutInt ( const TCHAR* key, int val ); 50 + //@{ 真偽値書き込み //@} 51 + bool PutBool( const TCHAR* key, bool val ); 52 + //@{ 文字列書き込み //@} 53 + bool PutStr ( const TCHAR* key, const TCHAR* val ); 54 + //@{ パス書き込み //@} 55 + bool PutPath( const TCHAR* key, const Path& val ); 56 + 57 +private: 58 + 59 + Path iniName_; 60 + String section_; 61 + char m_StrBuf[256]; 62 +}; 63 + 64 + 65 + 66 +//------------------------------------------------------------------------- 67 + 68 +inline IniFile::IniFile( const TCHAR* ini, bool exepath ) 69 + { SetFileName( ini, exepath ); } 70 + 71 +inline void IniFile::SetSection( const TCHAR* section ) 72 + { section_ = section; } 73 + 74 + 75 + 76 + 77 +//========================================================================= 78 + 79 +} // namespace ki 80 +#endif // _KILIB_REGISTRY_H_
Added kilib/stdafx.cpp version [93c3ae4d1bf237d8]
1 +#include "stdafx.h"
Added kilib/stdafx.h version [bb450c1d9108af87]
1 +#ifndef _KILIB_STDAFX_H_ 2 +#define _KILIB_STDAFX_H_ 3 + 4 +#undef WINVER 5 +#define WINVER 0x0400 6 +#undef _WIN32_IE 7 +#define _WIN32_IE 0x0200 8 +#undef _WIN32_WINNT 9 +#define _WIN32_WINNT 0x0400 10 + 11 +#define OEMRESOURCE 12 +#define NOMINMAX 13 +#ifdef SUPERTINY 14 + #define memset memset_default 15 +#endif 16 + 17 +#include <windows.h> 18 +#include <shlobj.h> 19 +#include <commdlg.h> 20 +#include <commctrl.h> 21 +#include <imm.h> 22 +// dimm.hが無くてエラーになる場合、プロジェクトの設定でUSEGLOBALIMEの定義を 23 +// 削除するか、最新の Platform SDK を導入すればビルドが通るようになります。 24 +#ifdef USEGLOBALIME 25 +#include <dimm.h> 26 +#endif 27 + 28 +#ifdef SUPERTINY 29 + #undef memset 30 +#endif 31 + 32 +#ifndef WM_MOUSEWHEEL 33 +#define WM_MOUSEWHEEL 0x020A 34 +#endif 35 +#ifndef OFN_ENABLESIZING 36 +#define OFN_ENABLESIZING 0x00800000 37 +#endif 38 +#ifndef IMR_RECONVERTSTRING 39 +#define IMR_RECONVERTSTRING 0x0004 40 +#define IMR_CONFIRMRECONVERTSTRING 0x0005 41 +typedef struct tagRECONVERTSTRING { 42 + DWORD dwSize; 43 + DWORD dwVersion; 44 + DWORD dwStrLen; 45 + DWORD dwStrOffset; 46 + DWORD dwCompStrLen; 47 + DWORD dwCompStrOffset; 48 + DWORD dwTargetStrLen; 49 + DWORD dwTargetStrOffset; 50 +} RECONVERTSTRING, *PRECONVERTSTRING, NEAR *NPRECONVERTSTRING, FAR *LPRECONVERTSTRING; 51 +#endif 52 +#ifndef WM_IME_REQUEST 53 +#define WM_IME_REQUEST 0x0288 54 +#endif 55 + 56 +#ifdef _MSC_VER 57 +#pragma warning( disable: 4355 ) 58 +#endif 59 + 60 +#ifdef __DMC__ 61 + #define SetWindowLongPtr SetWindowLong 62 + #define GetWindowLongPtr GetWindowLong 63 + #define UINT_PTR UINT 64 + #define LONG_PTR LONG 65 + #define GWLP_WNDPROC GWL_WNDPROC 66 + #define GWLP_USERDATA GWL_USERDATA 67 +#endif 68 + 69 +#endif // _KILIB_STDAFX_H_
Added kilib/string.cpp version [9d4f2283a9450bb3]
1 +#include "stdafx.h" 2 +#include "app.h" 3 +#include "memory.h" 4 +#include "string.h" 5 +using namespace ki; 6 + 7 + 8 + 9 +//========================================================================= 10 + 11 +String::StringData* String::nullData_; 12 +char String::lb_[256]; 13 + 14 +void String::LibInit() 15 +{ 16 + static int nullstr_image[4]; 17 + nullstr_image[0] = 1; 18 + nullstr_image[1] = 1; 19 + nullstr_image[2] = 4; 20 + nullData_ = reinterpret_cast<StringData*>(nullstr_image); 21 + 22 +#if !defined(_UNICODE) && defined(_MBCS) 23 + for( int c=0; c<256; ++c ) 24 + lb_[c] = (::IsDBCSLeadByte(c) ? 2 : 1); 25 +#endif 26 +} 27 + 28 + 29 + 30 +//------------------------------------------------------------------------- 31 + 32 +String::String( const TCHAR* s, long len ) 33 +{ 34 + // 長さ指定が無い場合は計算 35 + if( len==-1 ) 36 + len = ::lstrlen(s); 37 + 38 + if( len==0 ) 39 + { 40 + // 0文字用の特殊バッファ 41 + SetData( null() ); 42 + } 43 + else 44 + { 45 + // 新規バッファ作成 46 + data_ = static_cast<StringData*> 47 + (mem().Alloc( sizeof(StringData)+(len+1)*sizeof(TCHAR) )); 48 + data_->ref = 1; 49 + data_->len = len+1; 50 + data_->alen = len+1; 51 + memmove( data_+1, s, (len+1)*sizeof(TCHAR) ); 52 + } 53 +} 54 + 55 +inline void String::ReleaseData() 56 +{ 57 + if( --data_->ref <= 0 ) 58 + mem().DeAlloc( 59 + data_, sizeof(StringData)+sizeof(TCHAR)*data_->alen ); 60 +} 61 + 62 +String::~String() 63 +{ 64 + ReleaseData(); 65 +} 66 + 67 +TCHAR* String::ReallocMem( ulong minimum=0 ) 68 +{ 69 + return AllocMemHelper( minimum, c_str(), len()+1 ); 70 +} 71 + 72 +String& String::SetString( const TCHAR* str, ulong siz ) 73 +{ 74 + TCHAR* buf = AllocMem( siz+1 ); 75 + 76 + memmove( buf, str, siz*sizeof(TCHAR) ); 77 + buf[siz] = TEXT('\0'); 78 + 79 + UnlockMem( siz ); 80 + return *this; 81 +} 82 + 83 +String& String::CatString( const TCHAR* str, ulong siz ) 84 +{ 85 + const int plen = len(); 86 + TCHAR* buf = ReallocMem( plen + siz + 1 ); 87 + 88 + memmove( buf+plen, str, siz*sizeof(TCHAR) ); 89 + buf[plen+siz] = TEXT('\0'); 90 + 91 + UnlockMem( plen+siz ); 92 + return *this; 93 +} 94 + 95 +TCHAR* String::AllocMemHelper( ulong minimum, const TCHAR* str, ulong siz ) 96 +{ 97 + if( data_->ref > 1 || data_->alen < minimum ) 98 + { 99 + minimum = Max( minimum, data_->alen ); 100 + 101 + StringData* pNew = static_cast<StringData*> 102 + (mem().Alloc( sizeof(StringData)+minimum*sizeof(TCHAR) )); 103 + pNew->ref = 1; 104 + pNew->alen = minimum; 105 + pNew->len = siz; 106 + memmove( pNew->buf(), str, siz*sizeof(TCHAR) ); 107 + 108 + ReleaseData(); 109 + data_ = pNew; 110 + } 111 + 112 + return data_->buf(); 113 +} 114 + 115 +String& String::operator = ( const String& obj ) 116 +{ 117 + if( data() != obj.data() ) 118 + { 119 + ReleaseData(); 120 + SetData( obj.data() ); 121 + } 122 + return *this; 123 +} 124 + 125 +#ifdef _UNICODE 126 +String& String::operator = ( const char* s ) 127 +{ 128 + long len = ::MultiByteToWideChar( CP_ACP, 0, s, -1, NULL, 0 ); 129 + ::MultiByteToWideChar( CP_ACP, 0, s, -1, AllocMem(len+1), len+1 ); 130 +#else 131 +String& String::operator = ( const wchar_t* s ) 132 +{ 133 + long len = ::WideCharToMultiByte(CP_ACP,0,s,-1,NULL,0,NULL,NULL); 134 + ::WideCharToMultiByte(CP_ACP,0,s,-1,AllocMem(len+1),len+1,NULL,NULL); 135 +#endif 136 + UnlockMem( len ); 137 + return *this; 138 +} 139 + 140 +String& String::Load( UINT rsrcID ) 141 +{ 142 + const int step=256; 143 + 144 + // 256バイトの固定長バッファへまず読んでみる 145 + TCHAR tmp[step], *buf; 146 + int red = app().LoadString( rsrcID, tmp, countof(tmp) ); 147 + if( countof(tmp) - red > 2 ) 148 + return (*this = tmp); 149 + 150 + // 少しずつ増やして対応してみる 151 + int siz = step; 152 + do 153 + { 154 + siz+= step; 155 + buf = AllocMem( siz ); 156 + red = app().LoadString( rsrcID, buf, siz ); 157 + } while( siz - red <= 2 ); 158 + 159 + buf[red] = TEXT('\0'); 160 + UnlockMem( red ); 161 + return *this; 162 +} 163 + 164 +void String::TrimRight( ulong siz ) 165 +{ 166 + if( siz >= len() ) 167 + { 168 + ReleaseData(); 169 + SetData( null() ); 170 + } 171 + else 172 + { 173 + // 文字列バッファの参照カウントを確実に1にする 174 + ReallocMem(); 175 + 176 + // 指定文字数分削る 177 + data_->len -= siz; 178 + data_->buf()[data_->len-1] = TEXT('\0'); 179 + } 180 +} 181 + 182 +int String::GetInt( const TCHAR* x ) 183 +{ 184 + int n=0; 185 + bool minus = (*x==TEXT('-')); 186 + for( const TCHAR* p=(minus?x+1:x); *p!=TEXT('\0'); p=next(p) ) 187 + { 188 + if( *p<TEXT('0') || TEXT('9')<*p ) 189 + return 0; 190 + n = (10*n) + (*p-TEXT('0')); 191 + } 192 + return minus ? -n : n; 193 +} 194 + 195 +String& String::SetInt( int n ) 196 +{ 197 + if( n==0 ) 198 + { 199 + *this = TEXT("0"); 200 + } 201 + else 202 + { 203 + bool minus = (n<0); 204 + if( minus ) 205 + n= -n; 206 + 207 + TCHAR tmp[20]; 208 + tmp[19] = TEXT('\0'); 209 + int i; 210 + 211 + for( i=18; i>=0; --i ) 212 + { 213 + tmp[i] = TEXT('0') + n%10; 214 + n /= 10; 215 + if( n==0 ) 216 + break; 217 + } 218 + 219 + if( minus ) 220 + tmp[--i] = TEXT('-'); 221 + 222 + *this = tmp+i; 223 + } 224 + return *this; 225 +} 226 + 227 +const wchar_t* String::ConvToWChar() const 228 +{ 229 +#ifdef _UNICODE 230 + return c_str(); 231 +#else 232 + int ln = ::MultiByteToWideChar( CP_ACP, 0, c_str(), -1 , 0, 0 ); 233 + wchar_t* p = new wchar_t[ln+1]; 234 + ::MultiByteToWideChar( CP_ACP, 0, c_str(), -1 , p, ln+1 ); 235 + return p; 236 +#endif 237 +} 238 +
Added kilib/string.h version [9ee1f8a2b0ea71f4]
1 +#ifndef _KILIB_STRING_H_ 2 +#define _KILIB_STRING_H_ 3 +#include "types.h" 4 +#include "memory.h" 5 +#include "ktlaptr.h" 6 +#ifndef __ccdoc__ 7 +namespace ki { 8 +#endif 9 +#ifdef _UNICODE 10 + #define XTCHAR char 11 +#else 12 + #define XTCHAR wchar_t 13 +#endif 14 + 15 + 16 + 17 +//========================================================================= 18 +//@{ @pkg ki.StdLib //@} 19 +//@{ 20 +// 文字列処理 21 +// 22 +// かなりMFCのCStringをパクってます。とりあえず operator= による 23 +// 単純代入にはほとんどコストがかからないようにしました。SubStr()の 24 +// 時もコピーしないようにしようかとも思ったんですが、そこまでは 25 +// 要らないだろうという気もするので…。 26 +//@} 27 +//========================================================================= 28 + 29 +class String : public Object 30 +{ 31 +public: 32 + 33 + //@{ 空文字列作成 //@} 34 + String(); 35 + ~String(); 36 + 37 + //@{ 別のStringのコピー //@} 38 + String( const String& obj ); 39 + 40 + //@{ 別の文字配列のコピー //@} 41 + String( const TCHAR* str, long siz=-1 ); 42 + 43 + //@{ リソースから作成 //@} 44 + explicit String( UINT rsrcID ); 45 + 46 + //@{ 大文字小文字を区別する比較 //@} 47 + bool operator==( LPCTSTR s ) const; 48 + bool operator==( const String& obj ) const; 49 + 50 + //@{ 大文字小文字を区別しない比較 //@} 51 + bool isSame( LPCTSTR s ) const; 52 + bool isSame( const String& obj ) const; 53 + 54 + //@{ 単純代入 //@} 55 + String& operator=( const String& obj ); 56 + String& operator=( const TCHAR* s ); 57 + String& operator=( const XTCHAR* s ); 58 + 59 + //@{ 加算代入 //@} 60 + String& operator+=( const String& obj ); 61 + String& operator+=( const TCHAR* s ); 62 + String& operator+=( TCHAR c ); 63 + 64 + //@{ リソースロード //@} 65 + String& Load( UINT rsrcID ); 66 + 67 + //@{ 右を削る //@} 68 + void TrimRight( ulong siz ); 69 + 70 + //@{ intから文字列へ変換 //@} 71 + String& SetInt( int n ); 72 + 73 + //@{ 文字列からintへ変換 //@} 74 + int GetInt(); 75 + 76 +public: 77 + 78 + //@{ 文字列バッファを返す //@} 79 + const TCHAR* c_str() const; 80 + 81 + //@{ 長さ //@} 82 + ulong len() const; 83 + 84 + //@{ 要素 //@} 85 + const TCHAR operator[](int n) const; 86 + 87 + //@{ ワイド文字列に変換して返す //@} 88 + const wchar_t* ConvToWChar() const; 89 + 90 + //@{ ConvToWCharの返値バッファの解放 //@} 91 + void FreeWCMem( const wchar_t* wc ) const; 92 + 93 +public: 94 + 95 + //@{ 次の一文字 //@} 96 + static TCHAR* next( TCHAR* p ); 97 + static const TCHAR* next( const TCHAR* p ); 98 + 99 + //@{ 2バイト文字の先頭かどうか? //@} 100 + static bool isLB( TCHAR c ); 101 + 102 + //@{ 文字列からintへ変換 //@} 103 + static int GetInt( const TCHAR* p ); 104 + 105 +protected: 106 + 107 + // 書き込み可能なバッファを、終端含めて最低でもminimum文字分用意する 108 + TCHAR* AllocMem( ulong minimum ); 109 + TCHAR* ReallocMem( ulong minimum ); 110 + 111 + // 書き込み終了後、長さを再設定 112 + void UnlockMem( long siz=-1 ); 113 + 114 +private: 115 + 116 + struct StringData 117 + { 118 + long ref; // 参照カウンタ 119 + ulong len; // 終端'\0'を含める長さ 120 + ulong alen; // 割り当てられているメモリのサイズ 121 + TCHAR* buf() const // TCHAR buf[alen] 122 + { return reinterpret_cast<TCHAR*>( 123 + const_cast<StringData*>(this+1) 124 + ); } 125 + }; 126 + 127 +private: 128 + 129 + TCHAR* AllocMemHelper( ulong minimum, const TCHAR* str, ulong siz ); 130 + String& CatString( const TCHAR* str, ulong siz ); 131 + String& SetString( const TCHAR* str, ulong siz ); 132 + void SetData( StringData* d ); 133 + void ReleaseData(); 134 + static StringData* null(); 135 + StringData* data() const; 136 + 137 +private: 138 + 139 + StringData* data_; 140 + static StringData* nullData_; 141 + static char lb_[256]; 142 + 143 +private: 144 + 145 + static void LibInit(); 146 + friend void APIENTRY Startup(); 147 +}; 148 + 149 + 150 + 151 +//------------------------------------------------------------------------- 152 +#ifndef __ccdoc__ 153 + 154 +// 初期化 155 +inline String::String() 156 + { SetData( null() ); } 157 +// 初期化 158 +inline String::String( UINT rsrcID ) 159 + { SetData( null() ), Load( rsrcID ); } 160 +// 初期化 161 +inline String::String( const String& obj ) 162 + { SetData( obj.data() ); } 163 + 164 +// ポインタ計算サポート 165 +#if !defined(_UNICODE) && defined(_MBCS) 166 + inline TCHAR* String::next( TCHAR* p ) 167 + { return p + lb_[*(uchar*)p]; } 168 + inline const TCHAR* String::next( const TCHAR* p ) 169 + { return p + lb_[*(const uchar*)p]; } 170 + inline bool String::isLB( TCHAR c ) 171 + { return lb_[(uchar)c]==2; } 172 +#else // _UNICODE or _SBCS 173 + inline TCHAR* String::next( TCHAR* p ) 174 + { return p + 1; } 175 + inline const TCHAR* String::next( const TCHAR* p ) 176 + { return p + 1; } 177 + inline bool String::isLB( TCHAR c ) 178 + { return false; } 179 +#endif 180 + 181 +// 内部メモリ確保 182 +inline TCHAR* String::AllocMem( ulong minimum ) 183 + { return AllocMemHelper( minimum, TEXT(""), 1 ); } 184 +// 内部メモリ固定 185 +inline void String::UnlockMem( long siz ) 186 + { data_->len = 1 + (siz==-1 ? ::lstrlen(c_str()) : siz); } 187 + 188 +// 0文字データ 189 +inline String::StringData* String::null() 190 + { return nullData_; } 191 +// 内部データ構造 192 +inline String::StringData* String::data() const 193 + { return data_; } 194 +// 初期化 195 +inline void String::SetData( String::StringData* d ) 196 + { data_=d, data_->ref++; } 197 + 198 +// 属性 199 +inline const TCHAR* String::c_str() const 200 + { return data_->buf(); } 201 +// 属性 202 +inline ulong String::len() const 203 + { return data_->len-1; } 204 +// 要素 205 +inline const TCHAR String::operator[](int n) const 206 + { return data_->buf()[n]; } 207 + 208 +// 比較 209 +inline bool String::operator==( LPCTSTR s ) const 210 + { return 0==::lstrcmp( c_str(), s ); } 211 +// 比較 212 +inline bool String::operator==( const String& obj ) const 213 + { return (data_==obj.data_ ? true : operator==( obj.c_str() )); } 214 +// 比較 215 +inline bool String::isSame( LPCTSTR s ) const 216 + { return 0==::lstrcmpi( c_str(), s ); } 217 +// 比較 218 +inline bool String::isSame( const String& obj ) const 219 + { return (data_==obj.data_ ? true : operator==( obj.c_str() )); } 220 + 221 +// 要コピー代入 222 +inline String& String::operator = ( const TCHAR* s ) 223 + { return SetString( s, ::lstrlen(s) ); } 224 +// 合成 225 +inline String& String::operator += ( const String& obj ) 226 + { return CatString( obj.c_str(), obj.len() ); } 227 +// 合成 228 +inline String& String::operator += ( const TCHAR* s ) 229 + { return CatString( s, ::lstrlen(s) ); } 230 +// 合成 231 +inline String& String::operator += ( TCHAR c ) 232 + { return CatString( &c, 1 ); } 233 + 234 +// 変換 235 +inline int String::GetInt() 236 + { return GetInt( data_->buf() ); } 237 + 238 +//@{ String + String //@} 239 +inline const String operator+( const String& a, const String& b ) 240 + { return String(a) += b; } 241 +//@{ String + TCHAR* //@} 242 +inline const String operator+( const String& a, const TCHAR* b ) 243 + { return String(a) += b; } 244 +//@{ TCHAR* + String //@} 245 +inline const String operator+( const TCHAR* a, const String& b ) 246 + { return String(a) += b; } 247 + 248 +// ConvToWCharの返値バッファの解放 249 +inline void String::FreeWCMem( const wchar_t* wc ) const 250 +#ifdef _UNICODE 251 + {} 252 +#else // _MBCS or _SBCS 253 + { delete [] const_cast<wchar_t*>(wc); } 254 +#endif 255 + 256 + 257 + 258 +#endif // __ccdoc__ 259 +#undef XTCHAR 260 +//========================================================================= 261 +//@{ 262 +// 文字列処理+α 263 +// 264 +// Stringクラス内のバッファ確保関数を呼べるようにした版Stringです。 265 +//@} 266 +//========================================================================= 267 + 268 +struct RawString : public String 269 +{ 270 + TCHAR* AllocMem( ulong m ) { return String::AllocMem(m); } 271 + void UnlockMem() { String::UnlockMem(); } 272 +}; 273 + 274 +} // namespace ki 275 + 276 + 277 +//========================================================================= 278 +//@{ 279 +// 文字列処理+α2 280 +// 281 +// Wide文字版関数を自前で 282 +//@} 283 +//========================================================================= 284 + 285 +#ifdef _UNICODE 286 + #define my_lstrlenW ::lstrlenW 287 + #define my_lstrcpyW ::lstrcpyW 288 +#else 289 + inline static 290 + unicode* my_lstrcpyW( unicode* const d, const unicode* s ) 291 + { 292 + for(unicode* n=d; *n++=*s++;); 293 + return d; 294 + } 295 + 296 + inline static 297 + int my_lstrlenW( const unicode* const d ) 298 + { 299 + const unicode* n; 300 + for(n=d; *n; ++n); 301 + return static_cast<int>(n-d); 302 + } 303 +#endif 304 + 305 + 306 + 307 +//========================================================================= 308 + 309 +#endif // _KILIB_STRING_H_
Added kilib/textfile.cpp version [9c2e5d73acf07249]
1 +#include "stdafx.h" 2 +#include "app.h" 3 +#include "textfile.h" 4 +#include "ktlarray.h" 5 +using namespace ki; 6 + 7 + 8 + 9 +//========================================================================= 10 +// テキストファイル読み出し共通インターフェイス 11 +//========================================================================= 12 + 13 +struct ki::TextFileRPimpl : public Object 14 +{ 15 + inline TextFileRPimpl() 16 + : state(EOL) {} 17 + 18 + virtual size_t ReadLine( unicode* buf, ulong siz ) 19 + = 0; 20 + 21 + enum { EOF=0, EOL=1, EOB=2 } state; 22 +}; 23 + 24 + 25 + 26 +//------------------------------------------------------------------------- 27 +// Unicode系用のベースクラス 28 +// UTF-8以外はそんなに出会わないだろうから遅くてもよしとする。 29 +//------------------------------------------------------------------------- 30 + 31 +struct rBasicUTF : public ki::TextFileRPimpl 32 +{ 33 + virtual unicode PeekC() = 0; 34 + virtual unicode GetC() {unicode ch=PeekC(); Skip(); return ch;} 35 + virtual void Skip() = 0; 36 + virtual bool Eof() = 0; 37 + 38 + size_t ReadLine( unicode* buf, ulong siz ) 39 + { 40 + state = EOF; 41 + 42 + // 改行が出るまで読む 43 + unicode *w=buf, *e=buf+siz; 44 + while( !Eof() ) 45 + { 46 + *w = GetC(); 47 + if( *w==L'\r' || *w==L'\n' ) 48 + { 49 + state = EOL; 50 + break; 51 + } 52 + else if( *w!=0xfeff && ++w==e ) 53 + { 54 + state = EOB; 55 + break; 56 + } 57 + } 58 + 59 + // 改行コードスキップ処理 60 + if( state == EOL ) 61 + if( *w==L'\r' && !Eof() && PeekC()==L'\n' ) 62 + Skip(); 63 + 64 + // 読んだ文字数 65 + return w-buf; 66 + } 67 +}; 68 + 69 + 70 + 71 +//------------------------------------------------------------------------- 72 +// UCS2ベタ/UCS4ベタ。それぞれUTF16, UTF32の代わりとして使う。 73 +// ついでに同じtemplateで、ISO-8859-1も処理してしまう。^^; 74 +//------------------------------------------------------------------------- 75 + 76 +template<typename T> 77 +struct rUCS : public rBasicUTF 78 +{ 79 + rUCS( const uchar* b, ulong s, bool bigendian ) 80 + : fb( reinterpret_cast<const T*>(b) ) 81 + , fe( reinterpret_cast<const T*>(b+(s/sizeof(T))*sizeof(T)) ) 82 + , be( bigendian ) {} 83 + 84 + const T *fb, *fe; 85 + const bool be; 86 + 87 + // エンディアン変換 88 + inline byte swap( byte val ) { return val; } 89 + inline dbyte swap( dbyte val ) { return (val<<8) |(val>>8); } 90 + inline qbyte swap( qbyte val ) { return ((val>>24)&0xff | 91 + (val>>8)&0xff00 | 92 + (val<<8)&0xff0000| 93 + (val<<24)); } 94 + 95 + virtual void Skip() { ++fb; } 96 + virtual bool Eof() { return fb==fe; } 97 + virtual unicode PeekC() { return (unicode)(be ? swap(*fb) : *fb); } 98 +}; 99 + 100 +typedef rUCS< byte> rWest; 101 +typedef rUCS<dbyte> rUtf16; 102 + 103 +// UTF-32読み込み 104 +struct rUtf32 : public rUCS<qbyte> 105 +{ 106 + rUtf32( const uchar* b, ulong s, bool bigendian ) 107 + : rUCS<qbyte>(b,s,bigendian) 108 + , state(0) {} 109 + 110 + int state; 111 + qbyte curChar() { return be ? swap(*fb) : *fb; } 112 + bool inBMP(qbyte c) { return c<0x10000; } 113 + 114 + virtual unicode PeekC() 115 + { 116 + qbyte c = curChar(); 117 + if( inBMP(c) ) 118 + return (unicode)c; 119 + return (unicode)(state==0 ? 0xD800 + (((c-0x10000) >> 10)&0x3ff) 120 + : 0xDC00 + ( (c-0x10000) &0x3ff)); 121 + } 122 + 123 + virtual void Skip() 124 + { 125 + if( inBMP(curChar()) ) 126 + ++fb; 127 + else if( state==0 ) 128 + state=1; 129 + else 130 + ++fb, state=0; 131 + } 132 +}; 133 + 134 + 135 + 136 +//------------------------------------------------------------------------- 137 +// UTF-5 138 +// 0- F : 1bbbb 139 +// 10- FF : 1bbbb 0bbbb 140 +// 100-FFF : 1bbbb 0bbbb 0bbbb 141 +// というように、16進での一桁を一文字で表していくフォーマット。 142 +// 各 0bbbb は '0', '1', ... '9', 'A', ... 'F' 143 +// 各 1bbbb は 'G', 'H', ... 'P', 'Q', ... 'V' の字で表現。 144 +//------------------------------------------------------------------------- 145 + 146 +struct rUtf5 : public rBasicUTF 147 +{ 148 + rUtf5( const uchar* b, ulong s ) 149 + : fb( b ) 150 + , fe( b+s ) {} 151 + 152 + const uchar *fb, *fe; 153 + 154 + // 16進文字から整数値へ変換 155 + inline byte conv( uchar x ) 156 + { 157 + if( '0'<=x && x<='9' ) return x-'0'; 158 + else return x-'A'+0x0A; 159 + } 160 + 161 + void Skip() { do ++fb; while( fb<fe && *fb<'G' ); } 162 + bool Eof() { return fb==fe; } 163 + unicode PeekC() 164 + { 165 + unicode ch = (*fb-'G'); 166 + for( const uchar* p=fb+1; p<fe && *p<'G'; ++p ) 167 + ch = (ch<<4)|conv(*p); 168 + return ch; 169 + } 170 +}; 171 + 172 + 173 + 174 +//------------------------------------------------------------------------- 175 +// UTF-7 176 +// ASCII範囲の字はそのまま。それ以外はUTF-16の値をbase64エンコード 177 +// して出力。エンコードされた部分は + と - で挟まれる。また '+' と 178 +// いう字自体を表現するために "+-" という形式を用いる。 179 +//------------------------------------------------------------------------- 180 + 181 +namespace 182 +{ 183 + static const uchar u7c[128]={ 184 + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 185 + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 186 + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3e,0xff,0xff,0xff,0x3f, 187 + 0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0xff,0xff,0xff,0xff,0xff,0xff, 188 + 0xff,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e, 189 + 0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0xff,0xff,0xff,0xff,0xff, 190 + 0xff,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28, 191 + 0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0xff,0xff,0xff,0xff,0xff }; 192 +} 193 + 194 +struct rUtf7 : public rBasicUTF 195 +{ 196 + rUtf7( const uchar* b, ulong s ) 197 + : fb( b ) 198 + , fe( b+s ) 199 + , rest( -1 ) { fillbuf(); } 200 + 201 + const uchar *fb, *fe; 202 + unicode buf[3]; // b64を8文字毎に読んでバッファに溜めておく 203 + int rest; // バッファの空き 204 + bool inB64; // base64エリア内ならtrue 205 + 206 + void Skip() { if(--rest==0) fillbuf(); } 207 + bool Eof() { return fb==fe && rest==0; } 208 + unicode PeekC() { return buf[rest-1]; } 209 + 210 + void fillbuf() 211 + { 212 + if( fb<fe ) 213 + if( !inB64 ) 214 + if( *fb=='+' ) 215 + if( fb+1<fe && fb[1]=='-' ) 216 + rest=1, buf[0]=L'+', fb+=2; // +- 217 + else 218 + ++fb, inB64=true, fillbuf(); // 単独 + 219 + else 220 + rest=1, buf[0]=*fb++; // 普通の字 221 + else 222 + { 223 + // 何文字デコードできるか数える 224 + int N=0, E=Max(int(fb-fe),8); 225 + while( N<E && fb[N]<0x80 && u7c[fb[N]]!=0xff ) 226 + ++N; 227 + 228 + // デコード 229 + buf[0]=buf[1]=buf[2]=0; 230 + switch( N ) 231 + { 232 + case 8: buf[2]|= u7c[fb[7]]; 233 + case 7: buf[2]|=(u7c[fb[6]]<< 6); 234 + case 6: buf[2]|=(u7c[fb[5]]<<12), buf[1]|=(u7c[fb[5]]>>4); 235 + case 5: buf[1]|=(u7c[fb[4]]<< 2); 236 + case 4: buf[1]|=(u7c[fb[3]]<< 8); 237 + case 3: buf[1]|=(u7c[fb[2]]<<14), buf[0]|=(u7c[fb[2]]>>2); 238 + case 2: buf[0]|=(u7c[fb[1]]<< 4); 239 + case 1: buf[0]|=(u7c[fb[0]]<<10); 240 + unicode t; 241 + rest = 1; 242 + if( N==8 ) 243 + rest=3, t=buf[0], buf[0]=buf[2], buf[2]=t; 244 + else if( N>=6 ) 245 + rest=2, t=buf[0], buf[0]=buf[1], buf[1]=t; 246 + } 247 + 248 + // 使った分進む 249 + if( N<E ) 250 + { 251 + inB64=false; 252 + if( fb[N]=='-' ) 253 + ++fb; 254 + } 255 + fb += N; 256 + if( N==0 ) 257 + fillbuf(); 258 + } 259 + } 260 +}; 261 + 262 + 263 + 264 +//------------------------------------------------------------------------- 265 +// UTF8/MBCS 266 +// CR,LFが1バイト文字としてきちんと出てくるので、 267 +// 切り分けが簡単な形式をここでまとめて扱う。UTF8以外の変換は 268 +// Windowsに全て任せている。 269 +//------------------------------------------------------------------------- 270 + 271 +namespace 272 +{ 273 + typedef char* (WINAPI * uNextFunc)(WORD,const char*,DWORD); 274 + 275 + static const byte mask[] = { 0, 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01 }; 276 + static inline int GetMaskIndex(uchar n) 277 + { 278 + if( uchar(n+2) < 0xc2 ) return 1; // 00〜10111111, fe, ff 279 + if( n < 0xe0 ) return 2; // 110xxxxx 280 + if( n < 0xf0 ) return 3; // 1110xxxx 281 + if( n < 0xf8 ) return 4; // 11110xxx 282 + if( n < 0xfc ) return 5; // 111110xx 283 + return 6; // 1111110x 284 + } 285 + 286 + static char* WINAPI CharNextUtf8( WORD, const char* p, DWORD ) 287 + { 288 + return const_cast<char*>( p+GetMaskIndex(uchar(*p)) ); 289 + } 290 + 291 + // Win95対策。 292 + // http://support.microsoft.com/default.aspx?scid=%2Fisapi%2Fgomscom%2Easp%3Ftarget%3D%2Fjapan%2Fsupport%2Fkb%2Farticles%2Fjp175%2F3%2F92%2Easp&LN=JA 293 + // MSDNにはWin95以降でサポートと書いてあるのにCP_UTF8は 294 + // 使えないらしいので、自前の変換関数で。 295 + typedef int (WINAPI * uConvFunc)(UINT,DWORD,const char*,int,wchar_t*,int); 296 + static int WINAPI Utf8ToWideChar( UINT, DWORD, const char* sb, int ss, wchar_t* wb, int ws ) 297 + { 298 + const uchar *p = reinterpret_cast<const uchar*>(sb); 299 + const uchar *e = reinterpret_cast<const uchar*>(sb+ss); 300 + wchar_t *w = wb; // バッファサイズチェック無し(仕様) 301 + 302 + for( int t; p<e; ++w ) 303 + { 304 + t = GetMaskIndex(*p); 305 + qbyte qch = (*p++ & mask[t]); 306 + while( p<e && --t ) 307 + qch<<=6, qch|=(*p++)&0x3f; 308 + if(qch<0x10000) 309 + *w = (wchar_t)qch; 310 + else 311 + *w++ = (wchar_t)(0xD800 + (((qch-0x10000)>>10)&0x3ff)), 312 + *w = (wchar_t)(0xDC00 + (((qch-0x10000) )&0x3ff)); 313 + } 314 + return int(w-wb); 315 + } 316 +} 317 + 318 +struct rMBCS : public TextFileRPimpl 319 +{ 320 + // ファイルポインタ&コードページ 321 + const char* fb; 322 + const char* fe; 323 + const int cp; 324 + uNextFunc next; 325 + uConvFunc conv; 326 + 327 + // 初期設定 328 + rMBCS( const uchar* b, ulong s, int c ) 329 + : fb( reinterpret_cast<const char*>(b) ) 330 + , fe( reinterpret_cast<const char*>(b+s) ) 331 + , cp( c==UTF8 ? UTF8N : c ) 332 + , next( cp==UTF8N ? CharNextUtf8 : CharNextExA ) 333 + , conv( cp==UTF8N && app().isWin95() 334 + ? Utf8ToWideChar : MultiByteToWideChar ) 335 + { 336 + if( cp==UTF8N && fe-fb>=3 337 + && b[0]==0xef && b[1]==0xbb && b[2]==0xbf ) 338 + fb += 3; // BOMスキップ 339 + } 340 + 341 + size_t ReadLine( unicode* buf, ulong siz ) 342 + { 343 + // バッファの終端か、ファイルの終端の近い方まで読み込む 344 + const char *p, *end = Min( fb+siz/2, fe ); 345 + state = (end==fe ? EOF : EOB); 346 + 347 + // 改行が出るまで進む 348 + for( p=fb; p<end; ) 349 + if( *p=='\r' || *p=='\n' ) 350 + { 351 + state = EOL; 352 + break; 353 + } 354 + else if( (*p) & 0x80 ) 355 + { 356 + p = next(cp,p,0); 357 + } 358 + else 359 + { 360 + ++p; 361 + } 362 + 363 + // Unicodeへ変換 364 +#ifndef _UNICODE 365 + ulong len = conv( cp, 0, fb, p-fb, buf, siz ); 366 +#else 367 + ulong len = ::MultiByteToWideChar( cp, 0, fb, int(p-fb), buf, siz ); 368 +#endif 369 + // 改行コードスキップ処理 370 + if( state == EOL ) 371 + if( *(p++)=='\r' && p<fe && *p=='\n' ) 372 + ++p; 373 + fb = p; 374 + 375 + // 終了 376 + return len; 377 + } 378 +}; 379 + 380 + 381 + 382 +//------------------------------------------------------------------------- 383 +// ISO-2022 の適当な実装 384 +// 385 +// コードページとして、G0, G1, G2, G3 の四面を持つ。 386 +// それぞれ決まったエスケープシーケンスによって、 387 +// さまざまな文字集合を各面に呼び出すことが出来る。 388 +// とりあえず現在のバージョンで対応しているふりなのは 389 +// 次の通り。()内に、そのいい加減っぷりを示す。 390 +// 391 +// <<いつでも>> 392 +// 1B 28 42 : G0へ ASCII 393 +// 1B 28 4A : G0へ JIS X 0201 ローマ字 (のかわりにASCII) 394 +// 1B 29 4A : G1へ JIS X 0201 ローマ字 (のかわりにASCII) 395 +// 1B 2A 4A : G2へ JIS X 0201 ローマ字 (のかわりにASCII) 396 +// 1B 3B 4A : G3へ JIS X 0201 ローマ字 (のかわりにASCII) 397 +// 1B 2E 41 : G2へ ISO-8859-1 398 +// <<CP932が有効な場合>> 399 +// 1B 28 49 : G0へ JIS X 0201 カナ 400 +// 1B 29 49 : G1へ JIS X 0201 カナ 401 +// 1B 2A 49 : G2へ JIS X 0201 カナ 402 +// 1B 2B 49 : G3へ JIS X 0201 カナ 403 +// 1B 24 40 : G0へ JIS X 0208(1978) 404 +// 1B 24 42 : G0へ JIS X 0208(1983) (年度は区別しない) 405 +// <<CP936が有効な場合>> 406 +// 1B 24 41 : G0へ GB 2312 407 +// 1B 24 29 41 : G1へ GB 2312 408 +// 1B 24 2A 41 : G2へ GB 2312 409 +// 1B 24 2B 41 : G3へ GB 2312 410 +// <<CP949が有効な場合>> 411 +// 1B 24 28 43 : G0へ KS X 1001 412 +// 1B 24 29 43 : G1へ KS X 1001 413 +// 1B 24 2A 43 : G2へ KS X 1001 414 +// 1B 24 2B 43 : G3へ KS X 1001 415 +// 416 +// 各面に呼び出した文字集合は、 417 +// GL (0x21〜0xfe) GR (0xa0〜0xff) 418 +// のどちらかへマップすることで、実際のバイト値となる。 419 +// マップ命令となるバイト列は、次の通り 420 +// 421 +// 0F : GL へG0を呼び出し 422 +// 0E : GL へG1を呼び出し 423 +// 1B 7E : GR へG1を呼び出し 424 +// 8E : GL/GR両方 へG2を一瞬だけ呼び出し。1B 4E も同義 425 +// 8F : GL/GR両方 へG3を一瞬だけ呼び出し。1B 4F も同義 426 +// 427 +//------------------------------------------------------------------------- 428 + 429 +enum CodeSet { ASCII, LATIN, KANA, JIS, KSX, GB }; 430 + 431 +struct rIso2022 : public TextFileRPimpl 432 +{ 433 + // Helper: JIS X 0208 => SJIS 434 + void jis2sjis( uchar k, uchar t, char* s ) 435 + { 436 + if(k>=0x3f) s[0] = (char)(((k+1)>>1)+0xc0); 437 + else s[0] = (char)(((k+1)>>1)+0x80); 438 + if( k&1 ) s[1] = (char)((t>>6) ? t+0x40 : t+0x3f); 439 + else s[1] = (char)(t+0x9e); 440 + } 441 + 442 + // ファイルポインタ 443 + const uchar* fb; 444 + const uchar* fe; 445 + bool fixed; // ESCによる切り替えを行わないならtrue 446 + bool mode_hz; // HZの場合。 447 + 448 + // 作業変数 449 + CodeSet *GL, *GR, G[4]; 450 + int gWhat; // 次の字は 1:GL/GR 2:G2 3:G3 で出力 451 + ulong len; 452 + 453 + // 初期化 454 + rIso2022( const uchar* b, ulong s, bool f, bool hz, 455 + CodeSet g0, CodeSet g1, CodeSet g2=ASCII, CodeSet g3=ASCII ) 456 + : fb( b ) 457 + , fe( b+s ) 458 + , fixed( f ) 459 + , mode_hz( hz ) 460 + , GL( &G[0] ) 461 + , GR( &G[1] ) 462 + , gWhat( 1 ) 463 + { 464 + G[0]=g0, G[1]=g1, G[2]=g2, G[3]=g3; 465 + } 466 + 467 + void DoSwitching( const uchar*& p ) 468 + { 469 + if( fixed ) 470 + { 471 + if( p[0]==0x24 && p[1]!=0x40 && p[1]!=0x41 && p[1]!=0x42 472 + && p+2 < fe && (p[2]==0x41 || p[2]==0x43) ) 473 + ++p; 474 + } 475 + else 476 + { 477 + if( p[1]==0x4A ) 478 + G[ (p[0]-0x28)%4 ] = ASCII; // 1B [28-2B] 4A 479 + else if( p[1]==0x49 ) 480 + G[ (p[0]-0x28)%4 ] = KANA; // 1B [28-2B] 49 481 + else if( *reinterpret_cast<const dbyte*>(p)==0x4228 ) 482 + G[ 0 ] = ASCII; // 1B 28 42 483 + else if( *reinterpret_cast<const dbyte*>(p)==0x412E ) 484 + G[ 2 ] = LATIN; // 1B 2E 41 485 + else if( p[0]==0x24 ) 486 + if( p[1]==0x40 || p[1]==0x42 ) 487 + G[ 0 ] = JIS; // 1B 24 [40|42] 488 + else if( p[1]==0x41 ) 489 + G[ 0 ] = GB; // 1B 24 41 490 + else if( p+2 < fe ) 491 + if( p[2]==0x41 ) 492 + G[ ((*++p)-0x28)%4 ] = GB; // 1B 24 [28-2B] 41 493 + else if( p[2]==0x43 ) 494 + G[ ((*++p)-0x28)%4 ] = KSX; // 1B 24 [28-2B] 43 495 + } 496 + ++p; 497 + } 498 + 499 + void DoOutput( unicode*& buf, const uchar*& p ) 500 + { 501 + // 文字集合取り出し 502 + CodeSet cs = 503 + (gWhat==2 ? G[2] : 504 + (gWhat==3 ? G[3] : 505 + (*p&0x80 ? *GR : *GL))); 506 + 507 + char c[2]; 508 + ulong wt=1; 509 + switch( cs ) 510 + { 511 + case ASCII: 512 + *buf = (*p)&0x7f; 513 + break; 514 + case LATIN: 515 + *buf = (*p)|0x80; 516 + break; 517 + case KANA: 518 + c[0] = (*p)|0x80; 519 + wt = ::MultiByteToWideChar( 520 + 932, MB_PRECOMPOSED, c, 1, buf, 2 ); 521 + break; 522 + case GB: 523 + case KSX: 524 + c[0] = (* p)|0x80; 525 + c[1] = (*++p)|0x80; 526 + wt = ::MultiByteToWideChar( 527 + (cs==GB?936:949), MB_PRECOMPOSED, c, 2, buf, 2 ); 528 + break; 529 + case JIS: 530 + jis2sjis( (p[0]&0x7f)-0x20, (p[1]&0x7f)-0x20, c ); 531 + ++p; 532 + wt = ::MultiByteToWideChar( 533 + 932, MB_PRECOMPOSED, c, 2, buf, 2 ); 534 + break; 535 + } 536 + buf+=wt; 537 + len+=wt; 538 + } 539 + 540 + size_t ReadLine( unicode* buf, ulong siz ) 541 + { 542 + len=0; 543 + 544 + // バッファの終端か、ファイルの終端の近い方まで読み込む 545 + const uchar *p, *end = Min( fb+siz/2, fe ); 546 + state = (end==fe ? EOF : EOB); 547 + 548 + // 改行が出るまで進む 549 + for( p=fb; p<end; ++p ) 550 + switch( *p ) 551 + { 552 + case '\r': 553 + case '\n': state = EOL; goto outofloop; 554 + case 0x0F: GL = &G[0]; break; 555 + case 0x0E: GL = &G[1]; break; 556 + case 0x8E: gWhat = 2; break; 557 + case 0x8F: gWhat = 3; break; 558 + case 0x1B: 559 + if( p+1<fe ) { 560 + ++p; if( *p==0x7E ) GR = &G[1]; 561 + else if( *p==0x4E ) gWhat = 2; 562 + else if( *p==0x4F ) gWhat = 3; 563 + else if( p+1<fe ) DoSwitching(p); 564 + }break; 565 + case 0x7E: if( mode_hz && p+1<fe ) { 566 + ++p; if( *p==0x7D ){ GL = &G[0]; break; } 567 + else if( *p==0x7B ){ GL = &G[1]; break; } 568 + } // fall through... 569 + default: DoOutput( buf, p ); gWhat=1; break; 570 + } 571 + outofloop: 572 + 573 + // 改行コードスキップ処理 574 + if( state == EOL ) 575 + if( *(p++)=='\r' && p<fe && *p=='\n' ) 576 + ++p; 577 + fb = p; 578 + 579 + // 終了 580 + return len; 581 + } 582 +}; 583 + 584 + 585 + 586 +//------------------------------------------------------------------------- 587 +// 自動判定などなど 588 +//------------------------------------------------------------------------- 589 + 590 +TextFileR::TextFileR( int charset ) 591 + : cs_( charset ) 592 + , nolbFound_(true) 593 +{ 594 +} 595 + 596 +TextFileR::~TextFileR() 597 +{ 598 + Close(); 599 +} 600 + 601 +size_t TextFileR::ReadLine( unicode* buf, ulong siz ) 602 +{ 603 + return impl_->ReadLine( buf, siz ); 604 +} 605 + 606 +int TextFileR::state() const 607 +{ 608 + return impl_->state; 609 +} 610 + 611 +void TextFileR::Close() 612 +{ 613 + fp_.Close(); 614 +} 615 + 616 +bool TextFileR::Open( const TCHAR* fname ) 617 +{ 618 + // ファイルを開く 619 + if( !fp_.Open(fname) ) 620 + return false; 621 + const uchar* buf = fp_.base(); 622 + const ulong siz = fp_.size(); 623 + 624 + // 必要なら自動判定 625 + cs_ = AutoDetection( cs_, buf, Min<ulong>(siz,16<<10) ); // 先頭16KB 626 + 627 + // 対応するデコーダを作成 628 + switch( cs_ ) 629 + { 630 + case Western: impl_ = new rWest(buf,siz,true); break; 631 + case UTF16b: 632 + case UTF16BE: impl_ = new rUtf16(buf,siz,true); break; 633 + case UTF16l: 634 + case UTF16LE: impl_ = new rUtf16(buf,siz,false); break; 635 + case UTF32b: 636 + case UTF32BE: impl_ = new rUtf32(buf,siz,true); break; 637 + case UTF32l: 638 + case UTF32LE: impl_ = new rUtf32(buf,siz,false); break; 639 + case UTF5: impl_ = new rUtf5(buf,siz); break; 640 + case UTF7: impl_ = new rUtf7(buf,siz); break; 641 + case EucJP: impl_ = new rIso2022(buf,siz,true,false,ASCII,JIS,KANA); break; 642 + case IsoJP: impl_ = new rIso2022(buf,siz,false,false,ASCII,KANA); break; 643 + case IsoKR: impl_ = new rIso2022(buf,siz,true,false,ASCII,KSX); break; 644 + case IsoCN: impl_ = new rIso2022(buf,siz,true,false,ASCII,GB); break; 645 + case HZ: impl_ = new rIso2022(buf,siz,true,true, ASCII,GB); break; 646 + default: impl_ = new rMBCS(buf,siz,cs_); break; 647 + } 648 + 649 + return true; 650 +} 651 + 652 +int TextFileR::AutoDetection( int cs, const uchar* ptr, ulong siz ) 653 +{ 654 +//-- まず、文字の出現回数の統計を取る 655 + 656 + int freq[256]; 657 + bool bit8 = false; 658 + mem00( freq, sizeof(freq) ); 659 + for( ulong i=0; i<siz; ++i ) 660 + { 661 + if( ptr[i] >= 0x80 ) 662 + bit8 = true; 663 + ++freq[ ptr[i] ]; 664 + } 665 + 666 +//-- 改行コード決定 (UTF16/32/7のとき問題あり。UTF5に至っては判定不可…) 667 + 668 + if( freq['\r'] > freq['\n']*2 ) lb_ = CR; 669 + else if( freq['\n'] > freq['\r']*2 ) lb_ = LF; 670 + else lb_ = CRLF; 671 + nolbFound_ = freq['\r']==0 && freq['\n']==0; 672 + 673 +//-- デフォルトコード 674 + 675 + int defCs = ::GetACP(); 676 + 677 +//-- 小さすぎる場合はここで終了 678 + 679 + if( siz <= 4 ) 680 + return cs==AutoDetect ? defCs : cs; 681 + 682 +//-- 明示指定がある場合はここで終了 683 + 684 + ulong bom4 = (ptr[0]<<24) + (ptr[1]<<16) + (ptr[2]<<8) + (ptr[3]); 685 + ulong bom2 = (ptr[0]<<8) + (ptr[1]); 686 + 687 + if( cs==UTF8 || cs==UTF8N ) 688 + cs = (bom4>>8==0xefbbbf ? UTF8 : UTF8N); 689 + else if( cs==UTF32b || cs==UTF32BE ) 690 + cs = (bom4==0x0000feff ? UTF32b : UTF32BE); 691 + else if( cs==UTF32l || cs==UTF32LE ) 692 + cs = (bom4==0xfffe0000 ? UTF32l : UTF32LE); 693 + else if( cs==UTF16b || cs==UTF16BE ) 694 + cs = (bom2==0xfeff ? UTF16b : UTF16BE); 695 + else if( cs==UTF16l || cs==UTF16LE ) 696 + cs = (bom2==0xfffe ? UTF16l : UTF16LE); 697 + 698 + if( cs != AutoDetect ) 699 + return cs; 700 + 701 +//-- BOMチェック・7bitチェック 702 + 703 + bool Jp = ::IsValidCodePage(932)!=FALSE; 704 + 705 + if( (bom4>>8) == 0xefbbbf ) cs = UTF8; 706 + else if( bom4 == 0x0000feff ) cs = UTF32b; 707 + else if( bom4 == 0xfffe0000 ) cs = UTF32l; 708 + else if( bom2 == 0xfeff ) cs = UTF16b; 709 + else if( bom2 == 0xfffe ) cs = UTF16l; 710 + else if( bom4 == 0x1b242943 && ::IsValidCodePage(949) ) cs = IsoKR; 711 + else if( bom4 == 0x1b242941 && ::IsValidCodePage(936) ) cs = IsoCN; 712 + else if( Jp && !bit8 && freq[0x1b]>0 ) cs = IsoJP; 713 + 714 + if( cs != AutoDetect ) 715 + return cs; 716 + 717 +//-- UTF-5 チェック 718 + 719 + ulong u5sum = 0; 720 + for( uchar c='0'; c<='9'; ++c ) u5sum += freq[c]; 721 + for( uchar c='A'; c<='V'; ++c ) u5sum += freq[c]; 722 + if( siz == u5sum ) 723 + return UTF5; 724 + 725 +//-- 暫定版 UTF-8 / 日本語EUC チェック 726 + 727 + cs = defCs; 728 + 729 + // 改行コードがLFか、ある程度の大きさか、でないと 730 + // 無条件で ANSI-CP と見なしてしまう。 731 + if( bit8 && (siz>4096 || lb_==1 732 + || freq[0xfd]>0 || freq[0xfe]>0 || freq[0xff]>0 || freq[0x80]>0) ) 733 + { 734 + // UHCやGBKはEUC-JPと非常に混同しやすいので、そっちがデフォルトの場合は 735 + // EUC-JP自動判定を切る 736 + if( Jp && ::GetACP()!=UHC && ::GetACP()!=GBK && ::GetACP()!=Big5 ) 737 + { 738 + // EUCとしておかしい値が無いかチェック 739 + bool be=true; 740 + for( int k=0x90; k<=0xa0; ++k )if( freq[k]>0 ){be=false;break;} 741 + for( int k=0x7f; k<=0x8d; ++k )if( freq[k]>0 ){be=false;break;} 742 + if( be ) 743 + return EucJP; 744 + } 745 + { 746 + // UTF8として読めるかどうかチェック 747 + bool b8=true; 748 + int mi=1; 749 + for( ulong i=0; i<siz && b8; ++i ) 750 + if( --mi ) 751 + { 752 + if( ptr[i]<0x80 || ptr[i]>=0xc0 ) 753 + b8 = false; 754 + } 755 + else 756 + { 757 + mi = 1; 758 + if( ptr[i] > 0x7f ) 759 + { 760 + mi = GetMaskIndex( ptr[i] ); 761 + if( mi == 1 )//ptr[i] >= 0xfe ) 762 + b8 = false; 763 + } 764 + } 765 + if( b8 ) 766 + return UTF8N; 767 + } 768 + } 769 + 770 +//-- 判定結果 771 + 772 + return cs; 773 +} 774 + 775 + 776 + 777 +//========================================================================= 778 +// テキストファイル出力共通インターフェイス 779 +//========================================================================= 780 + 781 +struct ki::TextFileWPimpl : public Object 782 +{ 783 + virtual void WriteLine( const unicode* buf, ulong siz ) 784 + { while( siz-- ) WriteChar( *buf++ ); } 785 + 786 + virtual void WriteLB( const unicode* buf, ulong siz ) 787 + { WriteLine( buf, siz ); } 788 + 789 + virtual void WriteChar( unicode ch ) 790 + {} 791 + 792 + ~TextFileWPimpl() 793 + { delete [] buf_; } 794 + 795 +protected: 796 + 797 + TextFileWPimpl( FileW& w ) 798 + : fp_ (w) 799 + , bsiz_ (65536) 800 + , buf_ (new char[bsiz_]) {} 801 + 802 + void ReserveMoreBuffer() 803 + { 804 + char* nBuf = new char[bsiz_<<=1]; 805 + delete [] buf_; 806 + buf_ = nBuf; 807 + } 808 + 809 + FileW& fp_; 810 + ulong bsiz_; 811 + char* buf_; 812 +}; 813 + 814 + 815 + 816 +//------------------------------------------------------------------------- 817 +// Unicodeテキスト 818 +//------------------------------------------------------------------------- 819 + 820 +struct wUtf16LE : public TextFileWPimpl 821 +{ 822 + wUtf16LE( FileW& w, bool bom ) : TextFileWPimpl(w) 823 + { if(bom){ unicode ch=0xfeff; fp_.Write(&ch,2); } } 824 + void WriteLine( const unicode* buf, ulong siz ) {fp_.Write(buf,siz*2);} 825 +}; 826 + 827 +struct wUtf16BE : public TextFileWPimpl 828 +{ 829 + wUtf16BE( FileW& w, bool bom ) : TextFileWPimpl(w) 830 + { if(bom) WriteChar(0xfeff); } 831 + void WriteChar( unicode ch ) { fp_.WriteC(ch>>8), fp_.WriteC(ch&0xff); } 832 +}; 833 + 834 +struct wUtf32LE : public TextFileWPimpl 835 +{ 836 + wUtf32LE( FileW& w, bool bom ) : TextFileWPimpl(w) 837 + { if(bom) {unicode c=0xfeff; WriteLine(&c,1);} } 838 +// void WriteChar( unicode ch ) 839 +// { fp_.WriteC(ch&0xff), fp_.WriteC(ch>>8), fp_.WriteC(0), fp_.WriteC(0); } 840 + virtual void WriteLine( const unicode* buf, ulong siz ) 841 + { 842 + while( siz-- ) 843 + { 844 + unicode c = *buf++; 845 + qbyte cc = c; 846 + if( (0xD800<=c && c<=0xDBFF) && siz>0 ) // trail char が正しいかどうかはチェックする気がない 847 + { 848 + unicode c2 = *buf++; siz--; 849 + cc = 0x10000 + (((c-0xD800)&0x3ff)<<10) + ((c2-0xDC00)&0x3ff); 850 + } 851 + for(int i=0; i<=3; ++i) 852 + fp_.WriteC( (uchar)(cc>>(8*i)) ); 853 + } 854 + } 855 +}; 856 + 857 +struct wUtf32BE : public TextFileWPimpl 858 +{ 859 + wUtf32BE( FileW& w, bool bom ) : TextFileWPimpl(w) 860 + { if(bom) {unicode c=0xfeff; WriteLine(&c,1);} } 861 +// void WriteChar( unicode ch ) 862 +// { fp_.WriteC(0), fp_.WriteC(0), fp_.WriteC(ch>>8), fp_.WriteC(ch&0xff); } 863 + virtual void WriteLine( const unicode* buf, ulong siz ) 864 + { 865 + while( siz-- ) 866 + { 867 + unicode c = *buf++; 868 + qbyte cc = c; 869 + if( (0xD800<=c && c<=0xDBFF) && siz>0 ) // trail char が正しいかどうかはチェックする気がない 870 + { 871 + unicode c2 = *buf++; siz--; 872 + cc = 0x10000 + (((c-0xD800)&0x3ff)<<10) + ((c2-0xDC00)&0x3ff); 873 + } 874 + for(int i=3; i>=0; --i) 875 + fp_.WriteC( (uchar)(cc>>(8*i)) ); 876 + } 877 + } 878 +}; 879 + 880 +struct wWest : public TextFileWPimpl 881 +{ 882 + wWest( FileW& w ) : TextFileWPimpl(w) {} 883 + void WriteChar( unicode ch ) { fp_.WriteC(ch>0xff ? '?' : (uchar)ch); } 884 +}; 885 + 886 +struct wUtf5 : public TextFileWPimpl 887 +{ 888 + wUtf5( FileW& w ) : TextFileWPimpl(w) {} 889 + void WriteChar( unicode ch ) 890 + { 891 + static const char conv[] = { 892 + '0','1','2','3','4','5','6','7', 893 + '8','9','A','B','C','D','E','F' }; 894 + if(ch<0x10) 895 + { 896 + fp_.WriteC(ch+'G'); 897 + } 898 + else if(ch<0x100) 899 + { 900 + fp_.WriteC((ch>>4)+'G'); 901 + fp_.WriteC(conv[ch&0xf]); 902 + } 903 + else if(ch<0x1000) 904 + { 905 + fp_.WriteC((ch>>8)+'G'); 906 + fp_.WriteC(conv[(ch>>4)&0xf]); 907 + fp_.WriteC(conv[ch&0xf]); 908 + } 909 + else 910 + { 911 + fp_.WriteC((ch>>12)+'G'); 912 + fp_.WriteC(conv[(ch>>8)&0xf]); 913 + fp_.WriteC(conv[(ch>>4)&0xf]); 914 + fp_.WriteC(conv[ch&0xf]); 915 + } 916 + } 917 +}; 918 + 919 + 920 + 921 +//------------------------------------------------------------------------- 922 +// Win95対策の自前UTF8/UTF7処理 923 +//------------------------------------------------------------------------- 924 +#ifndef _UNICODE 925 + 926 +struct wUTF8 : public TextFileWPimpl 927 +{ 928 + wUTF8( FileW& w, int cp ) 929 + : TextFileWPimpl(w) 930 + { 931 + if( cp == UTF8 ) // BOM書き込み 932 + fp_.Write( "\xEF\xBB\xBF", 3 ); 933 + } 934 + 935 + void WriteLine( const unicode* str, ulong len ) 936 + { 937 + // 0000-0000-0xxx-xxxx | 0xxxxxxx 938 + // 0000-0xxx-xxyy-yyyy | 110xxxxx 10yyyyyy 939 + // xxxx-yyyy-yyzz-zzzz | 1110xxxx 10yyyyyy 10zzzzzz 940 + // x-xxyy-yyyy-zzzz-zzww-wwww | 11110xxx 10yyyyyy 10zzzzzz 10wwwwww 941 + // ... 942 + while( len-- ) 943 + { 944 + qbyte ch = *str; 945 + if( (0xD800<=ch&&ch<=0xDBFF) && len ) 946 + ch = 0x10000 + (((ch-0xD800)&0x3ff)<<10) + ((*++str-0xDC00)&0x3ff), len--; 947 + 948 + if( ch <= 0x7f ) 949 + fp_.WriteC( static_cast<uchar>(ch) ); 950 + else if( ch <= 0x7ff ) 951 + fp_.WriteC( 0xc0 | static_cast<uchar>(ch>>6) ), 952 + fp_.WriteC( 0x80 | static_cast<uchar>(ch&0x3f) ); 953 + else if( ch<= 0xffff ) 954 + fp_.WriteC( 0xe0 | static_cast<uchar>(ch>>12) ), 955 + fp_.WriteC( 0x80 | static_cast<uchar>((ch>>6)&0x3f) ), 956 + fp_.WriteC( 0x80 | static_cast<uchar>(ch&0x3f) ); 957 + else if( ch<= 0x1fffff ) 958 + fp_.WriteC( 0xf0 | static_cast<uchar>(ch>>18) ), 959 + fp_.WriteC( 0x80 | static_cast<uchar>((ch>>12)&0x3f) ), 960 + fp_.WriteC( 0x80 | static_cast<uchar>((ch>>6)&0x3f) ), 961 + fp_.WriteC( 0x80 | static_cast<uchar>(ch&0x3f) ); 962 + else if( ch<= 0x3ffffff ) 963 + fp_.WriteC( 0xf8 | static_cast<uchar>(ch>>24) ), 964 + fp_.WriteC( 0x80 | static_cast<uchar>((ch>>18)&0x3f) ), 965 + fp_.WriteC( 0x80 | static_cast<uchar>((ch>>12)&0x3f) ), 966 + fp_.WriteC( 0x80 | static_cast<uchar>((ch>>6)&0x3f) ), 967 + fp_.WriteC( 0x80 | static_cast<uchar>(ch&0x3f) ); 968 + else 969 + fp_.WriteC( 0xfc | static_cast<uchar>(ch>>30) ), 970 + fp_.WriteC( 0x80 | static_cast<uchar>((ch>>24)&0x3f) ), 971 + fp_.WriteC( 0x80 | static_cast<uchar>((ch>>18)&0x3f) ), 972 + fp_.WriteC( 0x80 | static_cast<uchar>((ch>>12)&0x3f) ), 973 + fp_.WriteC( 0x80 | static_cast<uchar>((ch>>6)&0x3f) ), 974 + fp_.WriteC( 0x80 | static_cast<uchar>(ch&0x3f) ); 975 + ++str; 976 + } 977 + } 978 +}; 979 + 980 + 981 + 982 +struct wUTF7 : public TextFileWPimpl 983 +{ 984 + wUTF7( FileW& w ) : TextFileWPimpl(w) {} 985 + 986 + void WriteLine( const unicode* str, ulong len ) 987 + { 988 + static const uchar mime[64] = { 989 + 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', 990 + 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', 991 + 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', 992 + 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'}; 993 + 994 + // XxxxxxYyyyyyZzzz | zzWwwwwwUuuuuuVv | vvvvTtttttSsssss 995 + bool mode_m = false; 996 + while( len ) 997 + { 998 + if( *str <= 0x7f ) 999 + { 1000 + fp_.WriteC( static_cast<uchar>(*str) ); 1001 + if( *str == L'+' ) 1002 + fp_.WriteC( '-' ); 1003 + ++str, --len; 1004 + } 1005 + else 1006 + { 1007 + if(!mode_m) fp_.WriteC( '+' ), mode_m=true; 1008 + unicode tx[3] = {0,0,0}; 1009 + int n=0; 1010 + tx[0] = *str, ++str, --len, ++n; 1011 + if( len && *str>0x7f ) 1012 + { 1013 + tx[1] = *str, ++str, --len, ++n; 1014 + if( len && *str>0x7f ) 1015 + tx[2] = *str, ++str, --len, ++n; 1016 + } 1017 + { 1018 + fp_.WriteC( mime[ tx[0]>>10 ] ); 1019 + fp_.WriteC( mime[ (tx[0]>>4)&0x3f ] ); 1020 + fp_.WriteC( mime[ (tx[0]<<2|tx[1]>>14)&0x3f ] ); 1021 + if( n>=2 ) 1022 + { 1023 + fp_.WriteC( mime[ (tx[1]>>8)&0x3f ] ); 1024 + fp_.WriteC( mime[ (tx[1]>>2)&0x3f ] ); 1025 + fp_.WriteC( mime[ (tx[1]<<4|tx[2]>>12)&0x3f ] ); 1026 + if( n>=3 ) 1027 + { 1028 + fp_.WriteC( mime[ (tx[2]>>6)&0x3f ] ); 1029 + fp_.WriteC( mime[ tx[2]&0x3f ] ); 1030 + } 1031 + } 1032 + } 1033 + if( len && *str<=0x7f ) 1034 + fp_.WriteC( '-' ), mode_m = false; 1035 + } 1036 + } 1037 + } 1038 +}; 1039 + 1040 + 1041 + 1042 +#endif 1043 +//------------------------------------------------------------------------- 1044 +// Windows頼りの変換 1045 +//------------------------------------------------------------------------- 1046 + 1047 +struct wMBCS : public TextFileWPimpl 1048 +{ 1049 + wMBCS( FileW& w, int cp ) 1050 + : TextFileWPimpl(w), cp_(cp) 1051 + { 1052 + if( cp == UTF8 ) 1053 + { 1054 + // BOM書き込み 1055 + cp_ = UTF8N; 1056 + fp_.Write( "\xEF\xBB\xBF", 3 ); 1057 + } 1058 + } 1059 + 1060 + void WriteLine( const unicode* str, ulong len ) 1061 + { 1062 + // WideCharToMultiByte API を利用した変換 1063 + int r; 1064 + while( 1065 + 0==(r=::WideCharToMultiByte(cp_,0,str,len,buf_,bsiz_,NULL,NULL)) 1066 + && ::GetLastError()==ERROR_INSUFFICIENT_BUFFER ) 1067 + ReserveMoreBuffer(); 1068 + 1069 + // ファイルへ書き込み 1070 + fp_.Write( buf_, r ); 1071 + } 1072 + 1073 + int cp_; 1074 +}; 1075 + 1076 + 1077 + 1078 +//------------------------------------------------------------------------- 1079 +// ISO-2022 サブセットその1。 1080 +// ASCIIともう一つしか文字集合を使わないもの 1081 +//------------------------------------------------------------------------- 1082 + 1083 +struct wIso2022 : public TextFileWPimpl 1084 +{ 1085 + wIso2022( FileW& w, int cp ) 1086 + : TextFileWPimpl(w), hz_(cp==HZ) 1087 + { 1088 + switch( cp ) 1089 + { 1090 + case IsoKR: 1091 + fp_.Write( "\x1B\x24\x29\x43", 4 ); 1092 + cp_ = UHC; 1093 + break; 1094 + 1095 + case IsoCN: 1096 + fp_.Write( "\x1B\x24\x29\x41", 4 ); 1097 + // fall through... 1098 + default: 1099 + cp_ = GBK; 1100 + break; 1101 + } 1102 + } 1103 + 1104 + void WriteLine( const unicode* str, ulong len ) 1105 + { 1106 + // まず WideCharToMultiByte API を利用して変換 1107 + int r; 1108 + while( 1109 + 0==(r=::WideCharToMultiByte(cp_,0,str,len,buf_,bsiz_,NULL,NULL)) 1110 + && ::GetLastError()==ERROR_INSUFFICIENT_BUFFER ) 1111 + ReserveMoreBuffer(); 1112 + 1113 + bool ascii = true; 1114 + for( int i=0; i<r; ++i ) 1115 + if( buf_[i] & 0x80 ) 1116 + { 1117 + // 非ASCII部分は最上位ビットを落としてから出力 1118 + if( ascii ) 1119 + { 1120 + if( hz_ ) 1121 + fp_.WriteC( 0x7E ), fp_.WriteC( 0x7B ); 1122 + else 1123 + fp_.WriteC( 0x0E ); 1124 + ascii = false; 1125 + } 1126 + fp_.WriteC( buf_[i++] & 0x7F ); 1127 + fp_.WriteC( buf_[i] & 0x7F ); 1128 + } 1129 + else 1130 + { 1131 + // ASCII部分はそのまま出力 1132 + if( !ascii ) 1133 + { 1134 + if( hz_ ) 1135 + fp_.WriteC( 0x7E ), fp_.WriteC( 0x7D ); 1136 + else 1137 + fp_.WriteC( 0x0F ); 1138 + ascii = true; 1139 + } 1140 + fp_.WriteC( buf_[i] ); 1141 + 1142 + // ただしHZの場合、0x7E は 0x7E 0x7E と表す 1143 + if( hz_ && buf_[i]==0x7E ) 1144 + fp_.WriteC( 0x7E ); 1145 + } 1146 + 1147 + // 最後は確実にASCIIに戻す 1148 + if( !ascii ) 1149 + if( hz_ ) 1150 + fp_.WriteC( 0x7E ), fp_.WriteC( 0x7D ); 1151 + else 1152 + fp_.WriteC( 0x0F ); 1153 + } 1154 + 1155 + int cp_; 1156 + bool hz_; 1157 +}; 1158 + 1159 + 1160 + 1161 + 1162 +//------------------------------------------------------------------------- 1163 +// ISO-2022 サブセットその2。日本語EUC 1164 +//------------------------------------------------------------------------- 1165 + 1166 +// Helper: SJIS ==> JIS X 0208 1167 +static void sjis2jis( uchar s1, uchar s2, char* k ) 1168 +{ 1169 + if( ((s1==0xfa || s1==0xfb) && s2>=0x40) || (s1==0xfc && (s2&0xf0)==0x40) ) 1170 + { 1171 + // IBM外字のマッピング 1172 +static const WORD IBM_sjis2kuten[] = { 1173 +/*fa40*/0x5c51,0x5c52,0x5c53,0x5c54,0x5c55,0x5c56,0x5c57,0x5c58,0x5c59,0x5c5a,0x0d15,0x0d16,0x0d17,0x0d18,0x0d19,0x0d1a, 1174 +/*fa50*/0x0d1b,0x0d1c,0x0d1d,0x0d1e,0x022c,0x5c5c,0x5c5d,0x5c5e,0x0d4a,0x0d42,0x0d44,0x0248,0x5901,0x5902,0x5903,0x5904, 1175 +/*fa60*/0x5905,0x5906,0x5907,0x5908,0x5909,0x590a,0x590b,0x590c,0x590d,0x590e,0x590f,0x5910,0x5911,0x5912,0x5913,0x5914, 1176 +/*fa70*/0x5915,0x5916,0x5917,0x5918,0x5919,0x591a,0x591b,0x591c,0x591d,0x591e,0x591f,0x5920,0x5921,0x5922,0x5923,/**/0x0109, 1177 +/*fa80*/0x5924,0x5925,0x5926,0x5927,0x5928,0x5929,0x592a,0x592b,0x592c,0x592d,0x592e,0x592f,0x5930,0x5931,0x5932,0x5933, 1178 +/*fa90*/0x5934,0x5935,0x5936,0x5937,0x5938,0x5939,0x593a,0x593b,0x593c,0x593d,0x593e,0x593f,0x5940,0x5941,0x5942,0x5943, 1179 +/*faa0*/0x5944,0x5945,0x5946,0x5947,0x5948,0x5949,0x594a,0x594b,0x594c,0x594d,0x594e,0x594f,0x5950,0x5951,0x5952,0x5953, 1180 +/*fab0*/0x5954,0x5955,0x5956,0x5957,0x5958,0x5959,0x595a,0x595b,0x595c,0x595d,0x595e,0x5a01,0x5a02,0x5a03,0x5a04,0x5a05, 1181 +/*fac0*/0x5a06,0x5a07,0x5a08,0x5a09,0x5a0a,0x5a0b,0x5a0c,0x5a0d,0x5a0e,0x5a0f,0x5a10,0x5a11,0x5a12,0x5a13,0x5a14,0x5a15, 1182 +/*fad0*/0x5a16,0x5a17,0x5a18,0x5a19,0x5a1a,0x5a1b,0x5a1c,0x5a1d,0x5a1e,0x5a1f,0x5a20,0x5a21,0x5a22,0x5a23,0x5a24,0x5a25, 1183 +/*fae0*/0x5a26,0x5a27,0x5a28,0x5a29,0x5a2a,0x5a2b,0x5a2c,0x5a2d,0x5a2e,0x5a2f,0x5a30,0x5a31,0x5a32,0x5a33,0x5a34,0x5a35, 1184 +/*faf0*/0x5a36,0x5a37,0x5a38,0x5a39,0x5a3a,0x5a3b,0x5a3c,0x5a3d,0x5a3e,0x5a3f,0x5a40,0x5a41,0x5a42,/**/0x0109,0x0109,0x0109, 1185 +/*fb40*/0x5a43,0x5a44,0x5a45,0x5a46,0x5a47,0x5a48,0x5a49,0x5a4a,0x5a4b,0x5a4c,0x5a4d,0x5a4e,0x5a4f,0x5a50,0x5a51,0x5a52, 1186 +/*fb50*/0x5a53,0x5a54,0x5a55,0x5a56,0x5a57,0x5a58,0x5a59,0x5a5a,0x5a5b,0x5a5c,0x5a5d,0x5a5e,0x5b01,0x5b02,0x5b03,0x5b04, 1187 +/*fb60*/0x5b05,0x5b06,0x5b07,0x5b08,0x5b09,0x5b0a,0x5b0b,0x5b0c,0x5b0d,0x5b0e,0x5b0f,0x5b10,0x5b11,0x5b12,0x5b13,0x5b14, 1188 +/*fb70*/0x5b15,0x5b16,0x5b17,0x5b18,0x5b19,0x5b1a,0x5b1b,0x5b1c,0x5b1d,0x5b1e,0x5b1f,0x5b20,0x5b21,0x5b22,0x5b23,/**/0x0109, 1189 +/*fb80*/0x5b24,0x5b25,0x5b26,0x5b27,0x5b28,0x5b29,0x5b2a,0x5b2b,0x5b2c,0x5b2d,0x5b2e,0x5b2f,0x5b30,0x5b31,0x5b32,0x5b33, 1190 +/*fb90*/0x5b34,0x5b35,0x5b36,0x5b37,0x5b38,0x5b39,0x5b3a,0x5b3b,0x5b3c,0x5b3d,0x5b3e,0x5b3f,0x5b40,0x5b41,0x5b42,0x5b43, 1191 +/*fba0*/0x5b44,0x5b45,0x5b46,0x5b47,0x5b48,0x5b49,0x5b4a,0x5b4b,0x5b4c,0x5b4d,0x5b4e,0x5b4f,0x5b50,0x5b51,0x5b52,0x5b53, 1192 +/*fbb0*/0x5b54,0x5b55,0x5b56,0x5b57,0x5b58,0x5b59,0x5b5a,0x5b5b,0x5b5c,0x5b5d,0x5b5e,0x5c01,0x5c02,0x5c03,0x5c04,0x5c05, 1193 +/*fbc0*/0x5c06,0x5c07,0x5c08,0x5c09,0x5c0a,0x5c0b,0x5c0c,0x5c0d,0x5c0e,0x5c0f,0x5c10,0x5c11,0x5c12,0x5c13,0x5c14,0x5c15, 1194 +/*fbd0*/0x5c16,0x5c17,0x5c18,0x5c19,0x5c1a,0x5c1b,0x5c1c,0x5c1d,0x5c1e,0x5c1f,0x5c20,0x5c21,0x5c22,0x5c23,0x5c24,0x5c25, 1195 +/*fbe0*/0x5c26,0x5c27,0x5c28,0x5c29,0x5c2a,0x5c2b,0x5c2c,0x5c2d,0x5c2e,0x5c2f,0x5c30,0x5c31,0x5c32,0x5c33,0x5c34,0x5c35, 1196 +/*fbf0*/0x5c36,0x5c37,0x5c38,0x5c39,0x5c3a,0x5c3b,0x5c3c,0x5c3d,0x5c3e,0x5c3f,0x5c40,0x5c41,0x5c42,/**/0x0109,0x0109,0x0109, 1197 +/*fc40*/0x5c43,0x5c44,0x5c45,0x5c46,0x5c47,0x5c48,0x5c49,0x5c4a,0x5c4b,0x5c4c,0x5c4d,0x5c4e,/**/0x0109,0x0109,0x0109,0x0109, 1198 +}; 1199 + k[0] = IBM_sjis2kuten[ (s1-0xfa)*12*16 + (s2-0x40) ]>>8; 1200 + k[1] = IBM_sjis2kuten[ (s1-0xfa)*12*16 + (s2-0x40) ]&0xff; 1201 + } 1202 + else 1203 + { 1204 + // その他 1205 + if( s2>=0x9f ) 1206 + { 1207 + if( s1>=0xe0 ) k[0] = ((s1-0xc0)<<1); 1208 + else k[0] = ((s1-0x80)<<1); 1209 + k[1] = s2-0x9e; 1210 + } 1211 + else 1212 + { 1213 + if( s1>=0xe0 ) k[0] = ((s1-0xc0)<<1)-1; 1214 + else k[0] = ((s1-0x80)<<1)-1; 1215 + 1216 + if( s2 & 0x80 ) k[1] = s2-0x40; 1217 + else k[1] = s2-0x3f; 1218 + } 1219 + } 1220 + 1221 + k[0] += 0x20; 1222 + k[1] += 0x20; 1223 +} 1224 + 1225 +struct wEucJp : public TextFileWPimpl 1226 +{ 1227 + wEucJp( FileW& w ) 1228 + : TextFileWPimpl(w) {} 1229 + 1230 + void WriteLine( const unicode* str, ulong len ) 1231 + { 1232 + // まず WideCharToMultiByte API を利用して変換 1233 + int r; 1234 + while( 1235 + 0==(r=::WideCharToMultiByte(932,0,str,len,buf_,bsiz_,NULL,NULL)) 1236 + && ::GetLastError()==ERROR_INSUFFICIENT_BUFFER ) 1237 + ReserveMoreBuffer(); 1238 + 1239 + for( int i=0; i<r; ++i ) 1240 + if( buf_[i] & 0x80 ) 1241 + { 1242 + if( 0xA1<=(uchar)buf_[i] && (uchar)buf_[i]<=0xDF ) 1243 + { 1244 + // カナ 1245 + fp_.WriteC( 0x8E ); 1246 + fp_.WriteC( buf_[i] ); 1247 + } 1248 + else 1249 + { 1250 + // JIS X 0208 1251 + sjis2jis( buf_[i], buf_[i+1], buf_+i ); 1252 + fp_.WriteC( buf_[i++] | 0x80 ); 1253 + fp_.WriteC( buf_[i] | 0x80 ); 1254 + } 1255 + } 1256 + else 1257 + { 1258 + // ASCII部分はそのまま出力 1259 + fp_.WriteC( buf_[i] ); 1260 + } 1261 + } 1262 +}; 1263 + 1264 + 1265 + 1266 +//------------------------------------------------------------------------- 1267 +// ISO-2022 サブセットその3。ISO-2022-JP 1268 +//------------------------------------------------------------------------- 1269 + 1270 +struct wIsoJp : public TextFileWPimpl 1271 +{ 1272 + wIsoJp( FileW& w ) 1273 + : TextFileWPimpl(w) 1274 + { 1275 + fp_.Write( "\x1b\x28\x42", 3 ); 1276 + } 1277 + 1278 + void WriteLine( const unicode* str, ulong len ) 1279 + { 1280 + // まず WideCharToMultiByte API を利用して変換 1281 + int r; 1282 + while( 1283 + 0==(r=::WideCharToMultiByte(932,0,str,len,buf_,bsiz_,NULL,NULL)) 1284 + && ::GetLastError()==ERROR_INSUFFICIENT_BUFFER ) 1285 + ReserveMoreBuffer(); 1286 + 1287 + enum { ROMA, KANJI, KANA } state = ROMA; 1288 + for( int i=0; i<r; ++i ) 1289 + if( buf_[i] & 0x80 ) 1290 + { 1291 + if( 0xA1<=(uchar)buf_[i] && (uchar)buf_[i]<=0xDF ) 1292 + { 1293 + // カナ 1294 + if( state != KANA ) 1295 + fp_.Write( "\x1b\x28\x49", 3 ), state = KANA; 1296 + fp_.WriteC( buf_[i] & 0x7f ); 1297 + } 1298 + else 1299 + { 1300 + // JIS X 0208 1301 + if( state != KANJI ) 1302 + fp_.Write( "\x1b\x24\x42", 3 ), state = KANJI; 1303 + sjis2jis( buf_[i], buf_[i+1], buf_+i ); 1304 + fp_.WriteC( buf_[i++] ); 1305 + fp_.WriteC( buf_[i] ); 1306 + } 1307 + } 1308 + else 1309 + { 1310 + // ASCII部分はそのまま出力 1311 + if( state != ROMA ) 1312 + fp_.Write( "\x1b\x28\x42", 3 ), state = ROMA; 1313 + fp_.WriteC( buf_[i] ); 1314 + } 1315 + 1316 + if( state != ROMA ) 1317 + fp_.Write( "\x1b\x28\x42", 3 ), state = ROMA; 1318 + } 1319 +}; 1320 + 1321 + 1322 + 1323 + 1324 +//------------------------------------------------------------------------- 1325 +// 書き込みルーチンの準備等々 1326 +//------------------------------------------------------------------------- 1327 + 1328 +TextFileW::TextFileW( int charset, int linebreak ) 1329 + : cs_( charset ), lb_(linebreak) 1330 +{ 1331 +} 1332 + 1333 +TextFileW::~TextFileW() 1334 +{ 1335 + Close(); 1336 +} 1337 + 1338 +void TextFileW::Close() 1339 +{ 1340 + impl_ = NULL; 1341 + fp_.Close(); 1342 +} 1343 + 1344 +void TextFileW::WriteLine( const unicode* buf, ulong siz, bool lastline ) 1345 +{ 1346 + impl_->WriteLine( buf, siz ); 1347 + if( !lastline ) 1348 + { 1349 + static const ulong lbLst[] = {0x0D, 0x0A, 0x000A000D}; 1350 + static const ulong lbLen[] = { 1, 1, 2}; 1351 + impl_->WriteLB( 1352 + reinterpret_cast<const unicode*>(&lbLst[lb_]), lbLen[lb_] ); 1353 + } 1354 +} 1355 + 1356 +bool TextFileW::Open( const TCHAR* fname ) 1357 +{ 1358 + if( !fp_.Open( fname, true ) ) 1359 + return false; 1360 + 1361 + switch( cs_ ) 1362 + { 1363 + case Western: impl_ = new wWest( fp_ ); break; 1364 + case UTF5: impl_ = new wUtf5( fp_ ); break; 1365 + case UTF16l: 1366 + case UTF16LE: impl_ = new wUtf16LE( fp_, cs_==UTF16l ); break; 1367 + case UTF16b: 1368 + case UTF16BE: impl_ = new wUtf16BE( fp_, cs_==UTF16b ); break; 1369 + case UTF32l: 1370 + case UTF32LE: impl_ = new wUtf32LE( fp_, cs_==UTF32l ); break; 1371 + case UTF32b: 1372 + case UTF32BE: impl_ = new wUtf32BE( fp_, cs_==UTF32b ); break; 1373 + case EucJP: impl_ = new wEucJp( fp_ ); break; 1374 + case IsoJP: impl_ = new wIsoJp( fp_ ); break; 1375 + case IsoKR: impl_ = new wIso2022( fp_, cs_ ); break; 1376 + case IsoCN: impl_ = new wIso2022( fp_, cs_ ); break; 1377 + case HZ: impl_ = new wIso2022( fp_, cs_ ); break; 1378 + case UTF8: 1379 + case UTF8N: 1380 + default: 1381 +#ifndef _UNICODE 1382 + if( app().isWin95() && (cs_==UTF8 || cs_==UTF8N) ) 1383 + impl_ = new wUTF8( fp_, cs_ ); 1384 + else if( app().isWin95() && cs_==UTF7 ) 1385 + impl_ = new wUTF7( fp_ ); 1386 + else 1387 +#endif 1388 + impl_ = new wMBCS( fp_, cs_ ); 1389 + break; 1390 + } 1391 + return true; 1392 +}
Added kilib/textfile.h version [64224a920accbcb6]
1 +#ifndef _KILIB_TEXTFILE_H_ 2 +#define _KILIB_TEXTFILE_H_ 3 +#include "types.h" 4 +#include "ktlaptr.h" 5 +#include "memory.h" 6 +#include "file.h" 7 +#ifndef __ccdoc__ 8 +namespace ki { 9 +#endif 10 + 11 + 12 + 13 +//========================================================================= 14 +//@{ @pkg ki.StdLib //@} 15 +//@{ 16 +// 利用可能コードセット 17 +// 18 +// ただし、ここでリストアップされたもののうち、Windowsにちゃんと 19 +// 言語サポートがインストールされているものだけが実際には対応可能。 20 +// 値が-100より小さいコードは、そのすぐ上にあるコードページの言語 21 +// サポートを利用して変換を行うため、それに依存する。 22 +//@} 23 +//========================================================================= 24 + 25 +enum charset { 26 + AutoDetect = 0, // 自動判定 27 + // SJIS/EucJP/IsoJP/IsoKR/IsoCN 28 + // UTF5/UTF8/UTF8N/UTF16b/UTF16l/UTF32b/UTF32l 29 + // を判定する。他は知らない。(^^; 30 + 31 + Western = 1252, // 欧米 (Windows1252 >> ISO-8859-1) 32 + Turkish = 1254, // トルコ語 (Windows1254 >> ISO-8859-9) 33 + Hebrew = 1255, // ヘブライ語(Windows1255 >> ISO-8859-8) 34 + Arabic = 1256, // アラビア語(Windows1256 〜 ISO-8859-6) 35 + Baltic = 1257, // バルト語 (Windows1257 >> ISO-8859-13) 36 + Vietnamese = 1258, // ベトナム語(Windows1258 != VISCII) 37 + Central = 1250, // 中央ヨーロッパ(Windows1250 〜 ISO-8859-2) 38 + Greek = 1253, // ギリシャ語(Windows1253 〜 ISO-8859-7) 39 + Thai = 874, // タイ語 40 + 41 + Cyrillic = 1251, // キリル語(Windows1251 != ISO-8859-5) 42 + Koi8R = 20866,// キリル語(KOI8-R) 43 + Koi8U = 21866,// キリル語(KOI8-U ウクライナ系) 44 + 45 + UHC = 949, // 韓国語1 (Unified Hangle Code >> EUC-KR) 46 + IsoKR = -950, // 韓国語2 (ISO-2022-KR) 47 + Johab = 1361, // 韓国語3 (Johab) 48 + 49 + GBK = 936, // 中国語1 (簡体字 GBK >> EUC-CN) 50 + IsoCN = -936, // 中国語2 (簡体字 ISO-2022-CN) 51 + HZ = -937, // 中国語3 (簡体字 HZ-GB2312) 52 + Big5 = 950, // 中国語4 (繁体字 Big5) 53 + 54 + SJIS = 932, // 日本語1 (Shift_JIS) 55 + EucJP = -932, // 日本語2 (日本語EUC) 56 + IsoJP = -933, // 日本語3 (ISO-2022-JP) 57 + 58 + UTF5 = -2, // Unicode (UTF-5) : BOM無し 59 + UTF7 = 65000,// Unicode (UTF-7) : BOM無し 60 + UTF8 =-65001,// Unicode (UTF-8) : BOM有り 61 + UTF8N = 65001,// Unicode (UTF-8N) : BOM無し 62 + UTF16b = -3, // Unicode (UTF-16) : BOM有り BE 63 + UTF16l = -4, // Unicode (UTF-16) : BOM有り LE 64 + UTF16BE = -5, // Unicode (UTF-16BE): BOM無し 65 + UTF16LE = -6, // Unicode (UTF-16LE): BOM無し 66 + UTF32b = -7, // Unicode (UTF-32) : BOM有り BE 67 + UTF32l = -8, // Unicode (UTF-32) : BOM有り LE 68 + UTF32BE = -9, // Unicode (UTF-32BE): BOM無し 69 + UTF32LE = -10, // Unicode (UTF-32LE): BOM無し 70 + 71 + DOSUS = 437 // DOSLatinUS (CP437) 72 +}; 73 + 74 +//========================================================================= 75 +//@{ 76 +// 改行コード 77 +//@} 78 +//========================================================================= 79 + 80 +enum lbcode { 81 + CR = 0, 82 + LF = 1, 83 + CRLF = 2 84 +}; 85 + 86 +struct TextFileRPimpl; 87 +struct TextFileWPimpl; 88 + 89 + 90 + 91 +//========================================================================= 92 +//@{ 93 +// テキストファイル読込 94 +// 95 +// ファイルを指定された文字コードで解釈し、Unicode文字列として 96 +// 一行毎に返す。文字コードや改行コードの自動判定も可能。 97 +//@} 98 +//========================================================================= 99 + 100 +class TextFileR : public Object 101 +{ 102 +public: 103 + 104 + //@{ コンストラクタ(コード指定)//@} 105 + TextFileR( int charset=AutoDetect ); 106 + 107 + //@{ デストラクタ //@} 108 + ~TextFileR(); 109 + 110 + //@{ 開く //@} 111 + bool Open( const TCHAR* fname ); 112 + 113 + //@{ 閉じる //@} 114 + void Close(); 115 + 116 + //@{ 117 + // 読み込み (読んだ長さを返す) 118 + // 119 + // 少なくとも20くらいのサイズを確保したバッファを指定してください。 120 + //@} 121 + size_t ReadLine( unicode* buf, ulong siz ); 122 + 123 +public: 124 + 125 + //@{ 読んでるファイルのコードページ //@} 126 + int codepage() const; 127 + 128 + //@{ 改行コード (0:CR, 1:LF, 2:CRLF) //@} 129 + int linebreak() const; 130 + 131 + //@{ 読み込み状況 (0:EOF, 1:EOL, 2:EOB) //@} 132 + int state() const; 133 + 134 + //@{ ファイルサイズ //@} 135 + ulong size() const; 136 + 137 + //@{ 改行が一個も見つからなかったフラグ //@} 138 + bool nolb_found() const; 139 +private: 140 + 141 + dptr<TextFileRPimpl> impl_; 142 + FileR fp_; 143 + int cs_; 144 + int lb_; 145 + bool nolbFound_; 146 + 147 +private: 148 + 149 + int AutoDetection( int cs, const uchar* ptr, ulong siz ); 150 + 151 +private: 152 + 153 + NOCOPY(TextFileR); 154 +}; 155 + 156 + 157 + 158 +//------------------------------------------------------------------------- 159 + 160 +inline int TextFileR::codepage() const 161 + { return cs_; } 162 + 163 +inline int TextFileR::linebreak() const 164 + { return lb_; } 165 + 166 +inline ulong TextFileR::size() const 167 + { return fp_.size(); } 168 + 169 +inline bool TextFileR::nolb_found() const 170 + { return nolbFound_; } 171 + 172 + 173 +//========================================================================= 174 +//@{ 175 +// テキストファイル書込 176 +// 177 +// Unicode文字列を受け取り、指定された文字コードに変換しながら出力する。 178 +//@} 179 +//========================================================================= 180 + 181 +class TextFileW : public Object 182 +{ 183 +public: 184 + 185 + //@{ コンストラクタ(文字,改行コード指定)//@} 186 + TextFileW( int charset, int linebreak ); 187 + ~TextFileW(); 188 + 189 + //@{ 開く //@} 190 + bool Open( const TCHAR* fname ); 191 + 192 + //@{ 閉じる //@} 193 + void Close(); 194 + 195 + //@{ 一行書き出し //@} 196 + void WriteLine( const unicode* buf, ulong siz, bool lastline ); 197 + 198 +private: 199 + 200 + dptr<TextFileWPimpl> impl_; 201 + FileW fp_; 202 + const int cs_; 203 + const int lb_; 204 + 205 +private: 206 + 207 + NOCOPY(TextFileW); 208 +}; 209 + 210 + 211 + 212 +//========================================================================= 213 + 214 +} // namespace ki 215 +#endif // _KILIB_TEXTFILE_H_
Added kilib/thread.cpp version [1216ad374a35c8fc]
1 +#include "stdafx.h" 2 +#include "thread.h" 3 +using namespace ki; 4 + 5 + 6 + 7 +//========================================================================= 8 + 9 +ThreadManager* ThreadManager::pUniqueInstance_; 10 + 11 +ThreadManager::ThreadManager() 12 + : threadNum_(0) 13 +{ 14 + // 唯一のインスタンスは私です。 15 + pUniqueInstance_ = this; 16 +} 17 + 18 +//========================================================================= 19 + 20 +DWORD WINAPI ThreadManager::ThreadStubFunc(void* param) 21 +{ 22 + Runnable* r = static_cast<Runnable*>(param); 23 + r->StartThread(); 24 + r->FinalizeThread(); 25 + return 0; 26 +} 27 + 28 +void ThreadManager::Run( Runnable& r ) 29 +{ 30 + r.PleaseExit(); 31 + 32 + DWORD id; 33 + r.hThread_ = ::CreateThread( 34 + NULL, 0, &ThreadStubFunc, &r, CREATE_SUSPENDED, &id ); 35 + r.hEvent_ = ::CreateEvent( NULL, TRUE, FALSE, NULL ); 36 + ::ResumeThread( r.hThread_ ); 37 +} 38 + 39 +//========================================================================= 40 + 41 +Runnable::Runnable() 42 + : hThread_( NULL ) 43 + , hEvent_ ( NULL ) 44 +{ 45 +} 46 + 47 +Runnable::~Runnable() 48 +{ 49 + PleaseExit(); // あくまで最終手段 50 +} 51 + 52 +bool Runnable::isRunning() const 53 +{ 54 + return hThread_ != NULL; 55 +} 56 + 57 +bool Runnable::isExitRequested() const 58 +{ 59 + return WAIT_OBJECT_0 == ::WaitForSingleObject( hEvent_, 0 ); 60 +} 61 + 62 +void Runnable::FinalizeThread() 63 +{ 64 + ::CloseHandle( hThread_ ); 65 + hThread_ = NULL; 66 + ::CloseHandle( hEvent_ ); 67 + hEvent_ = NULL; 68 +} 69 + 70 +void Runnable::PleaseExit() 71 +{ 72 + if( HANDLE ht = hThread_ ) 73 + { 74 + ::SetEvent( hEvent_ ); 75 + ::WaitForSingleObject( ht, INFINITE ); 76 + } 77 +}
Added kilib/thread.h version [ad2ee82f907cec8e]
1 +#ifndef _KILIB_THREAD_H_ 2 +#define _KILIB_THREAD_H_ 3 +#include "types.h" 4 +#ifndef __ccdoc__ 5 +namespace ki { 6 +#endif 7 + 8 + 9 + 10 +//========================================================================= 11 +//@{ @pkg ki.Core //@} 12 +//@{ 13 +// マルチスレッドの管理 14 +// 15 +// まだ何もしません 16 +//@} 17 +//========================================================================= 18 + 19 + 20 +class ThreadManager 21 +{ 22 +public: 23 + //@{ 実行可能オブジェクトをに起動をかける //@} 24 + void Run( class Runnable& r ); 25 + 26 + //@{ 複数スレッドが走っているかどうか? //@} 27 + bool isMT() const; 28 + 29 +private: 30 + 31 + ThreadManager(); 32 + 33 +private: 34 + 35 + int threadNum_; 36 + static ThreadManager* pUniqueInstance_; 37 + 38 +private: 39 + 40 + static DWORD WINAPI ThreadStubFunc(void*); 41 + 42 +private: 43 + 44 + friend void APIENTRY Startup(); 45 + friend inline ThreadManager& thd(); 46 + NOCOPY(ThreadManager); 47 +}; 48 + 49 + 50 + 51 +//------------------------------------------------------------------------- 52 + 53 +//@{ 唯一のスレッド管理オブジェクトを返す //@} 54 +inline ThreadManager& thd() 55 + { return *ThreadManager::pUniqueInstance_; } 56 + 57 +inline bool ThreadManager::isMT() const 58 + { return 0 != threadNum_; } 59 + 60 + 61 + 62 +//========================================================================= 63 +//@{ 64 +// 実行可能オブジェクト基底 65 +//@} 66 +//========================================================================= 67 + 68 +class Runnable 69 +{ 70 +protected: 71 + Runnable(); 72 + virtual ~Runnable(); 73 + 74 + virtual void StartThread() = 0; 75 + void PleaseExit(); 76 + bool isExitRequested() const; 77 + bool isRunning() const; 78 + 79 +private: 80 + void FinalizeThread(); 81 + friend class ThreadManager; 82 + HANDLE hEvent_; 83 + HANDLE hThread_; 84 +}; 85 + 86 + 87 + 88 +//========================================================================= 89 +//@{ 90 +// マルチスレッド・ポリシー1 91 +// 92 +// このクラスから派生すると、AutoLock クラスを使えるようになります。 93 +// このクラスに this ポインタを渡すことで排他状態に入り、デストラクタで 94 +// 抜け出せるようになります。NoLockable::AutoLock は実際は何もしません。 95 +//@} 96 +//========================================================================= 97 + 98 +class NoLockable 99 +{ 100 +protected: 101 + struct AutoLock 102 + { 103 + AutoLock( NoLockable* host ) {} 104 + }; 105 +}; 106 + 107 + 108 + 109 +//========================================================================= 110 +//@{ 111 +// マルチスレッド・ポリシー2 112 +// 113 +// このクラスから派生すると、AutoLock クラスを使えるようになります。 114 +// このクラスに this ポインタを渡すことで排他状態に入り、デストラクタで 115 +// 抜け出せるようになります。EzLockable::AutoLock は、シングルスレッドで 116 +// 動作するときがほとんどというアプリケーション向けに、高速だけれど 117 +// 不完全な排他制御を行います。2本目のスレッド立ち上げの瞬間が危ない。 118 +//@} 119 +//========================================================================= 120 + 121 +class EzLockable 122 +{ 123 +protected: 124 + EzLockable() 125 + { ::InitializeCriticalSection( &csection_ ); } 126 + ~EzLockable() 127 + { ::DeleteCriticalSection( &csection_ ); } 128 + 129 + struct AutoLock 130 + { 131 + AutoLock( EzLockable* host ) 132 + { 133 + if( NULL != (pCs_=(thd().isMT() ? &host->csection_ : NULL)) ) 134 + ::EnterCriticalSection( pCs_ ); 135 + } 136 + ~AutoLock() 137 + { 138 + if( pCs_ ) 139 + ::LeaveCriticalSection( pCs_ ); 140 + } 141 + private: 142 + NOCOPY(AutoLock); 143 + CRITICAL_SECTION* pCs_; 144 + }; 145 + 146 +private: 147 + CRITICAL_SECTION csection_; 148 + #ifdef __DMC__ 149 + friend struct EzLockable::AutoLock; 150 + #else 151 + friend struct AutoLock; 152 + #endif 153 +}; 154 + 155 + 156 + 157 +//========================================================================= 158 +//@{ 159 +// マルチスレッド・ポリシー3 160 +// 161 +// このクラスから派生すると、AutoLock クラスを使えるようになります。 162 +// このクラスに this ポインタを渡すことで排他状態に入り、デストラクタで 163 +// 抜け出せるようになります。Lockable::AutoLock は、完全な排他制御を 164 +// 行います。万全を期すならかならずこのクラスを用いましょう。 165 +//@} 166 +//========================================================================= 167 + 168 +class Lockable 169 +{ 170 +protected: 171 + Lockable() 172 + { ::InitializeCriticalSection( &csection_ ); } 173 + ~Lockable() 174 + { ::DeleteCriticalSection( &csection_ ); } 175 + 176 + struct AutoLock 177 + { 178 + AutoLock( Lockable* host ) 179 + { 180 + pCs_ = &host->csection_; 181 + ::EnterCriticalSection( pCs_ ); 182 + } 183 + ~AutoLock() 184 + { 185 + ::LeaveCriticalSection( pCs_ ); 186 + } 187 + private: 188 + NOCOPY(AutoLock); 189 + CRITICAL_SECTION* pCs_; 190 + }; 191 + friend struct AutoLock; 192 + 193 +private: 194 + CRITICAL_SECTION csection_; 195 +}; 196 + 197 + 198 + 199 +//========================================================================= 200 + 201 +} // namespace ki 202 +#endif // _KILIB_THREAD_H_
Added kilib/types.h version [49179567f8607bc7]
1 +#ifndef _KILIB_TYPES_H_ 2 +#define _KILIB_TYPES_H_ 3 + 4 + 5 + 6 +//========================================================================= 7 +//@{ @pkg ki.Types //@} 8 +//========================================================================= 9 + 10 +// 変数のサイズを明示的に指示するときに使う名前 11 +typedef unsigned char byte; 12 +typedef unsigned short dbyte; 13 +typedef unsigned long qbyte; 14 +typedef wchar_t unicode; 15 + 16 +// unsigned って毎回打つの面倒 17 +typedef unsigned char uchar; 18 +typedef unsigned short ushort; 19 +typedef unsigned int uint; 20 +typedef unsigned long ulong; 21 + 22 +// 配列の要素数 23 +#define countof(_array) (sizeof(_array)/sizeof(_array[0])) 24 + 25 +// 大きい方、小さい方 26 +template<typename T> inline T Min(T x,T y) { return (x<y ? x : y); } 27 +template<typename T> inline T Max(T x,T y) { return (y<x ? x : y); } 28 + 29 +// 古いC++処理系でも、forで使う変数のスコープを強制的に制限 30 +#if defined(_MSC_VER) || defined(__DMC__) 31 +#define for if(0);else for 32 +#endif 33 + 34 +// コピー禁止オブジェクト 35 +#define NOCOPY(T) T( const T& ); T& operator=( const T& ) 36 + 37 + 38 + 39 +#endif // _KILIB_TYPES_H_
Added kilib/window.cpp version [db5de2240a19512a]
1 +#include "stdafx.h" 2 +#include "app.h" 3 +#include "window.h" 4 +using namespace ki; 5 + 6 + 7 + 8 +//========================================================================= 9 +// IMEに関するあれこれ 10 +//========================================================================= 11 + 12 +IMEManager* IMEManager::pUniqueInstance_; 13 + 14 +IMEManager::IMEManager() 15 +#ifdef USEGLOBALIME 16 + : immApp_( NULL ) 17 + , immMsg_( NULL ) 18 +#endif 19 +{ 20 + #ifdef USEGLOBALIME 21 + // 色々面倒なのでWin95ではGlobalIME無し 22 + if( !app().isWin95() ) 23 + { 24 + app().InitModule( App::OLE ); 25 + if( S_OK == ::CoCreateInstance( 26 + CLSID_CActiveIMM, NULL, CLSCTX_INPROC_SERVER, 27 + IID_IActiveIMMApp, (void**)&immApp_ ) ) 28 + { 29 + immApp_->QueryInterface( 30 + IID_IActiveIMMMessagePumpOwner, (void**)&immMsg_ ); 31 + } 32 + } 33 + #endif 34 + 35 + // 唯一のインスタンスは私です 36 + pUniqueInstance_ = this; 37 +} 38 + 39 +IMEManager::~IMEManager() 40 +{ 41 + #ifdef USEGLOBALIME 42 + if( immMsg_ != NULL ) 43 + immMsg_->Release(); 44 + if( immApp_ != NULL ) 45 + immApp_->Release(); 46 + #endif 47 +} 48 + 49 +void IMEManager::EnableGlobalIME( bool enable ) 50 +{ 51 + #ifdef USEGLOBALIME 52 + if( immApp_ ) 53 + if( enable ) immApp_->Activate( TRUE ); 54 + else immApp_->Deactivate(); 55 + #endif 56 +} 57 + 58 +void IMEManager::FilterWindows( ATOM* lst, UINT siz ) 59 +{ 60 + #ifdef USEGLOBALIME 61 + if( immApp_ ) 62 + immApp_->FilterClientWindows( lst, siz ); 63 + #endif 64 +} 65 + 66 +inline void IMEManager::TranslateMsg( MSG* msg ) 67 +{ 68 + #ifdef USEGLOBALIME 69 + if( immMsg_ ) 70 + if( S_OK == immMsg_->OnTranslateMessage( msg ) ) 71 + return; 72 + #endif 73 + ::TranslateMessage( msg ); 74 +} 75 + 76 +inline LRESULT IMEManager::DefProc( HWND h, UINT m, WPARAM w, LPARAM l ) 77 +{ 78 + #ifdef USEGLOBALIME 79 + if( immApp_ ) 80 + { 81 + LRESULT res; 82 + if( S_OK == immApp_->OnDefWindowProc( h,m,w,l,&res ) ) 83 + return res; 84 + } 85 + #endif 86 + return ::DefWindowProc( h, m, w, l ); 87 +} 88 + 89 +inline void IMEManager::MsgLoopBegin() 90 +{ 91 + #ifdef USEGLOBALIME 92 + if( immMsg_ ) 93 + immMsg_->Start(); 94 + #endif 95 +} 96 + 97 +inline void IMEManager::MsgLoopEnd() 98 +{ 99 + #ifdef USEGLOBALIME 100 + if( immMsg_ ) 101 + immMsg_->End(); 102 + #endif 103 +} 104 + 105 +void IMEManager::SetFont( HWND wnd, const LOGFONT& lf ) 106 +{ 107 + HIMC ime; 108 + LOGFONT* plf = const_cast<LOGFONT*>(&lf); 109 + 110 + #ifdef USEGLOBALIME 111 + if( immApp_ ) 112 + { 113 + immApp_->GetContext( wnd, &ime ); 114 + #ifdef _UNICODE 115 + immApp_->SetCompositionFontW( ime, plf ); 116 + #else 117 + immApp_->SetCompositionFontA( ime, plf ); 118 + #endif 119 + immApp_->ReleaseContext( wnd, ime ); 120 + } 121 + else 122 + #endif 123 + { 124 + ime = ::ImmGetContext( wnd ); 125 + ::ImmSetCompositionFont( ime, plf ); 126 + ::ImmReleaseContext( wnd, ime ); 127 + } 128 +} 129 + 130 +void IMEManager::SetPos( HWND wnd, int x, int y ) 131 +{ 132 + HIMC ime; 133 + COMPOSITIONFORM cf; 134 + cf.dwStyle = CFS_POINT; 135 + cf.ptCurrentPos.x = x; 136 + cf.ptCurrentPos.y = y; 137 + 138 + #ifdef USEGLOBALIME 139 + if( immApp_ ) 140 + { 141 + immApp_->GetContext( wnd, &ime ); 142 + immApp_->SetCompositionWindow( ime, &cf ); 143 + immApp_->ReleaseContext( wnd, ime ); 144 + } 145 + else 146 + #endif 147 + { 148 + ime = ::ImmGetContext( wnd ); 149 + ::ImmSetCompositionWindow( ime, &cf ); 150 + ::ImmReleaseContext( wnd, ime ); 151 + } 152 +} 153 + 154 +void IMEManager::GetString( HWND wnd, unicode** str, ulong* len ) 155 +{ 156 + *str = NULL; 157 + HIMC ime; 158 + 159 + #ifdef USEGLOBALIME 160 + if( immApp_ ) 161 + { 162 + long s=0; 163 + immApp_->GetContext( wnd, &ime ); 164 + immApp_->GetCompositionStringW( ime, GCS_RESULTSTR, 0, &s, NULL ); 165 + *str = new unicode[ (*len=s/2)+1 ]; 166 + immApp_->GetCompositionStringW( ime, GCS_RESULTSTR, s, &s, *str ); 167 + immApp_->ReleaseContext( wnd, ime ); 168 + } 169 + else 170 + #endif 171 + { 172 + ime = ::ImmGetContext( wnd ); 173 + long s = ::ImmGetCompositionStringW( ime,GCS_RESULTSTR,NULL,0 ); 174 + 175 + #ifndef _UNICODE 176 + if( s <= 0 ) 177 + { 178 + s = ::ImmGetCompositionStringA(ime,GCS_RESULTSTR,NULL,0); 179 + if( s > 0 ) 180 + { 181 + char* tmp = new char[s]; 182 + *str = new unicode[*len=s*2]; 183 + ::ImmGetCompositionStringA( ime,GCS_RESULTSTR,tmp,s ); 184 + *len = ::MultiByteToWideChar( 185 + CP_ACP, MB_PRECOMPOSED, tmp, s, *str, *len ); 186 + delete [] tmp; 187 + } 188 + } 189 + else 190 + #endif 191 + { 192 + *str = new unicode[ (*len=s/2)+1 ]; 193 + ::ImmGetCompositionStringW( ime, GCS_RESULTSTR, *str, s ); 194 + } 195 + 196 + ::ImmReleaseContext( wnd, ime ); 197 + } 198 +} 199 + 200 + 201 + 202 +//========================================================================= 203 +// Windowに関するあれこれ 204 +//========================================================================= 205 + 206 +Window::Window() 207 + : wnd_ (NULL) 208 + , isLooping_(false) 209 +{ 210 +} 211 + 212 +void Window::SetHwnd( HWND wnd ) 213 +{ 214 + wnd_ = wnd; 215 +} 216 + 217 +void Window::MsgLoop() 218 +{ 219 + // thisをメインウインドウとして、 220 + // メインメッセージループを回す 221 + isLooping_ = true; 222 + ime().MsgLoopBegin(); 223 + 224 + for( MSG msg; ::GetMessage( &msg, NULL, 0, 0 ); ) 225 + if( !PreTranslateMessage( &msg ) ) 226 + { 227 + ime().TranslateMsg( &msg ); 228 + ::DispatchMessage( &msg ); 229 + } 230 + 231 + ime().MsgLoopEnd(); 232 + isLooping_ = false; 233 +} 234 + 235 +void Window::ProcessMsg() 236 +{ 237 + // こっちはグローバル関数。 238 + // 未処理メッセージを一掃 239 + 240 + ime().MsgLoopBegin(); 241 + for( MSG msg; ::PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ); ) 242 + { 243 + ime().TranslateMsg( &msg ); 244 + ::DispatchMessage( &msg ); 245 + } 246 + ime().MsgLoopEnd(); 247 +} 248 + 249 + 250 + 251 +//------------------------------------------------------------------------- 252 + 253 +void Window::SetCenter( HWND hwnd, HWND rel ) 254 +{ 255 + // 自分のサイズを取得 256 + RECT rc,pr; 257 + ::GetWindowRect( hwnd, &rc ); 258 + 259 + // 親の位置、ないしは全画面の位置を取得 260 + if( rel != NULL ) 261 + ::GetWindowRect( rel, &pr ); 262 + else 263 + ::SystemParametersInfo( SPI_GETWORKAREA, 0, &pr, 0 ); 264 + 265 + // 中央を計算 266 + ::SetWindowPos( hwnd, 0, 267 + pr.left + ( (pr.right-pr.left)-(rc.right-rc.left) )/2, 268 + pr.top + ( (pr.bottom-pr.top)-(rc.bottom-rc.top) )/2, 269 + 0, 0, SWP_NOSIZE|SWP_NOZORDER ); 270 +} 271 + 272 +void Window::SetFront( HWND hwnd ) 273 +{ 274 + // kazubon氏の TClock のソースを参考にしました。感謝! 275 + 276 + if( app().isNewTypeWindows() ) 277 + { 278 + DWORD pid; 279 + HWND fore= ::GetForegroundWindow(); 280 + DWORD th1 = ::GetWindowThreadProcessId( fore, &pid ); 281 + DWORD th2 = ::GetCurrentThreadId(); 282 + ::AttachThreadInput( th2, th1, TRUE ); 283 + ::SetForegroundWindow( hwnd ); 284 + ::AttachThreadInput( th2, th1, FALSE ); 285 + ::BringWindowToTop( hwnd ); 286 + } 287 + else 288 + { 289 + ::SetForegroundWindow( hwnd ); 290 + } 291 +} 292 + 293 +//========================================================================= 294 + 295 +WndImpl::WndImpl( LPCTSTR className, DWORD style, DWORD styleEx ) 296 + : className_( className ) 297 + , style_ ( style ) 298 + , styleEx_ ( styleEx ) 299 + , thunk_ ( static_cast<byte*>( 300 + ::VirtualAlloc( NULL, THUNK_SIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE )) ) 301 +{ 302 +} 303 + 304 +WndImpl::~WndImpl() 305 +{ 306 + // ウインドウを破棄し忘れてたら閉じる 307 + // …が、この時点で既に vtable は破棄されかかっているので 308 + // 正しい on_destroy が呼ばれる保証は全くない。あくまで 309 + // 緊急脱出用(^^; と考えること。 310 + Destroy(); 311 + ::VirtualFree( thunk_, 0, MEM_RELEASE ); 312 +} 313 + 314 +void WndImpl::Destroy() 315 +{ 316 + if( hwnd() != NULL ) 317 + ::DestroyWindow( hwnd() ); 318 +} 319 + 320 +ATOM WndImpl::Register( WNDCLASSEX* cls ) 321 +{ 322 + // WndImpl派生クラスで使うWndClassを登録。 323 + // プロシージャはkilib謹製のものに書き換えちゃいます。 324 + cls->cbSize = sizeof(WNDCLASSEX); 325 + cls->hInstance = app().hinst(); 326 + cls->lpfnWndProc = StartProc; 327 + return ::RegisterClassEx( cls ); 328 +} 329 + 330 +struct ThisAndParam 331 +{ 332 + // ユーザ指定のパラメータ以外にも渡したいモノが少々… 333 + WndImpl* pThis; 334 + void* pParam; 335 +}; 336 + 337 +bool WndImpl::Create( 338 + LPCTSTR wndName, HWND parent, int x, int y, int w, int h, void* param ) 339 +{ 340 + // ここでthisポインタを忍び込ませておく 341 + ThisAndParam z = { this, param }; 342 + 343 + LOGGER("WndImpl::Create before CreateWindowEx API call"); 344 + 345 + return (NULL != ::CreateWindowEx( 346 + styleEx_, className_, wndName, style_, 347 + x, y, w, h, parent, NULL, app().hinst(), &z 348 + )); 349 +} 350 + 351 + 352 + 353 +//------------------------------------------------------------------------- 354 + 355 +LRESULT CALLBACK WndImpl::StartProc( 356 + HWND wnd, UINT msg, WPARAM wp, LPARAM lp ) 357 +{ 358 + // WM_CREATE以外はスルーの方針で 359 + if( msg != WM_CREATE ) 360 + return ::DefWindowProc( wnd, msg, wp, lp ); 361 + 362 + LOGGER("WndImpl::StartProc WM_CREATE kitaaaaa!!"); 363 + 364 + // 忍ばせて置いたthisポインタを取り出し 365 + CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(lp); 366 + ThisAndParam* pz = static_cast<ThisAndParam*>(cs->lpCreateParams); 367 + WndImpl* pThis = pz->pThis; 368 + cs->lpCreateParams = pz->pParam; 369 + 370 + // サンク 371 + pThis->SetUpThunk( wnd ); 372 + 373 + // WM_CREATE用メッセージを呼ぶ 374 + pThis->on_create( cs ); 375 + return 0; 376 +} 377 + 378 +void WndImpl::SetUpThunk( HWND wnd ) 379 +{ 380 + SetHwnd( wnd ); 381 + 382 + // ここで動的にx86の命令列 383 + // | mov dword ptr [esp+4] this 384 + // | jmp MainProc 385 + // あるいはAMD64の命令列 386 + // | mov rcx this 387 + // | mov rax MainProc 388 + // | jmp rax 389 + // を生成し、メッセージプロシージャとして差し替える。 390 + // 391 + // これで次回からは、第一引数が hwnd のかわりに 392 + // thisポインタになった状態でMainProcが呼ばれる 393 + // …と見なしたプログラムが書ける。 394 + // 395 + // 参考資料:ATLのソース 396 + 397 +#ifdef _M_AMD64 398 + *reinterpret_cast<dbyte*> (thunk_+ 0) = 0xb948; 399 + *reinterpret_cast<WndImpl**>(thunk_+ 2) = this; 400 + *reinterpret_cast<dbyte*> (thunk_+10) = 0xb848; 401 + *reinterpret_cast<void**> (thunk_+12) = MainProc; 402 + *reinterpret_cast<dbyte*> (thunk_+20) = 0xe0ff; 403 +#else 404 + *reinterpret_cast<qbyte*> (thunk_+0) = 0x042444C7; 405 + *reinterpret_cast<WndImpl**>(thunk_+4) = this; 406 + *reinterpret_cast< byte*> (thunk_+8) = 0xE9; 407 + *reinterpret_cast<qbyte*> (thunk_+9) = 408 + reinterpret_cast<byte*>((void*)MainProc)-(thunk_+13); 409 +#endif 410 + 411 + ::FlushInstructionCache( ::GetCurrentProcess(), thunk_, THUNK_SIZE ); 412 + ::SetWindowLongPtr( wnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(&thunk_[0]) ); 413 +} 414 + 415 +LRESULT CALLBACK WndImpl::MainProc( 416 + WndImpl* ptr, UINT msg, WPARAM wp, LPARAM lp ) 417 +{ 418 + if( msg == WM_COMMAND ) 419 + { 420 + if( !ptr->on_command( LOWORD(wp), (HWND)lp ) ) 421 + return ::DefWindowProc( ptr->hwnd(), msg, wp, lp ); 422 + } 423 + else if( msg == WM_DESTROY ) 424 + { 425 + ptr->on_destroy(); 426 + ::SetWindowLongPtr( ptr->hwnd(), GWLP_WNDPROC, 427 + reinterpret_cast<LONG_PTR>(StartProc) ); 428 + if( ptr->isMainWnd() ) 429 + ::PostQuitMessage( 0 ); 430 + ptr->SetHwnd(NULL); 431 + } 432 + else 433 + { 434 + return ptr->on_message( msg, wp, lp ); 435 + } 436 + 437 + return 0; 438 +} 439 + 440 + 441 + 442 +//------------------------------------------------------------------------- 443 + 444 +void WndImpl::on_create( CREATESTRUCT* cs ) 445 +{ 446 + // 何もしない 447 +} 448 + 449 +void WndImpl::on_destroy() 450 +{ 451 + // 何もしない 452 +} 453 + 454 +bool WndImpl::on_command( UINT, HWND ) 455 +{ 456 + // 何もしない 457 + return false; 458 +} 459 + 460 +LRESULT WndImpl::on_message( UINT msg, WPARAM wp, LPARAM lp ) 461 +{ 462 + // 何もしない 463 + return ime().DefProc( hwnd(), msg, wp, lp ); 464 +} 465 + 466 +bool WndImpl::PreTranslateMessage( MSG* ) 467 +{ 468 + // 何もしない 469 + return false; 470 +} 471 + 472 + 473 + 474 +//========================================================================= 475 + 476 +DlgImpl::DlgImpl( UINT id ) 477 + : rsrcID_( id ) 478 +{ 479 +} 480 + 481 +DlgImpl::~DlgImpl() 482 +{ 483 + // ウインドウを破棄し忘れてたら閉じる 484 + if( hwnd() != NULL ) 485 + End( IDCANCEL ); 486 +} 487 + 488 +void DlgImpl::End( UINT code ) 489 +{ 490 + endCode_ = code; 491 + 492 + if( type() == MODAL ) 493 + ::EndDialog( hwnd(), code ); 494 + else 495 + ::DestroyWindow( hwnd() ); 496 +} 497 + 498 +void DlgImpl::GoModal( HWND parent ) 499 +{ 500 + type_ = MODAL; 501 + ::DialogBoxParam( app().hinst(), MAKEINTRESOURCE(rsrcID_), parent, 502 + (DLGPROC)MainProc, reinterpret_cast<LPARAM>(this) ); 503 +} 504 + 505 +void DlgImpl::GoModeless( HWND parent ) 506 +{ 507 + type_ = MODELESS; 508 + ::CreateDialogParam( app().hinst(), MAKEINTRESOURCE(rsrcID_), parent, 509 + (DLGPROC)MainProc, reinterpret_cast<LPARAM>(this) ); 510 +} 511 + 512 + 513 + 514 +//------------------------------------------------------------------------- 515 + 516 +BOOL CALLBACK DlgImpl::MainProc( 517 + HWND dlg, UINT msg, WPARAM wp, LPARAM lp ) 518 +{ 519 + if( msg == WM_INITDIALOG ) 520 + { 521 + ::SetWindowLongPtr( dlg, GWLP_USERDATA, lp ); 522 + 523 + DlgImpl* ptr = reinterpret_cast<DlgImpl*>(lp); 524 + ptr->SetHwnd( dlg ); 525 + ptr->on_init(); 526 + return FALSE; 527 + } 528 + 529 + DlgImpl* ptr = 530 + reinterpret_cast<DlgImpl*>(::GetWindowLongPtr(dlg,GWLP_USERDATA)); 531 + 532 + if( ptr != NULL ) 533 + switch( msg ) 534 + { 535 + case WM_COMMAND: 536 + switch( LOWORD(wp) ) 537 + { 538 + case IDOK: 539 + if( ptr->on_ok() ) 540 + ptr->End( IDOK ); 541 + return TRUE; 542 + 543 + case IDCANCEL: 544 + if( ptr->on_cancel() ) 545 + ptr->End( IDCANCEL ); 546 + return TRUE; 547 + 548 + default: 549 + return ptr->on_command( HIWORD(wp), LOWORD(wp), 550 + reinterpret_cast<HWND>(lp) ) ? TRUE : FALSE; 551 + } 552 + 553 + case WM_DESTROY: 554 + ptr->on_destroy(); 555 + if( ptr->isMainWnd() ) 556 + ::PostQuitMessage( 0 ); 557 + ptr->SetHwnd(NULL); 558 + break; 559 + 560 + default: 561 + return ptr->on_message( msg, wp, lp ) ? TRUE : FALSE; 562 + } 563 + 564 + return FALSE; 565 +} 566 + 567 + 568 + 569 +//------------------------------------------------------------------------- 570 + 571 +void DlgImpl::on_init() 572 +{ 573 + // 何もしない 574 +} 575 + 576 +void DlgImpl::on_destroy() 577 +{ 578 + // 何もしない 579 +} 580 + 581 +bool DlgImpl::on_ok() 582 +{ 583 + // 何もしない 584 + return true; 585 +} 586 + 587 +bool DlgImpl::on_cancel() 588 +{ 589 + // 何もしない 590 + return true; 591 +} 592 + 593 +bool DlgImpl::on_command( UINT, UINT, HWND ) 594 +{ 595 + // 何もしない 596 + return false; 597 +} 598 + 599 +bool DlgImpl::on_message( UINT, WPARAM, LPARAM ) 600 +{ 601 + // 何もしない 602 + return false; 603 +} 604 + 605 +bool DlgImpl::PreTranslateMessage( MSG* msg ) 606 +{ 607 + // モードレスの時用。ダイアログメッセージ処理。 608 + return (FALSE != ::IsDialogMessage( hwnd(), msg )); 609 +}
Added kilib/window.h version [c9c601b3ae11f0e7]
1 +#ifndef _KILIB_WINDOW_H_ 2 +#define _KILIB_WINDOW_H_ 3 +#include "types.h" 4 +#include "memory.h" 5 +#include "ktlaptr.h" 6 +#ifndef __ccdoc__ 7 +namespace ki { 8 +#endif 9 + 10 + 11 + 12 +// タイムアウト付きMsgBoxの返値 13 +#define IDTIMEOUT 0 14 + 15 + 16 + 17 +//========================================================================= 18 +//@{ @pkg ki.Window //@} 19 +//@{ 20 +// 窓操作用クラス 21 +// 22 +// 外側から、ダイアログやコントロールやプロパティシートや 23 +// 普通のウインドウを全部まとめて共通に扱うためのインターフェイス。 24 +// 実際の実装は、下位クラス XxxImpl で行われている。 25 +//@} 26 +//========================================================================= 27 + 28 +class Window : public Object 29 +{ 30 +public: 31 + 32 + //@{ メインメッセージループ //@} 33 + void MsgLoop(); 34 + 35 + //@{ メッセージを送って処理されるまで待機 //@} 36 + LRESULT SendMsg( UINT msg, WPARAM wp=0, LPARAM lp=0 ); 37 + 38 + //@{ メッセージを送ってすぐ帰る //@} 39 + BOOL PostMsg( UINT msg, WPARAM wp=0, LPARAM lp=0 ); 40 + 41 + //@{ 42 + // 自動消滅機能付きメッセージボックス 43 + // @param msg 表示する文字列 44 + // @param caption ダイアログの題名 45 + // @param type Win32SDKの説明を見てね 46 + //@} 47 + int MsgBox( LPCTSTR msg, LPCTSTR caption=NULL, UINT type=MB_OK ) const; 48 + 49 + //@{ テキスト設定 //@} 50 + void SetText( const TCHAR* str ); 51 + 52 + //@{ 表示 //@} 53 + void ShowUp( int sw=SW_SHOW ); 54 + 55 + //@{ 移動 //@} 56 + void MoveTo( int l, int t, int r, int b ); 57 + 58 + //@{ フォーカス //@} 59 + void SetFocus(); 60 + 61 + //@{ 最前面へGo! //@} 62 + void SetFront(); 63 + 64 + //@{ 画面中央へGo! //@} 65 + void SetCenter(); 66 + 67 +public: 68 + 69 + //@{ ウインドウハンドル //@} 70 + HWND hwnd() const; 71 + 72 + //@{ 位置・サイズ //@} 73 + void getPos( RECT* rc ) const; 74 + 75 + //@{ サイズ //@} 76 + void getClientRect( RECT* rc ) const; 77 + 78 + //@{ メインループを回してるウインドウかどうか //@} 79 + bool isMainWnd() const; 80 + 81 + //@{ 生きてる? //@} 82 + bool isAlive() const; 83 + 84 +public: 85 + 86 + //@{ 未処理メッセージを適当に処理 //@} 87 + static void ProcessMsg(); 88 + 89 + //@{ 最前面へGo! //@} 90 + static void SetFront( HWND hwnd ); 91 + 92 + //@{ 93 + // 画面中央へGo! 94 + // @param hwnd 動かすウインドウ 95 + // @param rel 基準にするウインドウ 96 + //@} 97 + static void SetCenter( HWND hwnd, HWND rel=NULL ); 98 + 99 +protected: 100 + 101 + // 何もしないコンストラクタ 102 + Window(); 103 + 104 + // Hwndをセット 105 + void SetHwnd( HWND wnd ); 106 + 107 + // アクセラレータを通すとかダイアログメッセージの処理とか 108 + virtual bool PreTranslateMessage( MSG* ) = 0; 109 + 110 +private: 111 + 112 + HWND wnd_; 113 + bool isLooping_; 114 + 115 +private: 116 + 117 + NOCOPY(Window); 118 +}; 119 + 120 + 121 + 122 +//------------------------------------------------------------------------- 123 +#ifndef __ccdoc__ 124 + 125 +inline LRESULT Window::SendMsg( UINT msg, WPARAM wp, LPARAM lp ) 126 + { return ::SendMessage( wnd_, msg, wp, lp ); } 127 + 128 +inline BOOL Window::PostMsg( UINT msg, WPARAM wp, LPARAM lp ) 129 + { return ::PostMessage( wnd_, msg, wp, lp ); } 130 + 131 +inline int Window::MsgBox( LPCTSTR m, LPCTSTR c, UINT y ) const 132 + { return ::MessageBox( wnd_, m, c, y ); } 133 + 134 +inline void Window::ShowUp( int sw ) 135 + { ::ShowWindow( wnd_, sw ), ::UpdateWindow( wnd_ ); } 136 + 137 +inline void Window::SetText( const TCHAR* str ) 138 + { ::SetWindowText( wnd_, str ); } 139 + 140 +inline void Window::MoveTo( int l, int t, int r, int b ) 141 + { ::MoveWindow( wnd_, l, t, r-l, b-t, TRUE ); } 142 + 143 +inline void Window::SetFocus() 144 + { ::SetFocus( wnd_ ); } 145 + 146 +inline void Window::SetFront() 147 + { SetFront( wnd_ ); } 148 + 149 +inline void Window::SetCenter() 150 + { SetCenter( wnd_ ); } 151 + 152 +inline HWND Window::hwnd() const 153 + { return wnd_; } 154 + 155 +inline bool Window::isMainWnd() const 156 + { return isLooping_; } 157 + 158 +inline void Window::getPos( RECT* rc ) const 159 + { ::GetWindowRect( wnd_, rc ); } 160 + 161 +inline void Window::getClientRect( RECT* rc ) const 162 + { ::GetClientRect( wnd_, rc ); } 163 + 164 +inline bool Window::isAlive() const 165 + { return FALSE != ::IsWindow( wnd_ ); } 166 + 167 + 168 + 169 +#endif // __ccdoc__ 170 +//========================================================================= 171 +//@{ 172 +// IME制御マネージャ 173 +// 174 +// Global IME をサポートするには、ウインドウメッセージの処理を 175 +// 根本的に入れ替える必要がある。そこで、処理をこのクラスにまとめ 176 +// Windowクラスと連携処理を行うことで、ライブラリの外からは一切 177 +// 気にせず処理をできるようにしておく。なお、Global IMEに対応 178 +// するにはバージョンの新しいPlatform SDKが必要なため 179 +// マクロ USEGLOBALIME が定義されていなければその辺は処理しない。 180 +//@} 181 +//========================================================================= 182 + 183 +class IMEManager 184 +{ 185 +public: 186 + 187 + //@{ フォント指定 //@} 188 + void SetFont( HWND wnd, const LOGFONT& lf ); 189 + 190 + //@{ 位置指定 //@} 191 + void SetPos( HWND wnd, int x, int y ); 192 + 193 + //@{ 確定文字列ゲット。受け取ったら delete すること。 //@} 194 + void GetString( HWND wnd, unicode** str, ulong* len ); 195 + 196 + //@{ GlobalIMEを利用可能状態にする //@} 197 + void EnableGlobalIME( bool enable ); 198 + 199 + //@{ GlobalIMEを使えるWindowのリストを登録 //@} 200 + void FilterWindows( ATOM* lst, UINT siz ); 201 + 202 +private: 203 + 204 + IMEManager(); 205 + ~IMEManager(); 206 + void TranslateMsg( MSG* msg ); 207 + LRESULT DefProc( HWND wnd, UINT msg, WPARAM wp, LPARAM lp ); 208 + void MsgLoopBegin(); 209 + void MsgLoopEnd(); 210 + 211 +private: 212 + 213 + #ifdef USEGLOBALIME 214 + IActiveIMMApp* immApp_; 215 + IActiveIMMMessagePumpOwner* immMsg_; 216 + #endif 217 + static IMEManager* pUniqueInstance_; 218 + 219 +private: 220 + 221 + friend class Window; 222 + friend class WndImpl; 223 + friend void APIENTRY Startup(); 224 + friend inline IMEManager& ime(); 225 + NOCOPY(IMEManager); 226 +}; 227 + 228 + 229 + 230 +//------------------------------------------------------------------------- 231 + 232 +//@{ 唯一のIME管理オブジェクトを返す //@} 233 +inline IMEManager& ime() 234 + { return *IMEManager::pUniqueInstance_; } 235 + 236 + 237 + 238 +//========================================================================= 239 +//@{ 240 +// 普通のウインドウ実装 241 +// 242 +// 派生クラスを定義して、コンストラクタの引数で WndImpl に 243 +// WNDCLASS名やスタイルを渡し、初回なら WNDCLASS を Register 244 +// して、あとは適当なタイミングで Create() という使い方を想定。 245 +// 246 +// HWNDからWndImpl*への変換はx86/x86-64専用のサンクで行っています。 247 +// ので、他のアーキテクチャではこのままでは動作しません。移植 248 +// する場合は、GWL_USERDATA を使うなり clsExtra に入れるなりで 249 +// もう少し汎用性のある方法に適宜変えてください。 250 +//@} 251 +//========================================================================= 252 + 253 +class WndImpl : public Window 254 +{ 255 + enum { THUNK_SIZE = 22 }; 256 + 257 +public: 258 + 259 + //@{ ウインドウ作成 //@} 260 + bool Create( LPCTSTR wndName=NULL, HWND parent=NULL, 261 + int x =CW_USEDEFAULT, int y =CW_USEDEFAULT, 262 + int width =CW_USEDEFAULT, int height =CW_USEDEFAULT, 263 + void* param=NULL ); 264 + 265 + //@{ ウインドウ破棄 //@} 266 + void Destroy(); 267 + 268 +protected: 269 + 270 + //@{ 271 + // コンストラクタ 272 + // @param className ウインドウクラス名 273 + // @param style 標準スタイル 274 + // @param styleEx 標準拡張スタイル 275 + //@} 276 + WndImpl( LPCTSTR className, DWORD style, DWORD styleEx=0 ); 277 + ~WndImpl(); 278 + 279 + //@{ クラス名用の型 //@} 280 + typedef const TCHAR* const ClsName; 281 + 282 + //@{ ウインドウクラス登録 //@} 283 + static ATOM Register( WNDCLASSEX* cls ); 284 + 285 + // てけとーに実装して反応してください。 286 + // on_commandは、処理しなかったらfalseを返すこと。 287 + // on_messageは、処理しなかったらWndImpl::on_messageを呼び出すこと。 288 + // PreTranslateMessageは、処理してもしなくても中で呼び出すこと。 289 + virtual void on_create( CREATESTRUCT* cs ); 290 + virtual void on_destroy(); 291 + virtual bool on_command( UINT id, HWND ctrl ); 292 + virtual LRESULT on_message( UINT msg, WPARAM wp, LPARAM lp ); 293 + virtual bool PreTranslateMessage( MSG* msg ); 294 + 295 +private: 296 + 297 + static LRESULT CALLBACK StartProc( HWND, UINT, WPARAM, LPARAM ); 298 + static LRESULT CALLBACK MainProc( WndImpl*, UINT, WPARAM, LPARAM ); 299 + void SetUpThunk( HWND wnd ); 300 + 301 +private: 302 + 303 + LPCTSTR className_; 304 + const DWORD style_, styleEx_; 305 + byte* thunk_; 306 +}; 307 + 308 + 309 + 310 +//========================================================================= 311 +//@{ 312 +// ダイアログ実装 313 +// 314 +// 派生クラスを定義して、コンストラクタの引数で DlgImpl に 315 +// リソースIDを渡し、後は適当なタイミングで GoModal なり 316 +// Modeless なり、という使い方を想定。 317 +// 318 +// HWNDからDlgImpl*への変換は GWL_USERDATA で行っています。 319 +// ので、それは使わないようにしましょう。 320 +//@} 321 +//========================================================================= 322 + 323 +class DlgImpl : public Window 324 +{ 325 +public: 326 + 327 + enum dlgtype { MODAL, MODELESS }; 328 + 329 + //@{ モーダルで実行 //@} 330 + void GoModal( HWND parent=NULL ); 331 + 332 + //@{ モードレスで作成 //@} 333 + void GoModeless( HWND parent=NULL ); 334 + 335 + //@{ 強制的に終わらせる //@} 336 + void End( UINT code ); 337 + 338 +public: 339 + 340 + //@{ モーダルかモードレスか //@} 341 + dlgtype type() const; 342 + 343 + //@{ 終了コード取得 //@} 344 + UINT endcode() const; 345 + 346 +protected: 347 + 348 + //@{ コンストラクタ //@} 349 + DlgImpl( UINT id ); 350 + ~DlgImpl(); 351 + 352 + //@{ 子アイテムID→HWND変換 //@} 353 + HWND item( UINT id ) const; 354 + 355 + //@{ アイテムに対してメッセージ送信 //@} 356 + LRESULT SendMsgToItem( UINT id, UINT msg, WPARAM wp=0, LPARAM lp=0 ); 357 + 358 + //@{ アイテムに対してメッセージ送信(ポインタ送る版) //@} 359 + LRESULT SendMsgToItem( UINT id, UINT msg, void* lp ); 360 + 361 + //@{ アイテムに対してメッセージ送信(文字列送る版) //@} 362 + LRESULT SendMsgToItem( UINT id, UINT msg, const TCHAR* lp ); 363 + 364 + // てけとーに実装して反応してください。 365 + // on_ok/on_cancelは、終了して良いならtrueを返すこと。 366 + // on_cmd/on_msgは、処理済みならtrueを返すこと。 367 + virtual void on_init(); 368 + virtual void on_destroy(); 369 + virtual bool on_ok(); 370 + virtual bool on_cancel(); 371 + virtual bool on_command( UINT cmd, UINT id, HWND ctrl ); 372 + virtual bool on_message( UINT msg, WPARAM wp, LPARAM lp ); 373 + virtual bool PreTranslateMessage( MSG* msg ); 374 + 375 +private: 376 + 377 + static BOOL CALLBACK MainProc( HWND, UINT, WPARAM, LPARAM ); 378 + 379 +private: 380 + 381 + dlgtype type_; 382 + UINT endCode_; 383 + const UINT rsrcID_; 384 +}; 385 + 386 + 387 + 388 +//------------------------------------------------------------------------- 389 +#ifndef __ccdoc__ 390 + 391 +inline DlgImpl::dlgtype DlgImpl::type() const 392 + { return type_; } 393 + 394 +inline UINT DlgImpl::endcode() const 395 + { return endCode_; } 396 + 397 +inline HWND DlgImpl::item( UINT id ) const 398 + { return ::GetDlgItem( hwnd(), id ); } 399 + 400 +inline LRESULT DlgImpl::SendMsgToItem 401 + ( UINT id, UINT msg, WPARAM wp, LPARAM lp ) 402 + { return ::SendDlgItemMessage( hwnd(), id, msg, wp, lp ); } 403 + 404 +inline LRESULT DlgImpl::SendMsgToItem( UINT id, UINT msg, void* lp ) 405 + { return ::SendDlgItemMessage( hwnd(), id, msg, 0, 406 + reinterpret_cast<LPARAM>(lp) ); } 407 + 408 +inline LRESULT DlgImpl::SendMsgToItem( UINT id, UINT msg, const TCHAR* lp ) 409 + { return ::SendDlgItemMessage( hwnd(), id, msg, 0, 410 + reinterpret_cast<LPARAM>(lp) ); } 411 + 412 + 413 + 414 +//========================================================================= 415 + 416 +#endif // __ccdoc__ 417 +} // namespace ki 418 +#endif // _KILIB_WINDOW_H_
Added kilib/winutil.cpp version [c65458ae7512b751]
1 +#include "stdafx.h" 2 +#include "app.h" 3 +#include "winutil.h" 4 +using namespace ki; 5 + 6 + 7 + 8 +//========================================================================= 9 + 10 +Clipboard::Clipboard( HWND owner, bool read ) 11 + : opened_( false ) 12 +{ 13 + if( ::OpenClipboard(owner) ) 14 + if( read || ::EmptyClipboard() ) 15 + opened_ = true; 16 + else 17 + ::CloseClipboard(); 18 +} 19 + 20 +Clipboard::~Clipboard() 21 +{ 22 + if( opened_ ) 23 + ::CloseClipboard(); 24 +} 25 + 26 +Clipboard::Text Clipboard::GetUnicodeText() const 27 +{ 28 + if( app().isNT() ) 29 + { 30 + // NTなら直接Unicodeでとれる 31 + HANDLE h = GetData( CF_UNICODETEXT ); 32 + if( h != NULL ) 33 + { 34 + unicode* ustr = static_cast<unicode*>( ::GlobalLock( h ) ); 35 + return Text( ustr, Text::GALLOC ); 36 + } 37 + } 38 + else 39 + { 40 + // 9xなら変換が必要 41 + HANDLE h = GetData( CF_TEXT ); 42 + if( h != NULL ) 43 + { 44 + char* cstr = static_cast<char*>( ::GlobalLock( h ) ); 45 + int Lu = ::lstrlenA( cstr ) * 3; 46 + unicode* ustr = new unicode[Lu]; 47 + ::MultiByteToWideChar( CP_ACP, 0, cstr, -1, ustr, Lu ); 48 + ::GlobalUnlock( h ); 49 + return Text( ustr, Text::NEW ); 50 + } 51 + } 52 + 53 + return Text( NULL, Text::NEW ); 54 +}
Added kilib/winutil.h version [882f1cfcdc84a351]
1 +#ifndef _KILIB_WINUTIL_H_ 2 +#define _KILIB_WINUTIL_H_ 3 +#include "types.h" 4 +#include "memory.h" 5 +#include "ktlaptr.h" 6 +#ifndef __ccdoc__ 7 +namespace ki { 8 +#endif 9 + 10 + 11 + 12 +//========================================================================= 13 +//@{ @pkg ki.WinUtil //@} 14 +//@{ 15 +// クリップボード管理 16 +// 17 +// OpenClipboard や CloseClipboard 辺りの呼び出しを適当に自動化します。 18 +//@} 19 +//========================================================================= 20 + 21 +class Clipboard : public Object 22 +{ 23 +public: 24 + 25 + //@{ 開く //@} 26 + Clipboard( HWND owner, bool read=true ); 27 + 28 + //@{ 閉じる //@} 29 + ~Clipboard(); 30 + 31 + //@{ データ読み込み //@} 32 + HANDLE GetData( UINT uFormat ) const; 33 + 34 + //@{ 指定フォーマットのデータがクリップボード上にあるか? //@} 35 + bool IsAvail( UINT uFormat ) const; 36 + 37 + //@{ 指定フォーマットのデータがクリップボード上にあるか?(複数) //@} 38 + bool IsAvail( UINT uFormats[], int num ) const; 39 + 40 + //@{ テキスト情報保持クラス //@} 41 + class Text { 42 + friend class Clipboard; 43 + 44 + mutable unicode* str_; 45 + enum Tp { NEW, GALLOC } mem_; 46 + 47 + Text( unicode* s, Tp m ) : str_(s), mem_(m) {} 48 + void operator=( const Text& ); 49 + 50 + public: 51 + Text( const Text& t ) 52 + : str_(t.str_), mem_(t.mem_) { t.str_=NULL; } 53 + ~Text() 54 + { 55 + if( str_ != NULL ) 56 + if( mem_==NEW ) delete [] str_; 57 + else GlobalUnlock( str_ ); 58 + } 59 + const unicode* data() const { return str_; } 60 + }; 61 + 62 + //@{ テキスト読み込み //@} 63 + Text GetUnicodeText() const; 64 + 65 + //@{ データ書き込み //@} 66 + bool SetData( UINT uFormat, HANDLE hData ); 67 + 68 + //@{ 独自フォーマットの登録 //@} 69 + static UINT RegisterFormat( const TCHAR* name ); 70 + 71 +public: 72 + 73 + //@{ 正常に開かれているかチェック //@} 74 + bool isOpened() const; 75 + 76 +private: 77 + 78 + bool opened_; 79 + 80 +private: 81 + 82 + NOCOPY(Clipboard); 83 +}; 84 + 85 + 86 + 87 +//------------------------------------------------------------------------- 88 + 89 +inline bool Clipboard::isOpened() const 90 + { return opened_; } 91 + 92 +inline HANDLE Clipboard::GetData( UINT uFormat ) const 93 + { return ::GetClipboardData( uFormat ); } 94 + 95 +inline bool Clipboard::SetData( UINT uFormat, HANDLE hData ) 96 + { return NULL != ::SetClipboardData( uFormat, hData ); } 97 + 98 +inline bool Clipboard::IsAvail( UINT uFormat ) const 99 + { return false!=::IsClipboardFormatAvailable(uFormat); } 100 + 101 +inline bool Clipboard::IsAvail( UINT uFormats[], int num ) const 102 + { return -1!=::GetPriorityClipboardFormat(uFormats,num); } 103 + 104 +inline UINT Clipboard::RegisterFormat( const TCHAR* name ) 105 + { return ::RegisterClipboardFormat(name); } 106 + 107 + 108 + 109 +//========================================================================= 110 +//@{ 111 +// 排他制御 112 +// 113 +// 名前付きMutexを扱います 114 +//@} 115 +//========================================================================= 116 + 117 +class Mutex : public Object 118 +{ 119 +public: 120 + Mutex( const TCHAR* name ); 121 + ~Mutex(); 122 + 123 +private: 124 + const HANDLE mtx_; 125 + 126 +private: 127 + NOCOPY(Mutex); 128 +}; 129 + 130 + 131 + 132 +//------------------------------------------------------------------------- 133 + 134 +inline Mutex::Mutex( const TCHAR* name ) 135 + : mtx_( ::CreateMutex( NULL, TRUE, name ) ) {} 136 + 137 +inline Mutex::~Mutex() 138 + { if( mtx_ != NULL ) ::ReleaseMutex( mtx_ ), ::CloseHandle( mtx_ ); } 139 + 140 + 141 + 142 +//========================================================================= 143 + 144 +} // namespace ki 145 +#endif // _KILIB_WINUTIL_H_
Added release/readme.en.txt version [97fc802499438f8f]
1 + 2 + 3 +=<> 4 +=<> GreenPad ver 1.08+ 5 +=<> 2008/07/11 6 + 7 + 8 +<<What's This?>> 9 + 10 + GreenPad is a tiny text editor for Windows. 11 + 12 + It aims to be a handy Notepad replacement with minimal but 13 + complete features, not to be a rich, bloated monsterous 14 + editor. GreenPad supports: 15 + * Unicode 2.0 16 + * Proportional Fonts 17 + * Syntax Highlighting 18 + * Searching with Regular Expressions 19 + while keeping the size of .exe very small (around 50KB!). 20 + 21 + Freeware, distributed under the NYSL licence. 22 + The source code is available at: http://www.kmonos.net/lib/gp.en.html 23 + 24 + 25 +<<What's New in 1.08>> 26 + 27 + * Fixed: Several potential access violations bugs 28 + * Partial support for surrogate pairs (proper rendering and carret moves, 29 + reading/writing UTF-32 and UTF-8 text beyond BMP). 30 + * Changed the tab-order of the Find/Replace dialog. 31 + * Changed the behavior of [Home] and [End] key to be more compatible with NotePad. 32 + 33 +<<Keyboard Shortcuts>> 34 + 35 + Ctrl+R Reopen 36 + Shift+Ctrl+S Save as... 37 + Ctrl+Y Redo 38 + F5 Insert date & time 39 + 40 + Ctrl+F Find 41 + F3 Find next 42 + Shift+F3 Find prev 43 + Ctrl+H Replace 44 + Ctrl+J Jump to line # 45 + Ctrl+G Grep 46 + 47 + Ctrl+1 No Wrapping 48 + Ctrl+2 Wrap by specified width 49 + Ctrl+3 Wrap by the size of window 50 + 51 + Ctrl+Up Curosr Up 3 lines 52 + Ctrl+Dn Curosr Down 3 lines 53 + 54 + and Windows-common shortcuts ( Ctrl+S to save, Ctrl+C to copy, ... ) 55 + 56 + 57 +<<Q&A>> 58 + 59 + * How to change fonts and colors ? 60 + 61 + In the types/ dir, you'll see some .lay files. Please edit them manually. 62 + ========================================================= 63 + ct=Color of Text (RGB) 64 + ck=Color of Keyword 65 + cb=Color of BackGround 66 + cc=Color of ControlCharactor 67 + cn=Color of commeNt 68 + cl=Color of Line no. 69 + ft=FonT name 70 + sz=font SiZe 71 + tb=TaB width 72 + sc=11000 73 + wp=WraP type (-1: no wrap 0: right edge 1: ww chars ) 74 + ww=Wrap Width 75 + ln=show LineNo. 76 + ========================================================= 77 + Year, editing manually, is very inconvinient. 78 + I'll create GUI configurator someday ... 79 + 80 + * How to create syntax hilighting modes? 81 + 82 + Write you own .kwd files and put them into the types/ directory. 83 + The format of .kwd files is as follows: 84 + ========================================================= 85 + 1111 # Four Boolean Flags, 0:false 1:true (explained later) 86 + /* # beginning symbol for block-comments 87 + */ # ending symbol for block-comments 88 + // # beggining symbol for one-line comments 89 + auto # the list of keywords follows... 90 + bool 91 + _Bool 92 + break 93 + case 94 + ... 95 + ========================================================= 96 + The meanings of the four flags are, from left to right: 97 + - CaseSensitive (if set to 1, keywords are treated as case-sensitive.) 98 + - EnableSingleQuotation (if set to 1, keywords inside '...' is not highlighted.) 99 + - EnableDoubleQuoatation (if set to 1, keywords inside "..." is not highlighted.) 100 + - EnableEscapeSequences (if set to 1, "..\".." is teated as a single string.) 101 + Usually, 0111 or 1111 is recommended. 102 + 103 + * Which regular expressions can be used? 104 + 105 + Here is the complete list of the regular expressions available in GreenPad: 106 + ========================================================= 107 + quanitification: 108 + ? : 0 or 1 109 + * : 0 or more 110 + + : 1 or more 111 + 112 + alternation: 113 + a|b 114 + 115 + grouping(parentheses) 116 + 117 + special escape characters: 118 + \t : tab 119 + \\ : '\' itself 120 + \[ : '[' 121 + 122 + positional match: 123 + ^ : start of line 124 + $ : end of line 125 + 126 + character classes: 127 + [abc] : matches a single character 'a', 'b', or 'c' 128 + [^abc] : matches any single character other than 'a', 'b', or 'c' 129 + [d-h] : matches 'd', 'e', 'f', 'g', 'h' 130 + \w : [0-9a-zA-Z_] 131 + \W : [^0-9a-zA-Z_] 132 + \d : [0-9] 133 + \D : [^0-9] 134 + \s : [\t ] 135 + \S : [^\t ] 136 + ========================================================= 137 + There are some limitations: 138 + * GreenPad does searching line by line, thus 139 + you cannot search "aaa\nbbb" or something like it. 140 + * No forward/backward references. 141 + * No shortest matches (every * is greedy) 142 + 143 + * External Grep Program ? 144 + 145 + You can enter some GUI grep program here. For example, 146 + C:\Software\Gj\GrepJuice.exe "%D" 147 + is set in my environment. 148 + %D is automatically replaced by the current directory 149 + %F is replaced with the full path of the current file. 150 + %N is replaced with the name (without path info) of the current file. 151 + 152 + * Command Line Options ? 153 + 154 + greenpad ([-l LineNumber] [-c CharacterSet] filename)* 155 + 156 + For example: 157 + greenpad -l543 -c932 aaaa.txt 158 + opens a file named "aaaa.txt" assuming the Shift_JIS encoding, 159 + and brings its 543rd line to the view area. CharacterSet number 160 + supported by default is: 161 + iso-8859-1 = -1 162 + UTF5 = -2 163 + UTF8 = -65001 164 + UTF16BE = -5 165 + UTF16LE = -6 166 + UTF32BE = -9 167 + UTF32LE = -10 168 + If you have installed "Language Support" for your Windows, 169 + the character sets of installed languages become 170 + readable/writable in GreenPad. You should consult with 171 + the "area and language option" control panel to get the 172 + CharacterSet numbet for those languages. Note however that 173 + for some east asian encodings, special CharacterSet numbers 174 + are assigned for a technical reason. 175 + EUC-JP = -932 176 + iso-2022-jp = -933 177 + iso-2022-kr = -950 178 + iso-2022-cn = -936 179 + GB2312 = -937 180 + 181 + * How to share GreenPad's configurations between users of same machine? 182 + 183 + Usually, GreenPad saves and loads its configuration for each 184 + machine user account. However, sometimes you want to use only one 185 + setting for one GreenPad.exe. (for example, when you have GreenPad 186 + in an emergency floppy disk and log in different users accounts.) 187 + 188 + In this case, you should add the following two lines to GreenPad.ini 189 + file: 190 + [SharedConfig] 191 + Enable=1 192 + then GreenPad will be executed in user-independent-settings-mode. 193 + 194 + 195 +<<Acknowledgements>> 196 + 197 + * The icon image of GreenPad is the work of 198 + SB( http://homepage3.nifty.com/scriba/ ). Thanks. 199 + 200 + 201 +<<License>> 202 + 203 + NYSL Version 0.9982 http://www.kmonos.net/nysl/ 204 + 205 + A. This software is "Everyone'sWare". It means: 206 + Anybody who has this software can use it as if you're 207 + the author. 208 + 209 + A-1. Freeware. No fee is required. 210 + A-2. You can freely redistribute this software. 211 + A-3. You can freely modify this software. And the source 212 + may be used in any software with no limitation. 213 + A-4. When you release a modified version to public, you 214 + must publish it with your name. 215 + 216 + B. The author is not responsible for any kind of damages or loss 217 + while using or misusing this software, which is distributed 218 + "AS IS". No warranty of any kind is expressed or implied. 219 + You use AT YOUR OWN RISK. 220 + 221 + C. Copyrighted to k.inaba. 222 + 223 + D. Above three clauses are applied both to source and binary 224 + form of this software. 225 + 226 + 227 +--------------------------------------------------------------------------- 228 + by k.inaba( http://www.kmonos.net/ )
Added release/readme.txt version [70e72f2bca2bf1ca]
1 + 2 +=<> 3 +=<> GreenPad ver 1.08+ 4 +=<> 2008/07/11 5 + 6 + 7 +<<これは何?>> 8 + 9 + Windows上で動作する、テキストエディタです。 10 + なんでもできる高機能エディタではなく、メモ帳の代わりとして 11 + 使えるような、最低限の機能は備えつつ高速に動作する簡易テキ 12 + ストエディタを目指して開発されています。 13 + 14 + NYSLライセンスに従うフリーウェアです。ソースコードが 15 + http://www.kmonos.net/lib/gp.html 16 + で公開されています。 17 + 18 + 最新版での更新内容は、 19 + ・S版で「開く」「保存」ダイアログが出なくなっていたバグ修正 20 + ・タイトルバーをクリックしたときシステムメニューが出ないバグ修正 21 + ・環境によってステータスバーにカーソル位置表示が出ないバグ修正 22 + です。 23 + 24 + 25 +<<1.08+ での更新内容>> 26 + 27 + * A版が起動しなくなっていたバグを修正 28 + (U版には変更ありません) 29 + 30 + 31 +<<1.08 での主な更新内容>> 32 + 33 + * メモリアクセス違反で強制終了するバグを何カ所か修正 34 + * サロゲートペアに少し対応(描画やカーソル移動でサロゲートペアを分解しないようになった 35 + && UTF-32 と UTF-8 ファイルのBMP外文字の読み書きに対応) 36 + 注: BMP外の文字は、対応するフォント(XANO明朝 等)を指定した時のみ描画されます。 37 + * 検索/置換ダイアログのタブ順変更 38 + * Home/End キーを論理行ではなく表示行単位の動作に変更 39 + 40 + 41 +<<特徴>> 42 + 43 + ・内部処理はUnicode 44 + ・プロポーショナルフォントが使える 45 + ・キーワード色分けが出来る 46 + ・文字コードはいわゆる SJIS, EUC, JIS, UTF8, UTF7, UTF16 などの 47 + 他にも、Windowsがサポートしていればそれに合わせて色々対応 48 + ・改行コードは CRLF/CR/LF に対応 49 + ・出来る限りの無限Undo可能 50 + ・ショボめの正規表現検索機能内蔵 51 + ・exeのサイズがわりと小さい 52 + ・選択時に行と行の間に隙間が見えるのは作者の趣味 53 + 54 + 55 +<<使い方>> 56 + 57 + 基本的な使い方は、Windowsの標準的なテキスト編集方法と 58 + 同じです。適当に勢いで使ってください。 59 + 60 + Windowsの一般的なものではないかもしれないキーボード 61 + ショートカットは次の通りです。 62 + | 63 + | Ctrl+R 開き直す 64 + | Shift+Ctrl+S 別名保存 65 + | 66 + | Ctrl+Y Redo 67 + | F5 日時の挿入 68 + | 69 + | Ctrl+F 検索 70 + | Ctrl+H 置換 71 + | Ctrl+J ジャンプ 72 + | F3 次を検索 73 + | Shift+F3 前を検索 74 + | Ctrl+G Grep 75 + | 76 + | Ctrl+1 折り返しなし 77 + | Ctrl+2 指定幅折り返し 78 + | Ctrl+3 右端折り返し 79 + | 80 + | Ctrl+↑ 3行単位でカーソル移動 81 + | Ctrl+↓ 3行単位でカーソル移動 82 + | 83 + | Shift+変換 選択範囲を再変換 84 + | Ctrl+BS 確定取消 85 + 86 + 検索には正規表現がちょびっと使えます。 87 + 対応している正規表現は以下のとおりです。 88 + | 89 + | c 普通の字は、その文字自身を意味する 90 + | \t タブ文字 91 + | \w [0-9a-zA-Z_] と同義。英数字 92 + | \W [^0-9a-zA-Z_] と同義。英数字以外 93 + | \d [0-9] と同義。数字 94 + | \D [^0-9] と同義。数字以外 95 + | \s [\t ] と同義。空白文字 96 + | \S [^\t ] と同義。空白文字以外 97 + | \その他 \\ なら \、\[ なら [ という一文字 98 + | ^ 行の先頭 99 + | $ 行の末尾 100 + | . 任意の一文字 101 + | [...] [] 内に含まれる任意の1文字。A-Z や あ-ん のような範囲指定も可。 102 + | [^...] [] 内に含まれない任意の1文字。範囲指定も可。 103 + | 104 + | r* 正規表現 r を0回以上繰返したもの 105 + | r+ 正規表現 r を1回以上繰返したもの 106 + | r? 正規表現 r の0回または1回 107 + | r1r2 正規表現 r1 に続いて r2 が現れることを表す 108 + | r1|r2 正規表現 r1 または r2 を表す 109 + | (r) 正規表現 r を表す. 110 + | 111 + | 例 112 + | 第[1-9]号 "第1号"とか"第2号"とかにマッチ 113 + | <[^>]+> XMLのタグとかにマッチ 114 + | (。|!|?)$ 行末の。か!か?にマッチ 115 + | 116 + | 前方参照とか最短一致とか置換に\1とかそういったことは、 117 + | 残念ながら一切できません。改行を挟んだ検索などもでき 118 + | ません。ゴメンナサイ。 119 + 120 + 121 +<<Q&A>> 122 + 123 + ・どうやってフォントとかを変えればよいの? 124 + | 下のほうの*.kwdや*.layの書式に従って、設定ファイルを編集してください。 125 + | 機会があったら設定変更画面も用意しますので…スミマセン 126 + 127 + ・Unicode対応なはずなのに日本語以外の字が表示できないよ? 128 + | 対応するフォントが必要です。Unicode 2.0をフルに 129 + | 使えるフォントとしては MS Office 付属の "Arial Unicode" や、 130 + | "BDF UM+" ( http://www.kaoriya.net/#FONT ) など。 131 + | メニューの「文書タイプ」>「UnicodeText」を選ぶと、 132 + | Arial Unicode を使ってテキストを表示します。その他のUnicodeフォントは、 133 + | GreenPad フォルダの types\unicode.lay を書き換えるなどしてご利用下さい。 134 + 135 + ・右から左に書くタイプの言語がうまく表示できない。 136 + | ごめんなさいGreenPadでは無理です。 137 + 138 + ・設定の「外部Grepプログラム」欄には何を入れればよいのでしょう? 139 + | "Grep"用のプログラムがインストールされていると、ここに 140 + | 入力しておくことでGreenPadから起動できます。例として私の環境では 141 + | C:\Software\Getia\getia.exe "%D" 142 + | となっています。外部ツールの起動時に、 143 + | %D は「現在開いているファイルのあるフォルダ」 144 + | %F は「現在開いているファイルのフルパス名」 145 + | %N は「現在開いているファイルの名前部分」 146 + | に置き換わります。ちなみに作者のおすすめGrepプログラムは 147 + | getia (http://site-clue.statice.jp/soft_getia.php) 148 + | です。 149 + 150 + ・コマンドラインオプションは? 151 + | -l : 行番号指定 152 + | -c : 文字コード指定 153 + | の2つがあります。 154 + | 155 + | greenpad -l543 -c932 aaaa.txt 156 + | で、強制的にShiftJISで、aaaa.txtを開き、 157 + | 543行目を一番上にした状態で起動します。 158 + | 159 + | greenpad aaaa.txt -l543 -c932 160 + | ではダメです。オプションはファイル名より前に。 161 + | 162 + | greenpad -l123 aaaa.txt -l456 bbbb.txt 163 + | とやって2つのファイルを開くことは可能 164 + | 165 + | -cの後ろの数字は、下にあげる"文字コード番号"を指定します。 166 + 167 + ・文字コード番号? 168 + | WinXPならコントロールパネルの 169 + | 「言語と地域のオプション」の「詳細設定」の「コードページ 170 + | 変換テーブル」の数字を指定するとだいたい上手く行くと思います。 171 + | ただし、一部のコードにはGreenPad内で特別に負の数を割り振って 172 + | いますので、以下の値を使ってください。 173 + | 174 + | SJIS = 932, // 日本語1 (Shift_JIS) 175 + | EucJP = -932, // 日本語2 (日本語EUC) 176 + | IsoJP = -933, // 日本語3 (ISO-2022-JP) 177 + | 178 + | Western = -1, // 欧米 (Windows1252 >> ISO-8859-1) 179 + | IsoKR = -950, // 韓国語2 (ISO-2022-KR) 180 + | IsoCN = -936, // 中国語2 (簡体字 ISO-2022-CN) 181 + | HZ = -937, // 中国語3 (簡体字 HZ-GB2312) 182 + | UTF5 = -2, // Unicode (UTF-5) : BOM無し 183 + | UTF8 =-65001,// Unicode (UTF-8) : BOM有り 184 + | UTF16b = -3, // Unicode (UTF-16) : BOM有り BE 185 + | UTF16l = -4, // Unicode (UTF-16) : BOM有り LE 186 + | UTF16BE = -5, // Unicode (UTF-16BE): BOM無し 187 + | UTF16LE = -6, // Unicode (UTF-16LE): BOM無し 188 + | UTF32b = -7, // Unicode (UTF-32) : BOM有り BE 189 + | UTF32l = -8, // Unicode (UTF-32) : BOM有り LE 190 + | UTF32BE = -9, // Unicode (UTF-32BE): BOM無し 191 + | UTF32LE = -10, // Unicode (UTF-32LE): BOM無し 192 + 193 + ・キーワードファイル (*.kwd) の書き方は? 194 + | 195 + | UCS-2をLittleEndianでベタ書きしたファイルでなければならない。 196 + | 改行コードはなんでもいいけど LF にすると若干高速に読めるかも。 197 + | BOMはあってもなくても可。つけておくことを推奨。 198 + | 199 + | 1行目: flag ========================== 200 + | 201 + | 0 or 1 が4つ並ぶ。順に、1ならば 202 + | ・ キーワードは大文字小文字を区別 203 + | ・ '' の中ではコメント記号は無効 204 + | ・ "" の中ではコメント記号は無効 205 + | ・ \ 記号によるエスケープを行う 206 + | を意味する。 207 + | 208 + | 2行目: ブロックコメント開始記号 ====== 209 + | 210 + | /* とかそんな風に書く。 211 + | ブロックコメントを使わないなら空行にしておく。 212 + | 213 + | 3行目: ブロックコメント終了記号 ====== 214 + | 215 + | */ とかそんな風に書く。 216 + | ブロックコメントを使わないなら空行にしておく。 217 + | 218 + | 4行目: 行コメント開始記号 ============ 219 + | 220 + | // とかそんな風に書く。 221 + | 行コメントを使わないなら空行にしておく。 222 + | 223 + | 5行目以降: キーワード ================ 224 + | 225 + | 強調表示したい単語をひたすら書き連ねる 226 + | 227 + | ※ キーワードとして使えるのは、 228 + | ※ 数字、アルファベット(大小)、下線 229 + | ※ からなる単語のみ。border-width とか #include とかはダメ。 230 + | ※ __int64 などは可。 231 + | 232 + | ※ コメント記号としては、 233 + | ※ キーワードに使える文字・空白文字 234 + | ※ を除いたASCII文字のみが使える。 begin とかはダメ。 235 + 236 + ・レイアウトファイル (*.lay) の書き方は? 237 + | UCS-2をLittleEndianでベタ書きしたファイルでなければならない。 238 + | 任意の文字コードを使えるように変更することもすぐに可能なので、 239 + | 気が向いたら変えるかもしれない。ので、BOMはつけておくことを推奨。 240 + | 241 + | ct=文字色 242 + | ck=キーワード色 243 + | cb=背景色 244 + | cc=コメント色 245 + | cn=EOFや改行マークの色 246 + | cl=行番号の色 247 + | ft=フォント名 248 + | sz=フォントサイズ 249 + | tb=タブ幅 250 + | sc=特殊文字を表示するなら1(左から順に、EOF,改行,タブ,半角空白,全角空白) 251 + | wp=折り返し方式(-1:無し 0:右端 1:指定文字数) 252 + | ww=折り返し文字数(wp=1の時に利用) 253 + | ln=行番号表示(1:ON 0:OFF) 254 + | 255 + | 項目を省略すると、その項目に関しては default.lay の 256 + | 内容が読み込まれる。default.lay も無いときは exe 内に 257 + | 内蔵してあるデフォルトの設定が読み込まれる。 258 + 259 + ・初期設定ファイル (*.ini) の書き方は? 260 + | 設定ダイアログで設定するとここに書き込まれます。 261 + | Windowsのごく普通のINIファイル。ANSI-CP (日本ならShift_JIS)+CRLF で 262 + | 書かねばならない。例として、次のような感じになる。 263 + | 264 + | ------------------------------------------------------------------ 265 + | [ユーザー名] 266 + | UndoLimit= // アンドゥ回数制限。-1 なら制限無し 267 + | TxtFilter= // [開く]ダイアログ用のフィルタ。*.xxx の形で、; で区切ること 268 + | OpenSame= // 同じウインドウで開くなら1、でなければ0。 269 + | CountUni= // 俗に言う半角全角を区別せず、横の桁数を数える 270 + | GrepExe= // Grep用に使う外部アプリ起動のコマンドを入れる。 271 + | // %1があればそこをカレントフォルダ名に置き換える。 272 + | MRU= // [最近開いたファイル] に表示する個数。最大8個 273 + | MRU#= // [最近開いたファイル] を保存 274 + | SearchIgnoreCase= // 検索の時大文字小文字の違いを無視するかどうか 275 + | SearchRegExp= // 正規表現検索するかどうか 276 + | NewfileCharset= // 新規作成したファイルの文字コード 277 + | NewfileLB= // 新規作成したファイルの改行コード 278 + | NewfileDoctype= // 新規作成したファイルの文書タイプ 279 + | RememberWindowSize= // ウインドウサイズを再開時に再現するなら1 280 + | RememberWindowPos= // ウインドウ位置を再開時に再現するなら1 281 + | WndX= 282 + | WndY= 283 + | WndW= 284 + | WndH= 285 + | WndM= // 記憶されたウインドウサイズや位置 286 + | 287 + | [DocType] 288 + | 1= 289 + | 2= // 文書タイプの名前を列挙。連番なら幾つまで並べてもOK 290 + | 291 + | [文書タイプ名] 292 + | Pattern= // この文書タイプを自動適用するファイル名を正規表現で 293 + | // (ファイル名全体にマッチするように) 294 + | Keyword= // キーワードファイルの名前 295 + | Layout= // レイアウトファイルの名前 296 + | ------------------------------------------------------------------ 297 + | 298 + | ユーザーごとに設定を変えたりしたくない場合は、次のように、 299 + | SharedConfigというセクションと、Enable=1 という行を書いておく。 300 + | 301 + | ------------------------------------------------------------------ 302 + | [SharedConfig] 303 + | Enable=1 304 + | ------------------------------------------------------------------ 305 + | 306 + | こうすると、設定項目はすべてこのSharedConfigセクションから読み書き 307 + | されるようになる。設定済みGreenPadをiniと合わせて色々な環境へ 308 + | 持ち運びたいときに便利。 309 + 310 + 311 +<<謝辞>> 312 + 313 + ・アイコンはSB氏 ( http://homepage3.nifty.com/scriba/ ) に 314 + 制作していただきました。感謝。 315 + 316 + 317 +<<更新履歴>> 318 + 319 + 2008/04/29 【ver 1.08】 320 + ・再変換しようとすると強制終了するバグを修正 321 + 2008/04/17 322 + ・U版ではメモリ管理をWindowsに完全に任せるように変更 323 + ・検索文字列が「見つかりませんでした」ダイアログをモーダルにしました 324 + 2008/04/05 【ver 1.08 beta】 325 + ・強制終了するバグをいくつか修正 326 + ・BMP外の文字(サロゲートペアで表現される文字)にごまかしごまかし対応 327 + ・新たに、UTF-32 の読み書き、Win95 での UTF-8 の読み書きでBMP外の文字をサポート 328 + ・カーソル移動がちゃんとサロゲートペアを1文字として扱うようにしました 329 + ・描画時の文字幅もちゃんとなったはず 330 + ・検索ダイアログのタブ移動順を変更 331 + ・Home/End キーでは物理行ではなく表示行単位の移動としました 332 + 2006/12/04 【ver 1.07.4】 333 + ・ISO-8859-1 が標準文字コードの環境で、保存時にファイルが消える致命的なバグ修正 334 + 2006/11/30 335 + ・Win95で動作するように修正 336 + 2006/11/25 【ver 1.07.3】 337 + ・英語版で Save As... メニューのショートカットが変だったのを修正 338 + ・時々文字が描画されないことがある問題に対処 339 + 2006/11/22 【ver 1.07.2】 340 + ・Win98 でウインドウ位置やサイズを保存できてなかったバグ修正 341 + 2006/11/17 【ver 1.07.1】 342 + ・16x16 のアイコンを入れるようにした 343 + ・コンパイル/リンクオプション調整 344 + 2006/11/13 345 + ・デフォルト設定の、Javaモード判定用正規表現が間違ってたので修正 346 + ・内部文字列バッファはWORD整列してメモリ確保するよう修正 347 + 2006/11/09 【ver 1.07】 348 + ・Undoと文字入力の組み合わせによって、保存ができないタイミングがあったバグ修正 349 + ・バージョン情報の「ファイル名」を「GreenPad」に変更 350 + ・スクロールバーの右クリックのメニューの"最上部"、"最下部"が動くように修正 351 + ・正規表現検索でスタック食いつぶして落ちることはないように修正 352 + ・外部Grep起動コマンドに %D(ディレクトリ名), %F(フルパス), %N(ファイル名) 353 + を使えるようにした。従来の%1(ディレクトリ名)も互換性のために残してあります。 354 + ・改行がないファイルの保存時改行コードは、新規ファイルの場合にそろえるように修正 355 + ・中国語/韓国語環境では、EUC-JPの自動判定を行わないようにした(GBやUHCの誤判定防止) 356 + ・添付予約語ファイルをいくつか追加 357 + 2005/11/27 【ver 1.06.2】 358 + ・キリル語、ギリシャ語、中央ヨーロッパ語として使うコードページを修正 359 + ・日韓中以外の言語環境でも、ANSIコードページをデフォルトとして使うように変更 360 + 2005/10/23 【ver 1.06.1】 361 + ・S版で「開く」「保存」ダイアログが出なくなっていたバグ修正 362 + ・タイトルバーをクリックしたときシステムメニューが出ないバグ修正 363 + ・環境によってステータスバーにカーソル位置表示が出ないバグ修正 364 + 2005/10/21 365 + ・S版で、外部Grepを呼び出せなくなっていたバグ修正 366 + 2005/10/20 【ver 1.06】 367 + ・前回終了時のウインドウの位置とサイズを復元する機能を追加 368 + ・d.kwdを最新の言語仕様に追従。その他kwdファイルの整理 369 + 2005/10/18 370 + ・新規ファイルのデフォルト文字コードや文書タイプの設定を追加 371 + ・iniファイルに、ユーザ毎に設定を分けないSharedConfigモード追加 372 + ・Windows x64 版対応 373 + ・MinGW でリソース以外はコンパイル可能にした 374 + ・DigitalMars C++ でちゃんとコンパイル可能にした 375 + 2005/05/26 376 + ・HALさんのdelphi/asm/b2e用kwdを添付。 377 + 2005/03/11 378 + ・U版でファイルの保存時に、指定より一個親のフォルダに 379 + 保存してしまうことがあったバグを修正。 380 + 2004/07/29 【ver 1.05】 381 + ・Windows XP SP2 の Execution Protection 下でも実行できるように修正したつもり。 382 + ・開いているファイルのあるディレクトリを外から削除できるように修正。 383 + ・日本語/英語以外のファイル名も「最近のファイル」で扱えるようにした。 384 + 2004/06/20 385 + ・全置換をUndoする際にも↓と同じ問題が残っていたので修正。 386 + ・HALさんによるdelphi用のkwd/layを添付。 387 + 2004/06/13 388 + ・改行を削除して複数行を繋げた際に行番号表示がおかしくなるバグ修正 389 + ・[開く]や[保存]ダイアログで文字コード関係のボックスにTABキーで移動可能にした。 390 + ・全置換の際にカーソル位置の更新をステータスバーに毎回反映してて 391 + 遅かったバグを修正(つまり、ステータスバーの更新頻度を下げた。) 392 + 2003/09/27 393 + ・カーソル上下移動時の右寄せを左寄せに変えた 394 + 2003/05/13 【ver 1.04.2】 395 + ・関係ないメニューでステータスバーON/OFFしてしまうバグ修正…(^^;; 396 + 2003/05/09 【ver 1.04】 397 + ・ファイル履歴最大を20件にしたつもりが7件だったバグ修正。 398 + ・横位置を文字数で表示モードでない場合、TABの扱いが不自然だったバグ修正。 399 + ・ステータスバーON/OFF 400 + ・WM_COPY, WM_CUT, WM_PASTE, WM_UNDO, EM_UNDO, EM_CANUNDO, EM_SETREADONLY 401 + に反応するようにしたつもり。肝心なGETSEL/SETSEL系はチト面倒いので後回し。 402 + 2003/02/10 403 + ・BDF UM+ ( http://www.kaoriya.net/#FONT ) というフォントがあるそうです。 404 + 2003/02/08 【ver 1.03】 405 + ・ファイル履歴が2件までしか記録出来なくなってたバグ修正。 406 + ・Arial Unicode が自由にダウンロードできなくなったらしいので、 407 + Unicodeモードのフォントを Bitstream Cyberbit に変えようとしたところ、 408 + こちらも有料になってしまったらしい。他にフリーのUnicode2.0フルの 409 + フォントなんて知らないよー。(T_T) 410 + 2003/01/21 411 + ・UTF-8判別ルーチンの強化 412 + 2003/01/18 413 + ・TAB幅調整 414 + ( これ↓のWin2k以前の仕様に対処する方法が思いつかない。。。 ) 415 + ( http://www.microsoft.com/japan/msdn/windows/windowsxp/FixedPitchFont.asp ) 416 + 2002/12/21 417 + ・検索ダイアログ開きっぱなしモード(改) 418 + 2002/12/14 【ver 1.02】 419 + ・検索ダイアログ開きっぱなしモード 420 + ・検索ダイアログの設定保存 421 + ・選択中文字列を検索ダイアログへ反映 422 + ・選択範囲再変換機能搭載 423 + 2002/12/09 424 + ・英語版ReadMeを書いてみた。 425 + 2002/12/08 426 + ・設定項目の中に両端に""がある文字列を正しく保存出来ないバグ修正 427 + ・GreenPad.iniを開くとGreenPad.iniの末尾にゴミがくっつくことがある問題修正 428 + >読み込みオープン中のファイルをWritePrivateXXXで弄るとマズかったみたい。 429 + ・行番号色変更を可能にした。 430 + ・外部Grepの起動フォルダが正しくないことがあったバグ修正 431 + 2002/09/22 【ver 1.01】 432 + ・Win95で通常の検索が出来ないバグ修正 433 + ・アイコン変更 434 + ・C++の文書タイプ用パターンの修正 435 + ・perl/php/css用のキーワードファイルを標準添付 436 + 2002/07/26 【ver 1.00】 437 + ・文字数カウントをSJISでのバイト数でも行えるように。 438 + 2002/07/20 439 + ・WinNT4でも実行時に変化するメニュー項目が壊滅してたのを修正。 440 + 2002/07/17 441 + ・Win95で、実行時に変化するメニュー項目が全滅してたのを修正。 442 + ・Win95で、UTF-8の読み書き、UTF-7の書きが出来なくなってたのを修正。 443 + 2002/07/15 444 + ・Win9x系で全くファイルを開けなくなってたのを修正 445 + 2002/07/14 446 + ・排他処理をゆるくした 447 + ・[最近のファイル] メニューをようやく実装 448 + 2002/07/11 449 + ・「同じウィンドウで開く」実装 450 + ・ステータスバーに改行コードを表示するようにした 451 + 2002/07/09 452 + ・正規表現の\wと\Wが逆だったのを修正 453 + ・Win9xでのコピー&ペーストが致命的にバグってたのを修正 454 + ・メニューのチェック表示をラジオボタン的に 455 + ・GreenPad.iniの改行コードがCRのみになっちゃうバグ修正 456 + 2002/07/06 457 + ・設定ダイアログ完成。 458 + ・RC1に向け色々整備開始。 459 + 2002/07/02 460 + ・文書タイプ部分の設定ダイアログとかiniへの保存とか。 461 + 2002/07/01 462 + ・設定ダイアログの共通項目保存部分完成。あとは文書タイプ。 463 + 2002/06/30 464 + ・設定ダイアログ作り始め 465 + ・外部grep呼び出し機能追加。 466 + 2002/06/29 467 + ・英語版リソース追加 468 + 2002/06/24 469 + ・行頭を表す正規表現^が正しく働いてなかったので修正 470 + 2002/06/19 471 + ・layout変更の際にカーソルサイズを変更してなかったバグ修正 472 + 2002/06/17 473 + ・Ctrl+Tab / Ctrl+Shift+Tab に対応 474 + ・ステータスバーにカーソル座標を表示するようにした 475 + 2002/06/05 476 + ・正規表現検索の方も完成。 477 + 2002/06/04 478 + ・文書タイプ選択でのRegExp利用版を完成させる。 479 + 2002/06/03 480 + ・正規表現のマッチングルーチン暫定版完成。 481 + 2002/06/01 482 + ・「見つかりませんでした」を出すようにした。 483 + ・上書き保存時に文書タイプが戻ってしまうバグ修正 484 + ・文書タイプメニューのチェックマーク位置が正しくなるように修正 485 + ・タイプ選択ルーチンを暫定的に拡張子マッチングにしてみた。 486 + 2002/05/23 487 + ・検索メニューがグレーアウトしてたバグ修正 488 + ・置換機能実装。 489 + ・全置換も実装。あとは、見つからなかったときのメッセージを出すとかやらないと。 490 + 2002/05/21 491 + ・単純な前後検索(CaseIgnoreも可)は実装できた。 492 + [前を検索]などのUIはも少し考える必要がありそうだ。 493 + 2002/05/18 494 + ・[検索]用のフレーム作成。単純検索は、あとはカーソルとの連携のみ。 495 + ・この版からCVSを導入してみた。 496 + ・Gp本体部分のccdoc用ソースコメントもpkg化。 497 + 2002/05/06 498 + ・[開く][保存] ダイアログの初期ディレクトリが変だったので修正 499 + ・[表示>文書タイプ] メニュー 500 + 2002/05/05 501 + ・[開く]メニューまわりのソースの再構成。少しすっきりした。 502 + ・開き直す、の時は文書タイプの読み直しを行わないようにした。 503 + ・Undoに回数制限をかけたときのdirty flagの動作が変だったので修正 504 + ・8.3形式で渡されても名前部分だけは内部でLFNに変換するようにした。 505 + ・MLU以外の項目を全てiniから読み出すようにした。ただし Pattern は 506 + まだ読み出すだけで使っていない。ここには正規表現を使いたいので。 507 + ・テスト用にb2e.kwdとini.kwdを作ってみたりする。 508 + 2002/05/04 509 + ・grep。-l オプションにて、 510 + PGrep( http://osaka.cool.ne.jp/parasa/ ) 511 + JGREP( http://www.hi-ho.ne.jp/jun_miura/jgrep.htm ) 512 + GrepJuice( http://hp.vector.co.jp/authors/VA016609/ ) 513 + の外部ビューワとして利用できることを確認。 514 + ・名前を付けて保存、のタイミングで文書タイプのReloadを行うようにした 515 + ・DigitalMars の smake 用の makefile をまともなものに書き直し 516 + 2002/05/03 517 + ・*.iniファイルの項目決定&読み込みルーチン作成 518 + ・検索とかのダイアログだけ作ってみた 519 + ・Insertキーに反応するようにした。 520 + ・Ctrl+BackSpace で確定取り消し…というのをIMEが勝手に 521 + やってくれるらしい。面白い。(^^) 522 + ・-l## オプション(開くときに指定行番号へジャンプ)実装 523 + ・ついでに行番号ジャンプダイアログも実装 524 + ・F5で日時挿入機能実装 525 + 2002/04/28 526 + ・*.layファイルのフォーマット決定&読み込みルーチン作成 527 + ・c.kwd と html.kwd を書き直し 528 + ・ソースにVC.NET用のプロジェクトファイルを追加 529 + こっちの方がexeのサイズが小さくなることが判明。(^^; 530 + 2002/04/27 531 + ・4バイト以下のファイルを自動判定で読むとバグるのを修正 532 + ・未保存を表す * の表示制御を適切に行うようにした。 533 + ・文書タイプ別設定のフレームワークづくり 534 + ・折り返し方法切り替えのメニューとかつけてみた 535 + ・ウインドウへファイルをD&Dしたら開くようにした 536 + 2002/04/25 537 + ・BM法による検索ルーチンを作ったけど取り込んでない。 538 + 2002/04/24: 539 + ・[開く][保存]ダイアログにデフォルトで現在のファイル名が表示されるよーに。 540 + ・[開く][保存]ダイアログに「テキスト形式のファイル」って項目を。 541 + ・新規作成した時点では[保存]できなくなってたバグ修正。 542 + 2002/04/23 543 + ・[ファイル][編集] メニューのグレーアウト制御 544 + ・未保存ファイルを破棄しようとしてるときの問い合わせ処理全般 545 + ・ダブルクリックで単語選択 546 + ・Undo/Redoの回数制限機能 547 + 2002/04/22 548 + ・簡易クリップボード制御ライブラリをGpに統合 549 + ・Undo/Redo (回数無制限) 550 + ・ファイル保存時のメモリ確保に関する致命的バグ修正 551 + ・単語が消える問題に、二重TextOutによる応急処置 552 + 2001/08/05 - 2002/04/21 553 + ・(記録が残っていません。残念。) 554 + 2001/08/04 555 + ・開発スタート 556 + 557 + 558 +<<ライセンス>> 559 + 560 + NYSL Version 0.9982 http://www.kmonos.net/nysl/ 561 + 562 + A. 本ソフトウェアは Everyone'sWare です。このソフトを手にした一人一人が、 563 + ご自分の作ったものを扱うのと同じように、自由に利用することが出来ます。 564 + 565 + A-1. フリーウェアです。作者からは使用料等を要求しません。 566 + A-2. 有料無料や媒体の如何を問わず、自由に転載・再配布できます。 567 + A-3. いかなる種類の 改変・他プログラムでの利用 を行っても構いません。 568 + A-4. 変更したものや部分的に使用したものは、あなたのものになります。 569 + 公開する場合は、あなたの名前の下で行って下さい。 570 + 571 + B. このソフトを利用することによって生じた損害等について、作者は 572 + 責任を負わないものとします。各自の責任においてご利用下さい。 573 + 574 + C. 著作者人格権は k.inaba に帰属します。著作権は放棄します。 575 + 576 + D. 以上の3項は、ソース・実行バイナリの双方に適用されます。 577 + 578 + 579 +--------------------------------------------------------------------------- 580 + by k.inaba( http://www.kmonos.net/ )
Added release/type/C#.kwd version [ad426b7003c7466c]
cannot compute difference between binary files
Added release/type/C.kwd version [af5b5763401f9d62]
cannot compute difference between binary files
Added release/type/CSS.kwd version [154488afcdbc18cf]
cannot compute difference between binary files
Added release/type/D.kwd version [8f34ed709c56bfbe]
cannot compute difference between binary files
Added release/type/Delphi.kwd version [c2b8286ecff6ab7e]
cannot compute difference between binary files
Added release/type/Erlang.kwd version [fa674a7d7f5f2803]
cannot compute difference between binary files
Added release/type/HTML.kwd version [bcc48d5df9d738c6]
cannot compute difference between binary files
Added release/type/Haskell.kwd version [58ba6e7e25f5c6e7]
cannot compute difference between binary files
Added release/type/Java.kwd version [87d699ad82619471]
cannot compute difference between binary files
Added release/type/JavaScript.kwd version [3c80a2a95488f95a]
cannot compute difference between binary files
Added release/type/Lua.kwd version [8bdaec83a8614208]
cannot compute difference between binary files
Added release/type/OCaml.kwd version [9ae1c109a3b252d4]
cannot compute difference between binary files
Added release/type/PHP.kwd version [6502bc631bcbd487]
cannot compute difference between binary files
Added release/type/Perl.kwd version [2911b36abc38e4c0]
cannot compute difference between binary files
Added release/type/Python.kwd version [2a6051770f815127]
cannot compute difference between binary files
Added release/type/Ruby.kwd version [58c95a5eee341111]
cannot compute difference between binary files
Added release/type/asm.kwd version [f49cec2d93a24170]
cannot compute difference between binary files
Added release/type/b2e.kwd version [0191f97695669abc]
cannot compute difference between binary files
Added release/type/default.lay version [1e9cfd4ecec22dc3]
cannot compute difference between binary files
Added release/type/html.lay version [047516c168f611e7]
cannot compute difference between binary files
Added release/type/ini.kwd version [cd344f7f535888c7]
cannot compute difference between binary files
Added release/type/program.lay version [f08df96cba17006c]
cannot compute difference between binary files
Added release/type/unitext.lay version [edf43401b0a93fce]
cannot compute difference between binary files
Added rsrc/exefile.ico version [cf5ae6cc2663d634]
cannot compute difference between binary files
Added rsrc/gp_rsrc.rc version [eace87903f72cbef]
1 + 2 +#include "resource.h" 3 +#ifndef DS_SETFOREGROUND 4 + #define DS_SETFOREGROUND 0x200L 5 +#endif 6 +#ifndef RT_MANIFEST 7 + #define RT_MANIFEST 24 8 +#endif 9 + 10 +#include <winresrc.h> 11 +#include <winuser.h> 12 +#define IDC_STATIC (-1) 13 + 14 +///////////////////////////////////////////////////////////////////////////// 15 +// 日本語 resources 16 + 17 +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_JPN) 18 +#ifdef _WIN32 19 +LANGUAGE LANG_JAPANESE, SUBLANG_DEFAULT 20 +#pragma code_page(932) 21 +#endif //_WIN32 22 + 23 +///////////////////////////////////////////////////////////////////////////// 24 +// 25 +// RT_MANIFEST 26 +// 27 + 28 +1 RT_MANIFEST "manifest.xml" 29 + 30 +///////////////////////////////////////////////////////////////////////////// 31 +// 32 +// Version 33 +// 34 + 35 +VS_VERSION_INFO VERSIONINFO 36 + FILEVERSION 0,0,4,0 37 + PRODUCTVERSION 0,1,8,0 38 + FILEFLAGSMASK 0x3fL 39 +#ifdef _DEBUG 40 + FILEFLAGS 0x1L 41 +#else 42 + FILEFLAGS 0x0L 43 +#endif 44 + FILEOS 0x4L 45 + FILETYPE 0x1L 46 + FILESUBTYPE 0x0L 47 +BEGIN 48 + BLOCK "StringFileInfo" 49 + BEGIN 50 + BLOCK "041104b0" 51 + BEGIN 52 + VALUE "CompanyName", "kMonos.NET\0" 53 + VALUE "FileDescription", "GreenPad\0" 54 + VALUE "FileVersion", "#42\0" 55 + VALUE "InternalName", "kilib\0" 56 + VALUE "LegalCopyright", "Written by k.inaba 2002-2008.\0" 57 + VALUE "OriginalFilename", "GreenPad.exe\0" 58 + VALUE "ProductName", "GreenPad\0" 59 + VALUE "ProductVersion", "1.08.0\0" 60 + END 61 + END 62 + BLOCK "VarFileInfo" 63 + BEGIN 64 + VALUE "Translation", 0x411, 1200 65 + END 66 +END 67 + 68 +///////////////////////////////////////////////////////////////////////////// 69 +// 70 +// Icon 71 +// 72 + 73 +// Icon with lowest ID value placed first to ensure application icon 74 +// remains consistent on all systems. 75 +IDR_MAIN ICON "exefile.ico" 76 + 77 +///////////////////////////////////////////////////////////////////////////// 78 +// 79 +// Menu 80 +// 81 + 82 +IDR_MAIN MENU 83 +BEGIN 84 + POPUP "ファイル(&F)" 85 + BEGIN 86 + MENUITEM "新規作成(&N)\tCtrl+N", ID_CMD_NEWFILE 87 + MENUITEM SEPARATOR 88 + MENUITEM "開く(&O)...\tCtrl+O", ID_CMD_OPENFILE 89 + MENUITEM "開き直す(&R)...\tCtrl+R", ID_CMD_REOPENFILE 90 + MENUITEM SEPARATOR 91 + MENUITEM "保存(&S)\tCtrl+S", ID_CMD_SAVEFILE 92 + MENUITEM "別名で保存(&A)...\tCtrl+Shift+S", ID_CMD_SAVEFILEAS 93 + MENUITEM SEPARATOR 94 + POPUP "最近のファイル(&M)" 95 + BEGIN 96 + MENUITEM "(no files)", ID_MENUITEM40029, GRAYED 97 + END 98 + MENUITEM SEPARATOR 99 + MENUITEM "終了(&X)", ID_CMD_EXIT 100 + END 101 + POPUP "編集(&E)" 102 + BEGIN 103 + MENUITEM "元に戻す(&U)\tCtrl+Z", ID_CMD_UNDO 104 + MENUITEM "やり直す(&R)\tCtrl+Y", ID_CMD_REDO 105 + MENUITEM SEPARATOR 106 + MENUITEM "切り取り(&X)\tCtrl+X", ID_CMD_CUT 107 + MENUITEM "コピー(&C)\tCtrl+C", ID_CMD_COPY 108 + MENUITEM "貼り付け(&P)\tCtrl+V", ID_CMD_PASTE 109 + MENUITEM "削除(&D)\tDel", ID_CMD_DELETE 110 + MENUITEM SEPARATOR 111 + MENUITEM "全てを選択(&A)\tCtrl+A", ID_CMD_SELECTALL 112 + MENUITEM SEPARATOR 113 + MENUITEM "日時の挿入(&T)\tF5", ID_CMD_DATETIME 114 + END 115 + POPUP "検索(&S)" 116 + BEGIN 117 + MENUITEM "検索・置換(&F)\tCtrl+F", ID_CMD_FIND 118 + MENUITEM "次を検索(&N)\tF3", ID_CMD_FINDNEXT 119 + MENUITEM "前を検索(&P)\tShift+F3", ID_CMD_FINDPREV 120 + MENUITEM SEPARATOR 121 + MENUITEM "指定行へジャンプ(&J)\tCtrl+J", ID_CMD_JUMP 122 + MENUITEM SEPARATOR 123 + MENUITEM "Grep(&G)...\tCtrl+G", ID_CMD_GREP 124 + END 125 + POPUP "表示(&V)" 126 + BEGIN 127 + MENUITEM "折り返さない(&N)\tCtrl+1", ID_CMD_NOWRAP 128 + MENUITEM "指定幅で折り返し(&W)\tCtrl+2", ID_CMD_WRAPWIDTH 129 + MENUITEM "右端で折り返し(&R)\tCtrl+3", ID_CMD_WRAPWINDOW 130 + MENUITEM SEPARATOR 131 + POPUP "文書タイプ(&T)" 132 + BEGIN 133 + MENUITEM "(なし)", ID_MENUITEM40025, GRAYED 134 + END 135 + MENUITEM "設定(&S)...", ID_CMD_CONFIG 136 + MENUITEM SEPARATOR 137 + MENUITEM "ステータス バー(&B)", ID_CMD_STATUSBAR 138 + END 139 +END 140 + 141 + 142 +///////////////////////////////////////////////////////////////////////////// 143 +// 144 +// Dialog 145 +// 146 + 147 +IDD_OPENFILEHOOK DIALOGEX 0, 0, 187, 34 148 +STYLE DS_SETFONT | DS_3DLOOK | WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS 149 +FONT 9, "MS Pゴシック" 150 +BEGIN 151 + LTEXT "",1119,0,0,187,13,SS_SUNKEN | NOT WS_VISIBLE | NOT 152 + WS_GROUP 153 + LTEXT "文字コード(&C):",IDC_STATIC,7,18,42,8 154 + COMBOBOX IDC_CODELIST,66,16,111,103,CBS_DROPDOWNLIST | WS_VSCROLL | 155 + WS_TABSTOP 156 +END 157 + 158 +IDD_SAVEFILEHOOK DIALOGEX 0, 0, 187, 55 159 +STYLE DS_SETFONT | DS_3DLOOK | WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS 160 +FONT 9, "MS Pゴシック" 161 +BEGIN 162 + LTEXT "",1119,0,0,187,13,SS_SUNKEN | NOT WS_VISIBLE | NOT 163 + WS_GROUP 164 + LTEXT "文字コード(&C):",IDC_STATIC,7,18,42,8 165 + COMBOBOX IDC_CODELIST,66,16,111,103,CBS_DROPDOWNLIST | WS_VSCROLL | 166 + WS_TABSTOP 167 + LTEXT "改行コード(&L):",IDC_STATIC,7,37,41,8 168 + COMBOBOX IDC_CRLFLIST,66,35,60,103,CBS_DROPDOWNLIST | WS_VSCROLL | 169 + WS_TABSTOP 170 +END 171 + 172 +IDD_REOPENDLG DIALOG 0, 0, 187, 54 173 +STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_CENTER | WS_VISIBLE | 174 + WS_CLIPSIBLINGS | WS_CAPTION 175 +CAPTION "開き直す" 176 +FONT 9, "MS Pゴシック" 177 +BEGIN 178 + LTEXT "文字コード(&C):",IDC_STATIC,9,13,42,8 179 + COMBOBOX IDC_CODELIST,59,11,111,103,CBS_DROPDOWNLIST | WS_VSCROLL | 180 + WS_TABSTOP 181 + PUSHBUTTON "OK",IDOK,66,32,56,14 182 + PUSHBUTTON "キャンセル",IDCANCEL,125,32,56,14 183 +END 184 + 185 +IDD_FINDREPLACE DIALOG 0, 0, 316, 84 186 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_POPUP | 187 + WS_CAPTION | WS_SYSMENU 188 +CAPTION "検索・置換" 189 +FONT 9, "MS ゴシック" 190 +BEGIN 191 + LTEXT "検索文字列(&T):",IDC_STATIC,5,10,61,8 192 + EDITTEXT IDC_FINDBOX,68,8,122,13,ES_AUTOHSCROLL 193 + LTEXT "置換文字列(&W):",IDC_STATIC,5,31,61,8 194 + EDITTEXT IDC_REPLACEBOX,68,28,122,13,ES_AUTOHSCROLL 195 + DEFPUSHBUTTON "次を検索(&F)",ID_FINDNEXT,195,8,56,14 196 + PUSHBUTTON "置換(&R)",ID_REPLACENEXT,195,27,56,14 197 + PUSHBUTTON "前を検索(&E)",ID_FINDPREV,256,8,55,14 198 + PUSHBUTTON "全置換(&A)",ID_REPLACEALL,255,27,56,14 199 + GROUPBOX "オプション(&O)",IDC_STATIC,12,47,213,27 200 + CONTROL "大文字小文字を区別しない(&I)",IDC_IGNORECASE,"Button", 201 + BS_AUTOCHECKBOX | WS_TABSTOP,22,59,124,10 202 + CONTROL "正規表現(&X)",IDC_REGEXP,"Button",BS_AUTOCHECKBOX | 203 + WS_TABSTOP,153,58,60,10 204 + PUSHBUTTON "閉じる",IDCANCEL,244,59,37,14 205 +END 206 + 207 +IDD_JUMP DIALOG 0, 0, 131, 43 208 +STYLE DS_ABSALIGN | DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | 209 + WS_CAPTION | WS_SYSMENU 210 +CAPTION "指定行へジャンプ" 211 +FONT 9, "MS Pゴシック" 212 +BEGIN 213 + DEFPUSHBUTTON "&Go!",IDOK,87,12,25,14 214 + EDITTEXT IDC_LINEBOX,14,13,40,12,ES_AUTOHSCROLL | ES_NUMBER 215 + LTEXT "行目へ",IDC_STATIC,61,15,22,8 216 +END 217 + 218 +IDD_CONFIG DIALOGEX 0, 0, 287, 236 219 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU 220 +CAPTION "エディタ設定" 221 +FONT 9, "MS Pゴシック" 222 +BEGIN 223 + GROUPBOX "共通設定",IDC_STATIC,7,11,273,102 224 + LTEXT "[元に戻す]上限(&U):",IDC_STATIC,24,24,56,8 225 + CONTROL "無限",IDC_UNDOLIM1,"Button",BS_AUTORADIOBUTTON | 226 + WS_GROUP | WS_TABSTOP,86,23,33,10 227 + CONTROL "",IDC_UNDOLIM2,"Button",BS_AUTORADIOBUTTON,122,23,11,8 228 + EDITTEXT IDC_UNDO_CT,134,21,24,12,ES_AUTOHSCROLL | ES_NUMBER 229 + LTEXT "回",IDC_STATIC,162,24,8,8 230 + LTEXT "横位置の表示(&L):",IDC_STATIC,29,37,51,8 231 + CONTROL "文字数",IDC_COUNTBYLETTER,"Button",BS_AUTORADIOBUTTON | 232 + WS_GROUP | WS_TABSTOP,86,36,33,10 233 + CONTROL "表示位置",IDC_COUNTBYLETTER2,"Button", 234 + BS_AUTORADIOBUTTON | WS_TABSTOP,122,35,38,10 235 + LTEXT "ファイル履歴件数(&H):",IDC_STATIC,19,50,62,8 236 + EDITTEXT IDC_LATEST_NUM,86,48,32,12,ES_AUTOHSCROLL | ES_NUMBER 237 + LTEXT "ファイル・フィルタ(&F):",IDC_STATIC,21,66,60,8 238 + EDITTEXT IDC_TXTFILT,86,63,182,12,ES_AUTOHSCROLL 239 + LTEXT "外部Grep(&G):",IDC_STATIC,42,81,39,8 240 + EDITTEXT IDC_EXTGREP,86,78,182,12,ES_AUTOHSCROLL 241 + LTEXT "新規ファイルのモード(&N):",IDC_STATIC,9,95,73,8 242 + COMBOBOX IDC_NEWCS,86,92,76,162,CBS_DROPDOWNLIST | WS_VSCROLL | 243 + WS_TABSTOP 244 + COMBOBOX IDC_NEWLB,164,92,39,162,CBS_DROPDOWNLIST | WS_VSCROLL | 245 + WS_TABSTOP 246 + COMBOBOX IDC_NEWDT,204,92,65,164,CBS_DROPDOWNLIST | WS_VSCROLL | 247 + WS_TABSTOP 248 + CONTROL "同じウインドウで開く(&R)",IDC_OPENSAME,"Button", 249 + BS_AUTOCHECKBOX | WS_TABSTOP,181,25,83,10 250 + CONTROL "ウインドウサイズを記憶(&S)",IDC_REMSIZE,"Button", 251 + BS_AUTOCHECKBOX | WS_TABSTOP,181,35,92,10 252 + CONTROL "ウインドウ位置を記憶(&P)",IDC_REMPLACE,"Button", 253 + BS_AUTOCHECKBOX | WS_TABSTOP,181,45,86,10 254 + GROUPBOX "文書タイプ別設定",IDC_STATIC,7,118,274,92 255 + LISTBOX IDC_DOCTYPELIST,15,133,88,53,LBS_NOINTEGRALHEIGHT | 256 + WS_VSCROLL | WS_TABSTOP 257 + PUSHBUTTON "追加",IDC_NEWDOCTYPE,17,191,29,14 258 + PUSHBUTTON "削除",IDC_DELDOCTYPE,48,191,29,14 259 + LTEXT "パターン:",IDC_STATIC,114,138,27,8 260 + EDITTEXT IDC_DT_PAT,146,135,127,12,ES_AUTOHSCROLL 261 + LTEXT "キーワード:",IDC_STATIC,108,155,34,8 262 + COMBOBOX IDC_PAT_KWD,146,152,75,172,CBS_DROPDOWNLIST | CBS_SORT | 263 + CBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP 264 + PUSHBUTTON "編集",IDC_EDITKWD,231,152,19,14 265 + LTEXT "レイアウト:",IDC_STATIC,111,172,31,8 266 + COMBOBOX IDC_PAT_LAY,146,169,75,172,CBS_DROPDOWNLIST | CBS_SORT | 267 + CBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP 268 + PUSHBUTTON "編集",IDC_EDITLAY,231,169,19,14 269 + DEFPUSHBUTTON "OK",IDOK,175,214,50,14 270 + PUSHBUTTON "キャンセル",IDCANCEL,230,214,50,14 271 +END 272 + 273 +IDD_ADDDOCTYPE DIALOG 0, 0, 123, 67 274 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU 275 +CAPTION "文書タイプの追加" 276 +FONT 9, "MS Pゴシック" 277 +BEGIN 278 + LTEXT "名前(&N):",IDC_STATIC,17,11,27,8 279 + EDITTEXT IDC_NAME,46,8,69,12,ES_AUTOHSCROLL 280 + LTEXT "拡張子(&E):",IDC_STATIC,10,25,34,8 281 + EDITTEXT IDC_EXT,46,24,69,12,ES_AUTOHSCROLL 282 + DEFPUSHBUTTON "OK",IDOK,33,43,34,14 283 + PUSHBUTTON "キャンセル",IDCANCEL,71,43,33,14 284 +END 285 + 286 + 287 +///////////////////////////////////////////////////////////////////////////// 288 +// 289 +// Accelerator 290 +// 291 + 292 +IDR_MAIN ACCELERATORS 293 +BEGIN 294 + "1", ID_CMD_NOWRAP, VIRTKEY, CONTROL, NOINVERT 295 + "2", ID_CMD_WRAPWIDTH, VIRTKEY, CONTROL, NOINVERT 296 + "3", ID_CMD_WRAPWINDOW, VIRTKEY, CONTROL, NOINVERT 297 + "A", ID_CMD_SELECTALL, VIRTKEY, CONTROL, NOINVERT 298 + "C", ID_CMD_COPY, VIRTKEY, CONTROL, NOINVERT 299 + "F", ID_CMD_FIND, VIRTKEY, CONTROL, NOINVERT 300 + "G", ID_CMD_GREP, VIRTKEY, CONTROL, NOINVERT 301 + "H", ID_CMD_FIND, VIRTKEY, CONTROL, NOINVERT 302 + "J", ID_CMD_JUMP, VIRTKEY, CONTROL, NOINVERT 303 + "N", ID_CMD_NEWFILE, VIRTKEY, CONTROL, NOINVERT 304 + "O", ID_CMD_OPENFILE, VIRTKEY, CONTROL, NOINVERT 305 + "R", ID_CMD_REOPENFILE, VIRTKEY, CONTROL, NOINVERT 306 + "S", ID_CMD_SAVEFILE, VIRTKEY, CONTROL, NOINVERT 307 + "S", ID_CMD_SAVEFILEAS, VIRTKEY, SHIFT, CONTROL, 308 + NOINVERT 309 + "V", ID_CMD_PASTE, VIRTKEY, CONTROL, NOINVERT 310 + VK_DELETE, ID_CMD_CUT, VIRTKEY, SHIFT, NOINVERT 311 + VK_F3, ID_CMD_FINDNEXT, VIRTKEY, NOINVERT 312 + VK_F3, ID_CMD_FINDPREV, VIRTKEY, SHIFT, NOINVERT 313 + VK_F4, ID_CMD_EXIT, VIRTKEY, CONTROL, NOINVERT 314 + VK_F5, ID_CMD_DATETIME, VIRTKEY, NOINVERT 315 + VK_INSERT, ID_CMD_COPY, VIRTKEY, CONTROL, NOINVERT 316 + VK_INSERT, ID_CMD_PASTE, VIRTKEY, SHIFT, NOINVERT 317 + VK_RETURN, ID_CMD_REOPENFILE, VIRTKEY, ALT, NOINVERT 318 + VK_TAB, ID_CMD_NEXTWINDOW, VIRTKEY, CONTROL, NOINVERT 319 + VK_TAB, ID_CMD_PREVWINDOW, VIRTKEY, SHIFT, CONTROL, 320 + NOINVERT 321 + "X", ID_CMD_CUT, VIRTKEY, CONTROL, NOINVERT 322 + "Y", ID_CMD_REDO, VIRTKEY, CONTROL, NOINVERT 323 + "Z", ID_CMD_UNDO, VIRTKEY, CONTROL, NOINVERT 324 +END 325 + 326 + 327 +///////////////////////////////////////////////////////////////////////////// 328 +// 329 +// DESIGNINFO 330 +// 331 + 332 +#ifdef APSTUDIO_INVOKED 333 +GUIDELINES DESIGNINFO 334 +BEGIN 335 + IDD_FINDREPLACE, DIALOG 336 + BEGIN 337 + LEFTMARGIN, 7 338 + RIGHTMARGIN, 309 339 + TOPMARGIN, 7 340 + BOTTOMMARGIN, 77 341 + END 342 + 343 + IDD_JUMP, DIALOG 344 + BEGIN 345 + LEFTMARGIN, 7 346 + RIGHTMARGIN, 124 347 + TOPMARGIN, 7 348 + BOTTOMMARGIN, 36 349 + END 350 + 351 + IDD_CONFIG, DIALOG 352 + BEGIN 353 + LEFTMARGIN, 7 354 + RIGHTMARGIN, 280 355 + TOPMARGIN, 7 356 + BOTTOMMARGIN, 228 357 + END 358 + 359 + IDD_ADDDOCTYPE, DIALOG 360 + BEGIN 361 + LEFTMARGIN, 7 362 + RIGHTMARGIN, 116 363 + TOPMARGIN, 7 364 + BOTTOMMARGIN, 60 365 + END 366 +END 367 +#endif // APSTUDIO_INVOKED 368 + 369 + 370 +///////////////////////////////////////////////////////////////////////////// 371 +// 372 +// String Table 373 +// 374 + 375 +STRINGTABLE 376 +BEGIN 377 + IDS_ASKTOSAVE "現在の文書を保存しますか?" 378 + IDS_APPNAME "GreenPad" 379 + IDS_SAVEERROR "ファイルの保存に失敗しました。" 380 + IDS_ALLFILES "全てのファイル(*.*)" 381 + IDS_TXTFILES "テキスト形式のファイル" 382 + IDS_OPENERROR "ファイルを開くのに失敗しました。" 383 + IDS_DEFAULT "(標準)" 384 + IDS_NOTFOUND "見つかりませんでした。" 385 + IDS_REPLACEALLDONE "%d箇所置換しました。" 386 + IDS_OKTODEL "を削除してよろしいですか?" 387 +END 388 + 389 +#endif // 日本語 resources 390 +///////////////////////////////////////////////////////////////////////////// 391 + 392 + 393 +///////////////////////////////////////////////////////////////////////////// 394 +// 英語 (米国) resources 395 + 396 +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) 397 +#ifdef _WIN32 398 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 399 +#pragma code_page(1252) 400 +#endif //_WIN32 401 + 402 +///////////////////////////////////////////////////////////////////////////// 403 +// 404 +// Menu 405 +// 406 + 407 +IDR_MAIN MENU 408 +BEGIN 409 + POPUP "&File" 410 + BEGIN 411 + MENUITEM "&New File\tCtrl+N", ID_CMD_NEWFILE 412 + MENUITEM SEPARATOR 413 + MENUITEM "&Open...\tCtrl+O", ID_CMD_OPENFILE 414 + MENUITEM "&ReOpen...\tCtrl+R", ID_CMD_REOPENFILE 415 + MENUITEM SEPARATOR 416 + MENUITEM "&Save\tCtrl+S", ID_CMD_SAVEFILE 417 + MENUITEM "Save &As...\tCtrl+Shift+S", ID_CMD_SAVEFILEAS 418 + MENUITEM SEPARATOR 419 + POPUP "R&ecent Files" 420 + BEGIN 421 + MENUITEM "(no files)", ID_MENUITEM40030, GRAYED 422 + END 423 + MENUITEM "E&xit", ID_CMD_EXIT 424 + END 425 + POPUP "&Edit" 426 + BEGIN 427 + MENUITEM "&Undo\tCtrl+Z", ID_CMD_UNDO 428 + MENUITEM "&Redo\tCtrl+Y", ID_CMD_REDO 429 + MENUITEM SEPARATOR 430 + MENUITEM "Cut\tCtrl+&X", ID_CMD_CUT 431 + MENUITEM "&Copy\tCtrl+C", ID_CMD_COPY 432 + MENUITEM "&Paste\tCtrl+V", ID_CMD_PASTE 433 + MENUITEM "&Delete\tDel", ID_CMD_DELETE 434 + MENUITEM SEPARATOR 435 + MENUITEM "Select &All\tCtrl+A", ID_CMD_SELECTALL 436 + MENUITEM SEPARATOR 437 + MENUITEM "Insert Date&&&Time\tF5", ID_CMD_DATETIME 438 + END 439 + POPUP "&Search" 440 + BEGIN 441 + MENUITEM "&Find\tCtrl+F", ID_CMD_FIND 442 + MENUITEM "Find &Next\tF3", ID_CMD_FINDNEXT 443 + MENUITEM "Find &Prev\tShift+F3", ID_CMD_FINDPREV 444 + MENUITEM SEPARATOR 445 + MENUITEM "&Jump to Line\tCtrl+J", ID_CMD_JUMP 446 + MENUITEM SEPARATOR 447 + MENUITEM "&Grep...\tCtrl+G", ID_CMD_GREP 448 + END 449 + POPUP "&View" 450 + BEGIN 451 + MENUITEM "&No wrapping\tCtrl+1", ID_CMD_NOWRAP 452 + MENUITEM "&Wrap at #th letter\tCtrl+2", ID_CMD_WRAPWIDTH 453 + MENUITEM "Wrap at &Right Edge\tCtrl+3", ID_CMD_WRAPWINDOW 454 + MENUITEM SEPARATOR 455 + POPUP "&Document Type" 456 + BEGIN 457 + MENUITEM "dummy", ID_MENUITEM40025 458 + END 459 + MENUITEM "&Settings...", ID_CMD_CONFIG 460 + MENUITEM SEPARATOR 461 + MENUITEM "Status&Bar", ID_CMD_STATUSBAR 462 + END 463 +END 464 + 465 + 466 +///////////////////////////////////////////////////////////////////////////// 467 +// 468 +// Dialog 469 +// 470 + 471 +IDD_SAVEFILEHOOK DIALOGEX 0, 0, 187, 55 472 +STYLE DS_SETFONT | DS_3DLOOK | WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS 473 +FONT 9, "MS Sans Serif" 474 +BEGIN 475 + LTEXT "",1119,0,0,187,13,SS_SUNKEN | NOT WS_VISIBLE | NOT 476 + WS_GROUP 477 + LTEXT "&Charactor Encode:",IDC_STATIC,7,18,58,8 478 + COMBOBOX IDC_CODELIST,69,16,108,103,CBS_DROPDOWNLIST | WS_VSCROLL | 479 + WS_TABSTOP 480 + LTEXT "&Line-end:",IDC_STATIC,7,37,41,8 481 + COMBOBOX IDC_CRLFLIST,69,35,57,103,CBS_DROPDOWNLIST | WS_VSCROLL | 482 + WS_TABSTOP 483 +END 484 + 485 +IDD_REOPENDLG DIALOG 0, 0, 187, 54 486 +STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_CENTER | WS_VISIBLE | 487 + WS_CLIPSIBLINGS | WS_CAPTION 488 +CAPTION "ReOpen File" 489 +FONT 9, "MS Sans Serif" 490 +BEGIN 491 + LTEXT "&Charactor Encode:",IDC_STATIC,9,13,54,8 492 + COMBOBOX IDC_CODELIST,72,11,105,103,CBS_DROPDOWNLIST | WS_VSCROLL | 493 + WS_TABSTOP 494 + PUSHBUTTON "OK",IDOK,66,32,56,14 495 + PUSHBUTTON "Cancel",IDCANCEL,125,32,56,14 496 +END 497 + 498 +IDD_OPENFILEHOOK DIALOGEX 0, 0, 187, 34 499 +STYLE DS_SETFONT | DS_3DLOOK | WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS 500 +FONT 9, "MS Sans Serif" 501 +BEGIN 502 + LTEXT "",1119,0,0,187,13,SS_SUNKEN | NOT WS_VISIBLE | NOT 503 + WS_GROUP 504 + LTEXT "&Charactor Encode:",IDC_STATIC,7,18,54,8 505 + COMBOBOX IDC_CODELIST,66,16,111,103,CBS_DROPDOWNLIST | WS_VSCROLL | 506 + WS_TABSTOP 507 +END 508 + 509 +IDD_JUMP DIALOG 0, 0, 131, 43 510 +STYLE DS_ABSALIGN | DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | 511 + WS_CAPTION | WS_SYSMENU 512 +CAPTION "Jump To" 513 +FONT 9, "MS Sans Serif" 514 +BEGIN 515 + DEFPUSHBUTTON "&Go!",IDOK,83,13,25,14 516 + EDITTEXT IDC_LINEBOX,34,14,40,12,ES_AUTOHSCROLL | ES_NUMBER 517 + LTEXT "&Line",IDC_STATIC,17,16,13,8 518 +END 519 + 520 +IDD_FINDREPLACE DIALOG 0, 0, 282, 84 521 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_POPUP | 522 + WS_CAPTION | WS_SYSMENU 523 +CAPTION "Find & Replace" 524 +FONT 9, "MS Sans Serif" 525 +BEGIN 526 + LTEXT "&Text to Find:",IDC_STATIC,7,10,38,8 527 + EDITTEXT IDC_FINDBOX,56,7,123,13,ES_AUTOHSCROLL 528 + DEFPUSHBUTTON "&Find",ID_FINDNEXT,185,8,43,14 529 + PUSHBUTTON "Find&Prev",ID_FINDPREV,232,8,43,14 530 + LTEXT "Replace &with:",IDC_STATIC,7,31,40,8 531 + EDITTEXT IDC_REPLACEBOX,56,28,123,13,ES_AUTOHSCROLL 532 + PUSHBUTTON "&Replace",ID_REPLACENEXT,185,27,43,14 533 + PUSHBUTTON "Replace&All",ID_REPLACEALL,232,27,43,14 534 + GROUPBOX "&Options",IDC_STATIC,12,47,181,27 535 + CONTROL "&Ignore Case",IDC_IGNORECASE,"Button",BS_AUTOCHECKBOX | 536 + WS_TABSTOP,22,59,51,10 537 + CONTROL "Regular E&xpression",IDC_REGEXP,"Button", 538 + BS_AUTOCHECKBOX | WS_TABSTOP,114,58,73,10 539 + PUSHBUTTON "Close",IDCANCEL,244,59,29,14 540 +END 541 + 542 +IDD_ADDDOCTYPE DIALOG 0, 0, 123, 67 543 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU 544 +CAPTION "New DocType" 545 +FONT 9, "MS Sans Serif" 546 +BEGIN 547 + LTEXT "&Name:",IDC_STATIC,22,11,19,8 548 + EDITTEXT IDC_NAME,46,8,69,12,ES_AUTOHSCROLL 549 + LTEXT "&Extension:",IDC_STATIC,10,25,34,8 550 + EDITTEXT IDC_EXT,46,24,69,12,ES_AUTOHSCROLL 551 + DEFPUSHBUTTON "OK",IDOK,33,43,34,14 552 + PUSHBUTTON "Cancel",IDCANCEL,71,43,33,14 553 +END 554 + 555 +IDD_CONFIG DIALOGEX 0, 0, 287, 236 556 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU 557 +CAPTION "Config" 558 +FONT 9, "MS Sans Serif" 559 +BEGIN 560 + GROUPBOX "Common",IDC_STATIC,7,7,273,106 561 + LTEXT "&Undo:",IDC_STATIC,62,21,25,8 562 + CONTROL "Infinite",IDC_UNDOLIM1,"Button",BS_AUTORADIOBUTTON | 563 + WS_GROUP | WS_TABSTOP,88,20,33,10 564 + CONTROL "",IDC_UNDOLIM2,"Button",BS_AUTORADIOBUTTON,124,20,11,8 565 + EDITTEXT IDC_UNDO_CT,135,18,24,12,ES_AUTOHSCROLL | ES_NUMBER 566 + LTEXT "times",IDC_STATIC,163,21,17,8 567 + LTEXT "&Column by:",IDC_STATIC,46,33,40,8 568 + CONTROL "Letters",IDC_COUNTBYLETTER,"Button",BS_AUTORADIOBUTTON | 569 + WS_GROUP | WS_TABSTOP,88,32,33,10 570 + CONTROL "Positions",IDC_COUNTBYLETTER2,"Button", 571 + BS_AUTORADIOBUTTON | WS_TABSTOP,124,32,49,10 572 + LTEXT "M&RU File Num:",IDC_STATIC,34,45,52,8 573 + EDITTEXT IDC_LATEST_NUM,88,43,32,12,ES_AUTOHSCROLL | ES_NUMBER 574 + LTEXT "TextFile &Filter:",IDC_STATIC,36,63,44,8 575 + EDITTEXT IDC_TXTFILT,88,59,176,12,ES_AUTOHSCROLL 576 + LTEXT "Extrenal &Grep Program:",IDC_STATIC,12,77,77,8 577 + EDITTEXT IDC_EXTGREP,88,75,176,12,ES_AUTOHSCROLL 578 + LTEXT "&New File Mode:",IDC_STATIC,34,93,53,8 579 + COMBOBOX IDC_NEWCS,88,90,76,167,CBS_DROPDOWNLIST | WS_VSCROLL | 580 + WS_TABSTOP 581 + COMBOBOX IDC_NEWLB,166,90,39,166,CBS_DROPDOWNLIST | WS_VSCROLL | 582 + WS_TABSTOP 583 + COMBOBOX IDC_NEWDT,206,90,65,165,CBS_DROPDOWNLIST | WS_VSCROLL | 584 + WS_TABSTOP 585 + CONTROL "Open in Same &Window",IDC_OPENSAME,"Button", 586 + BS_AUTOCHECKBOX | WS_TABSTOP,186,17,90,10 587 + CONTROL "Remember Window &Size",IDC_REMSIZE,"Button", 588 + BS_AUTOCHECKBOX | WS_TABSTOP,186,27,92,10 589 + CONTROL "Remember Window &Pos",IDC_REMPLACE,"Button", 590 + BS_AUTOCHECKBOX | WS_TABSTOP,186,38,90,10 591 + GROUPBOX "Document Types",IDC_STATIC,6,118,274,92 592 + LISTBOX IDC_DOCTYPELIST,14,133,89,53,LBS_NOINTEGRALHEIGHT | 593 + WS_VSCROLL | WS_TABSTOP 594 + PUSHBUTTON "Add",IDC_NEWDOCTYPE,17,191,29,14 595 + PUSHBUTTON "Del",IDC_DELDOCTYPE,50,191,29,14 596 + LTEXT "Pattern:",IDC_STATIC,117,138,23,8 597 + EDITTEXT IDC_DT_PAT,149,135,123,12,ES_AUTOHSCROLL 598 + LTEXT "Keyword:",IDC_STATIC,114,155,27,8 599 + COMBOBOX IDC_PAT_KWD,149,152,72,172,CBS_DROPDOWNLIST | CBS_SORT | 600 + CBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP 601 + PUSHBUTTON "edit",IDC_EDITKWD,229,151,19,14 602 + LTEXT "Layout: ",IDC_STATIC,118,172,24,8 603 + COMBOBOX IDC_PAT_LAY,149,169,72,172,CBS_DROPDOWNLIST | CBS_SORT | 604 + CBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP 605 + PUSHBUTTON "edit",IDC_EDITLAY,229,169,19,14 606 + DEFPUSHBUTTON "OK",IDOK,175,215,50,14 607 + PUSHBUTTON "Cancel",IDCANCEL,230,215,50,14 608 +END 609 + 610 + 611 +///////////////////////////////////////////////////////////////////////////// 612 +// 613 +// DESIGNINFO 614 +// 615 + 616 +#ifdef APSTUDIO_INVOKED 617 +GUIDELINES DESIGNINFO 618 +BEGIN 619 + IDD_JUMP, DIALOG 620 + BEGIN 621 + LEFTMARGIN, 7 622 + RIGHTMARGIN, 124 623 + TOPMARGIN, 7 624 + BOTTOMMARGIN, 36 625 + END 626 + 627 + IDD_FINDREPLACE, DIALOG 628 + BEGIN 629 + LEFTMARGIN, 7 630 + RIGHTMARGIN, 275 631 + TOPMARGIN, 7 632 + BOTTOMMARGIN, 77 633 + END 634 + 635 + IDD_ADDDOCTYPE, DIALOG 636 + BEGIN 637 + LEFTMARGIN, 7 638 + RIGHTMARGIN, 116 639 + TOPMARGIN, 7 640 + BOTTOMMARGIN, 60 641 + END 642 + 643 + IDD_CONFIG, DIALOG 644 + BEGIN 645 + LEFTMARGIN, 7 646 + RIGHTMARGIN, 280 647 + TOPMARGIN, 7 648 + BOTTOMMARGIN, 229 649 + END 650 +END 651 +#endif // APSTUDIO_INVOKED 652 + 653 + 654 +///////////////////////////////////////////////////////////////////////////// 655 +// 656 +// String Table 657 +// 658 + 659 +STRINGTABLE 660 +BEGIN 661 + IDS_ASKTOSAVE "Do you want to Save the current file ?" 662 + IDS_APPNAME "GreenPad" 663 + IDS_SAVEERROR "Could not save the file." 664 + IDS_ALLFILES "All Files(*.*)" 665 + IDS_TXTFILES "Text Files" 666 + IDS_OPENERROR "Could not open the file." 667 + IDS_DEFAULT "(default)" 668 + IDS_NOTFOUND "Not Found." 669 + IDS_REPLACEALLDONE "%d times Replaced." 670 + IDS_OKTODEL " will be removed. OK?" 671 +END 672 + 673 +#endif // 英語 (米国) resources 674 +/////////////////////////////////////////////////////////////////////////////
Added rsrc/manifest.xml version [adc8ffd4825a9049]
1 +<?xml version="1.0" standalone="yes"?> 2 +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"><dependency><dependentAssembly><assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*" /></dependentAssembly></dependency></assembly>
Added rsrc/resource.h version [feca3a05cea60d4e]
1 +//{{NO_DEPENDENCIES}} 2 +// Microsoft Visual C++ generated include file. 3 +// Used by kilib.rc 4 +// 5 +#define IDS_ASKTOSAVE 1 6 +#define IDS_APPNAME 2 7 +#define IDS_SAVEERROR 3 8 +#define ID_FINDNEXT 3 9 +#define IDS_ALLFILES 4 10 +#define ID_REPLACENEXT 4 11 +#define IDS_TXTFILES 5 12 +#define ID_REPLACEALL 5 13 +#define IDS_OPENERROR 6 14 +#define IDS_DEFAULT 7 15 +#define IDS_NOTFOUND 8 16 +#define IDS_REPLACEALLDONE 9 17 +#define IDS_OKTODEL 10 18 +#define IDR_MAIN 103 19 +#define IDD_OPENFILEHOOK 105 20 +#define IDD_SAVEFILEHOOK 106 21 +#define IDD_REOPENDLG 107 22 +#define IDD_FINDREPLACE 108 23 +#define IDD_JUMP 109 24 +#define IDD_CONFIG 110 25 +#define IDD_ADDDOCTYPE 111 26 +#define IDC_CODELIST 1002 27 +#define IDC_CRLFLIST 1003 28 +#define IDC_FINDBOX 1004 29 +#define IDC_REPLACE 1005 30 +#define IDC_REPLACEBOX 1005 31 +#define IDC_IGNORECASE 1006 32 +#define IDC_REGEXP 1007 33 +#define IDC_LINEBOX 1007 34 +#define IDC_BACKSEARCH 1008 35 +#define ID_FINDPREV 1008 36 +#define IDC_LATEST_NUM 1010 37 +#define IDC_UNDOLIM1 1011 38 +#define IDC_UNDOLIM2 1012 39 +#define IDC_UNDO_CT 1013 40 +#define IDC_TXTFILT 1014 41 +#define IDC_EXTGREP 1015 42 +#define IDC_DT_PAT 1018 43 +#define IDC_PAT_KWD 1019 44 +#define IDC_DOCTYPELIST 1020 45 +#define IDC_NEWDOCTYPE 1021 46 +#define IDC_PAT_LAY 1022 47 +#define IDC_DELDOCTYPE 1023 48 +#define IDC_EDITKWD 1024 49 +#define IDC_EDITLAY 1025 50 +#define IDC_NAME 1025 51 +#define IDC_EXT 1026 52 +#define IDC_OPENSAME 1026 53 +#define IDC_COUNTBYLETTER 1027 54 +#define IDC_NEWCS 1028 55 +#define IDC_NEWLB 1029 56 +#define IDC_OPENSAME2 1030 57 +#define IDC_REMSIZE 1030 58 +#define IDC_OPENSAME3 1031 59 +#define IDC_REMPLACE 1031 60 +#define IDC_COUNTBYLETTER2 1032 61 +#define IDC_NEWLB2 1033 62 +#define IDC_NEWDT 1033 63 +#define ID_CMD_REOPENFILE 40002 64 +#define ID_CMD_PROPERTY 40003 65 +#define ID_CMD_NEWFILE 40004 66 +#define ID_CMD_OPENFILE 40005 67 +#define ID_CMD_SAVEFILE 40006 68 +#define ID_CMD_SAVEFILEAS 40007 69 +#define ID_CMD_EXIT 40008 70 +#define ID_CMD_UNDO 40009 71 +#define ID_CMD_REDO 40010 72 +#define ID_CMD_CUT 40011 73 +#define ID_CMD_COPY 40012 74 +#define ID_CMD_PASTE 40013 75 +#define ID_CMD_DELETE 40014 76 +#define ID_CMD_SELECTALL 40015 77 +#define ID_CMD_FIND 40016 78 +#define ID_CMD_FINDNEXT 40017 79 +#define ID_CMD_FINDPREV 40018 80 +#define ID_CMD_NOWRAP 40019 81 +#define ID_CMD_WRAPWIDTH 40020 82 +#define ID_CMD_WRAPWINDOW 40021 83 +#define ID_CMD_CONFIG 40022 84 +#define ID_CMD_JUMP 40023 85 +#define ID_CMD_DATETIME 40024 86 +#define ID_MENUITEM40025 40025 87 +#define ID_CMD_NEXTWINDOW 40026 88 +#define ID_CMD_PREVWINDOW 40027 89 +#define ID_CMD_GREP 40028 90 +#define ID_MENUITEM40029 40029 91 +#define ID_MENUITEM40030 40030 92 +#define ID_CMD_STATUSBAR 40032 93 +#define ID_CMD_MRU 40200 94 +#define ID_CMD_DOCTYPE 40300 95 + 96 +// Next default values for new objects 97 +// 98 +#ifdef APSTUDIO_INVOKED 99 +#ifndef APSTUDIO_READONLY_SYMBOLS 100 +#define _APS_NEXT_RESOURCE_VALUE 113 101 +#define _APS_NEXT_COMMAND_VALUE 40033 102 +#define _APS_NEXT_CONTROL_VALUE 1029 103 +#define _APS_NEXT_SYMED_VALUE 102 104 +#endif 105 +#endif