/*! キーボードマクロの読み込み エラーメッセージは出しません。呼び出し側でよきにはからってください。 */ BOOL CKeyMacroMgr::LoadKeyMacro( HINSTANCE hInstance, const TCHAR* pszPath ) { /* キーマクロのバッファをクリアする */ ClearAll(); CTextInputStream in( pszPath ); if(!in){ m_nReady = false; return FALSE; } WCHAR szFuncName[100]; WCHAR szFuncNameJapanese[256]; EFunctionCode nFuncID; int i; int nBgn, nEnd; CMacro* macro = NULL; // Jun. 16, 2002 genta m_nReady = true; // エラーがあればfalseになる std::tstring MACRO_ERROR_TITLE_string = LS(STR_ERR_DLGKEYMACMGR2); const TCHAR* MACRO_ERROR_TITLE = MACRO_ERROR_TITLE_string.c_str(); int line = 1; // エラー時に行番号を通知するため.1始まり. for( ; in.Good() ; ++line ){ std::wstring strLine = in.ReadLineW(); const WCHAR* szLine = strLine.c_str(); // '\0'終端文字列を取得 using namespace WCODE; int nLineLen = strLine.length(); // 先行する空白をスキップ for( i = 0; i < nLineLen; ++i ){ if( szLine[i] != SPACE && szLine[i] != TAB ){ break; } } nBgn = i; // Jun. 16, 2002 genta 空行を無視する if( nBgn == nLineLen || szLine[nBgn] == LTEXT('\0') ){ continue; } // コメント行の検出 //# パフォーマンス:'/'のときだけ2文字目をテスト if( szLine[nBgn] == LTEXT('/') && nBgn + 1 < nLineLen && szLine[nBgn + 1] == LTEXT('/') ){ continue; } // 関数名の取得 szFuncName[0]='\0';// 初期化 for( ; i < nLineLen; ++i ){ //# バッファオーバーランチェック if( szLine[i] == LTEXT('(') && (i - nBgn)< _countof(szFuncName) ){ auto_memcpy( szFuncName, &szLine[nBgn], i - nBgn ); szFuncName[i - nBgn] = L'\0'; ++i; nBgn = i; break; } } // 関数名にS_が付いていたら /* 関数名→機能ID,機能名日本語 */ //@@@ 2002.2.2 YAZAKI マクロをCSMacroMgrに統一 nFuncID = CSMacroMgr::GetFuncInfoByName( hInstance, szFuncName, szFuncNameJapanese ); if( -1 != nFuncID ){ macro = new CMacro( nFuncID ); // Jun. 16, 2002 genta プロトタイプチェック用に追加 int nArgs; const MacroFuncInfo* mInfo= CSMacroMgr::GetFuncInfoByID( nFuncID ); int nArgSizeMax = _countof( mInfo->m_varArguments ); if( mInfo->m_pData ){ nArgSizeMax = mInfo->m_pData->m_nArgMaxSize; } for(nArgs = 0; szLine[i] ; ++nArgs ) { // Jun. 16, 2002 genta プロトタイプチェック if( nArgs >= nArgSizeMax ){ ::MYMESSAGEBOX( NULL, MB_OK | MB_ICONSTOP | MB_TOPMOST, MACRO_ERROR_TITLE, LS(STR_ERR_DLGKEYMACMGR3), line, i + 1 ); m_nReady = false; } VARTYPE type = VT_EMPTY; if( nArgs < 4 ){ type = mInfo->m_varArguments[nArgs]; }else{ if( mInfo->m_pData && nArgs < mInfo->m_pData->m_nArgMinSize ){ type = mInfo->m_pData->m_pVarArgEx[nArgs - 4]; } } // Skip Space while( szLine[i] == LTEXT(' ') || szLine[i] == LTEXT('\t') ) i++; //@@@ 2002.2.2 YAZAKI PPA.DLLマクロにあわせて仕様変更。文字列は''で囲む。 // Jun. 16, 2002 genta double quotationも許容する if( LTEXT('\'') == szLine[i] || LTEXT('\"') == szLine[i] ){ // 'で始まったら文字列だよきっと。 // Jun. 16, 2002 genta プロトタイプチェック // Jun. 27, 2002 genta 余分な引数を無視するよう,VT_EMPTYを許容する. if( type != VT_BSTR && type != VT_EMPTY ){ ::MYMESSAGEBOX( NULL, MB_OK | MB_ICONSTOP | MB_TOPMOST, MACRO_ERROR_TITLE, LS(STR_ERR_DLGKEYMACMGR4), line, i + 1, szFuncName, nArgs + 1 ); m_nReady = false; break; } WCHAR cQuote = szLine[i]; ++i; nBgn = nEnd = i; // nBgnは引数の先頭の文字 // Jun. 16, 2002 genta // 行末の検出のため,ループ回数を1増やした for( ; i <= nLineLen; ++i ){ // 最後の文字+1までスキャン if( szLine[i] == LTEXT('\\') ){ // エスケープのスキップ ++i; continue; } if( szLine[i] == cQuote ){ // 始まりと同じquotationで終了。 nEnd = i; // nEndは終わりの次の文字(') break; } if( i == nLineLen ){ // 行末に来てしまった ::MYMESSAGEBOX( NULL, MB_OK | MB_ICONSTOP | MB_TOPMOST, MACRO_ERROR_TITLE, LS(STR_ERR_DLGKEYMACMGR5), line, szFuncName, nArgs + 1, cQuote ); m_nReady = false; nEnd = i - 1; // nEndは終わりの次の文字(') break; } } // Jun. 16, 2002 genta if( !m_nReady ){ break; } CNativeW cmemWork; cmemWork.SetString( strLine.c_str() + nBgn, nEnd - nBgn ); // 2014.01.28 「"\\'"」のような場合の不具合を修正 cmemWork.Replace( L"\\\\", L"\\\1" ); // 一時置換(最初に必要) cmemWork.Replace( LTEXT("\\\'"), LTEXT("\'") ); // Jun. 16, 2002 genta double quotationもエスケープ解除 cmemWork.Replace( LTEXT("\\\""), LTEXT("\"") ); cmemWork.Replace( L"\\r", L"\r" ); cmemWork.Replace( L"\\n", L"\n" ); cmemWork.Replace( L"\\t", L"\t" ); { // \uXXXX 置換 size_t nLen = cmemWork.GetStringLength(); size_t nBegin = 0; const wchar_t* p = cmemWork.GetStringPtr(); CNativeW cmemTemp; for( size_t n = 0; n < nLen; n++ ){ if( n + 1 < nLen && p[n] == L'\\' && p[n+1] == L'u' ){ size_t k; for( k = n + 2; k < nLen && k < n + 2 + 4 && (WCODE::Is09(p[k]) || (L'a' <= p[k] && p[k] <= L'f') || (L'A' <= p[k] && p[k] <= L'F')); k++ ){ } cmemTemp.AppendString( p + nBegin, n - nBegin ); nBegin = k; if( 0 < k - n - 2 ){ wchar_t hex[5]; wcsncpy( hex, &p[n+2], k - n - 2 ); hex[k - n - 2] = L'\0'; wchar_t* pEnd = NULL; wchar_t c = static_cast<wchar_t>(wcstol(hex, &pEnd, 16)); cmemTemp.AppendString( &c, 1 ); } n = k - 1; } } if( nBegin != 0 ){ if( 0 < nLen - nBegin ){ cmemTemp.AppendString( p + nBegin, nLen - nBegin ); } cmemWork.swap( cmemTemp ); } } cmemWork.Replace( L"\\\1", L"\\" ); // 一時置換を\に戻す(最後でないといけない) macro->AddStringParam( cmemWork.GetStringPtr(), cmemWork.GetStringLength() ); // 引数を文字列として追加 } else if ( Is09(szLine[i]) || szLine[i] == L'-' ){ // 数字で始まったら数字列だ(-記号も含む)。 // Jun. 16, 2002 genta プロトタイプチェック // Jun. 27, 2002 genta 余分な引数を無視するよう,VT_EMPTYを許容する. if( type != VT_I4 && type != VT_EMPTY){ ::MYMESSAGEBOX( NULL, MB_OK | MB_ICONSTOP | MB_TOPMOST, MACRO_ERROR_TITLE, LS(STR_ERR_DLGKEYMACMGR6), line, i + 1, szFuncName, nArgs + 1 ); m_nReady = false; break; } nBgn = nEnd = i; // nBgnは引数の先頭の文字 // 行末の検出のため,ループ回数を1増やした for( i = nBgn + 1; i <= nLineLen; ++i ){ // 最後の文字+1までスキャン if( Is09(szLine[i]) ){ // まだ数値 // ++i; continue; } else { nEnd = i; // 数字の最後の文字 i--; break; } } CNativeW cmemWork; cmemWork.SetString( strLine.c_str() + nBgn, nEnd - nBgn ); // Jun. 16, 2002 genta // 数字の中にquotationは入っていないよ //cmemWork.Replace( L"\\\'", L"\'" ); //cmemWork.Replace( L"\\\\", L"\\" ); macro->AddIntParam( _wtoi(cmemWork.GetStringPtr()) ); // 引数を数字として追加 } // Jun. 16, 2002 genta else if( szLine[i] == LTEXT(')') ){ // 引数無し break; } else { // Parse Error:文法エラーっぽい。 // Jun. 16, 2002 genta nBgn = nEnd = i; ::MYMESSAGEBOX( NULL, MB_OK | MB_ICONSTOP | MB_TOPMOST, MACRO_ERROR_TITLE, LS(STR_ERR_DLGKEYMACMGR7), line, i + 1 ); m_nReady = false; break; } for( ; i < nLineLen; ++i ){ // 最後の文字までスキャン if( szLine[i] == LTEXT(')') || szLine[i] == LTEXT(',') ){ // ,もしくは)を読み飛ばす i++; break; } } if (szLine[i-1] == LTEXT(')')){ break; } } // Jun. 16, 2002 genta if( !m_nReady ){ // どこかでエラーがあったらしい delete macro; break; } /* キーマクロのバッファにデータ追加 */ Append( macro ); } else { ::MYMESSAGEBOX( NULL, MB_OK | MB_ICONSTOP | MB_TOPMOST, MACRO_ERROR_TITLE, LS(STR_ERR_DLGKEYMACMGR8), line, szFuncName ); // Jun. 16, 2002 genta m_nReady = false; break; } } in.Close(); // Jun. 16, 2002 genta // マクロ中にエラーがあったら異常終了できるようにする. return m_nReady ? TRUE : FALSE; }