1
0
mirror of synced 2026-01-26 19:21:32 +03:00
Files
bkbtl/emulator/Common.cpp
2023-07-01 00:21:45 +03:00

375 lines
11 KiB
C++

/* This file is part of BKBTL.
BKBTL is free software: you can redistribute it and/or modify it under the terms
of the GNU Lesser General Public License as published by the Free Software Foundation,
either version 3 of the License, or (at your option) any later version.
BKBTL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with
BKBTL. If not, see <http://www.gnu.org/licenses/>. */
// Common.cpp
#include "stdafx.h"
#include "Main.h"
#include "Views.h"
//////////////////////////////////////////////////////////////////////
BOOL AssertFailedLine(LPCSTR lpszFileName, int nLine)
{
TCHAR buffer[360];
_sntprintf(buffer, sizeof(buffer) / sizeof(TCHAR) - 1,
_T("ASSERTION FAILED\n\nFile: %S\nLine: %d\n\n")
_T("Press Abort to stop the program, Retry to break to the debugger, or Ignore to continue execution."),
lpszFileName, nLine);
int result = MessageBox(NULL, buffer, _T("ASSERT"), MB_ICONSTOP | MB_ABORTRETRYIGNORE);
switch (result)
{
case IDRETRY:
return TRUE;
case IDIGNORE:
return FALSE;
case IDABORT:
PostQuitMessage(255);
}
return FALSE;
}
void AlertInfo(LPCTSTR sMessage)
{
::MessageBox(NULL, sMessage, g_szTitle, MB_OK | MB_ICONINFORMATION | MB_TOPMOST);
}
void AlertWarning(LPCTSTR sMessage)
{
::MessageBox(NULL, sMessage, g_szTitle, MB_OK | MB_ICONEXCLAMATION | MB_TOPMOST);
}
void AlertWarningFormat(LPCTSTR sFormat, ...)
{
const size_t buffersize = 512;
TCHAR buffer[buffersize];
va_list ptr;
va_start(ptr, sFormat);
_vsntprintf_s(buffer, buffersize, buffersize - 1, sFormat, ptr);
va_end(ptr);
::MessageBox(NULL, buffer, g_szTitle, MB_OK | MB_ICONEXCLAMATION | MB_TOPMOST);
}
BOOL AlertOkCancel(LPCTSTR sMessage)
{
int result = ::MessageBox(NULL, sMessage, g_szTitle, MB_OKCANCEL | MB_ICONQUESTION | MB_TOPMOST);
return (result == IDOK);
}
//////////////////////////////////////////////////////////////////////
// DebugPrint and DebugLog
#if defined(PRODUCT)
void DebugPrint(LPCTSTR) {}
void DebugPrintFormat(LPCTSTR, ...) {}
void DebugLogClear() {}
void DebugLogCloseFile() {}
void DebugLog(LPCTSTR) {}
void DebugLogFormat(LPCTSTR, ...) {}
#else
void DebugPrint(LPCTSTR message)
{
if (g_hwndConsole == NULL)
return;
ConsoleView_Print(message);
}
void DebugPrintFormat(LPCTSTR pszFormat, ...)
{
const size_t buffersize = 512;
TCHAR buffer[buffersize];
va_list ptr;
va_start(ptr, pszFormat);
_vsntprintf_s(buffer, buffersize, buffersize - 1, pszFormat, ptr);
va_end(ptr);
DebugPrint(buffer);
}
const LPCTSTR TRACELOG_FILE_NAME = _T("trace.log");
const LPCTSTR TRACELOG_NEWLINE = _T("\r\n");
HANDLE Common_LogFile = NULL;
void DebugLogCreateFile()
{
if (Common_LogFile == NULL)
{
Common_LogFile = ::CreateFile(TRACELOG_FILE_NAME,
GENERIC_WRITE, FILE_SHARE_READ, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
}
}
void DebugLogCloseFile()
{
if (Common_LogFile == NULL)
return;
::CloseHandle(Common_LogFile);
Common_LogFile = NULL;
}
void DebugLogClear()
{
DebugLogCreateFile();
if (Common_LogFile != NULL)
{
// Trunkate to zero length
::SetFilePointer(Common_LogFile, 0, 0, 0);
::SetEndOfFile(Common_LogFile);
}
}
void DebugLog(LPCTSTR message)
{
DebugLogCreateFile();
SetFilePointer(Common_LogFile, 0, NULL, FILE_END);
int nLength = lstrlen(message) * sizeof(TCHAR);
char ascii[256]; *ascii = 0;
WideCharToMultiByte(CP_ACP, 0, message, nLength, ascii, 256, NULL, NULL);
DWORD dwBytesWritten = 0;
//WriteFile(Common_LogFile, message, dwLength, &dwBytesWritten, NULL);
WriteFile(Common_LogFile, ascii, strlen(ascii), &dwBytesWritten, NULL);
//dwLength = lstrlen(TRACELOG_NEWLINE) * sizeof(TCHAR);
//WriteFile(Common_LogFile, TRACELOG_NEWLINE, dwLength, &dwBytesWritten, NULL);
}
void DebugLogFormat(LPCTSTR pszFormat, ...)
{
const size_t buffersize = 512;
TCHAR buffer[buffersize];
va_list ptr;
va_start(ptr, pszFormat);
_vsntprintf_s(buffer, buffersize, buffersize - 1, pszFormat, ptr);
va_end(ptr);
DebugLog(buffer);
}
#endif // !defined(PRODUCT)
//////////////////////////////////////////////////////////////////////
// Названия регистров процессора
const TCHAR* REGISTER_NAME[] = { _T("R0"), _T("R1"), _T("R2"), _T("R3"), _T("R4"), _T("R5"), _T("SP"), _T("PC") };
HFONT CreateMonospacedFont()
{
HFONT font;
LOGFONT logfont; memset(&logfont, 0, sizeof(logfont));
logfont.lfHeight = 12;
logfont.lfWeight = FW_NORMAL;
logfont.lfCharSet = DEFAULT_CHARSET;
logfont.lfOutPrecision = OUT_DEFAULT_PRECIS;
logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
logfont.lfQuality = DEFAULT_QUALITY;
logfont.lfPitchAndFamily = FIXED_PITCH;
Settings_GetDebugFontName(logfont.lfFaceName);
font = CreateFontIndirect(&logfont);
if (font != NULL)
return font;
_tcscpy_s(logfont.lfFaceName, 32, _T("Lucida Console"));
font = CreateFontIndirect(&logfont);
if (font != NULL)
return font;
_tcscpy_s(logfont.lfFaceName, 32, _T("Courier"));
font = CreateFontIndirect(&logfont);
if (font != NULL)
return font;
return NULL;
}
HFONT CreateDialogFont()
{
HFONT font = CreateFont(
14, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
VARIABLE_PITCH,
_T("MS Shell Dlg 2"));
return font;
}
void GetFontWidthAndHeight(HDC hdc, int* pWidth, int* pHeight)
{
TEXTMETRIC tm;
GetTextMetrics(hdc, &tm);
if (pWidth != NULL)
*pWidth = tm.tmAveCharWidth;
if (pHeight != NULL)
*pHeight = tm.tmHeight;
}
// Print octal 16-bit value to buffer
// buffer size at least 7 characters
void PrintOctalValue(TCHAR* buffer, WORD value)
{
for (int p = 0; p < 6; p++)
{
int digit = value & 7;
buffer[5 - p] = _T('0') + (TCHAR)digit;
value = (value >> 3);
}
buffer[6] = 0;
}
// Print hex 16-bit value to buffer
// buffer size at least 5 characters
void PrintHexValue(TCHAR* buffer, WORD value)
{
for (int p = 0; p < 4; p++)
{
int digit = value & 15;
buffer[3 - p] = (digit < 10) ? _T('0') + (TCHAR)digit : _T('a') + (TCHAR)(digit - 10);
value = (value >> 4);
}
buffer[4] = 0;
}
// Print binary 16-bit value to buffer
// buffer size at least 17 characters
void PrintBinaryValue(TCHAR* buffer, WORD value)
{
for (int b = 0; b < 16; b++)
{
int bit = (value >> b) & 1;
buffer[15 - b] = bit ? _T('1') : _T('0');
}
buffer[16] = 0;
}
// Parse octal value from text
BOOL ParseOctalValue(LPCTSTR text, WORD* pValue)
{
WORD value = 0;
TCHAR* pChar = (TCHAR*) text;
for (int p = 0; ; p++)
{
if (p > 6) return FALSE;
TCHAR ch = *pChar; pChar++;
if (ch == 0) break;
if (ch < _T('0') || ch > _T('7')) return FALSE;
value = (value << 3);
TCHAR digit = ch - _T('0');
value += digit;
}
*pValue = value;
return TRUE;
}
void DrawOctalValue(HDC hdc, int x, int y, WORD value)
{
TCHAR buffer[7];
PrintOctalValue(buffer, value);
TextOut(hdc, x, y, buffer, (int) _tcslen(buffer));
}
void DrawHexValue(HDC hdc, int x, int y, WORD value)
{
TCHAR buffer[7];
PrintHexValue(buffer, value);
TextOut(hdc, x, y, buffer, (int) _tcslen(buffer));
}
void DrawBinaryValue(HDC hdc, int x, int y, WORD value)
{
TCHAR buffer[17];
PrintBinaryValue(buffer, value);
TextOut(hdc, x, y, buffer, 16);
}
void CopyTextToClipboard(LPCTSTR text)
{
ASSERT(text != nullptr);
size_t bufferLength = (_tcslen(text) + 1) * sizeof(TCHAR);
// Prepare global memory object for the text
HGLOBAL hglbCopy = ::GlobalAlloc(GMEM_MOVEABLE, bufferLength);
LPTSTR lptstrCopy = (LPTSTR)::GlobalLock(hglbCopy);
memcpy(lptstrCopy, text, bufferLength);
::GlobalUnlock(hglbCopy);
// Send the text to the Clipboard
::OpenClipboard(g_hwnd);
::EmptyClipboard();
::SetClipboardData(CF_UNICODETEXT, hglbCopy);
::CloseClipboard();
}
// BK to Unicode conversion table
const TCHAR BK_CHAR_CODES[] =
{
0x3C0, 0x2534, 0x2665, 0x2510, 0x2561, 0x251C, 0x2514, 0x2550, 0x2564, 0x2660, 0x250C, 0x252C, 0x2568, 0x2193, 0x253C, 0x2551,
0x2524, 0x2190, 0x256C, 0x2191, 0x2663, 0x2500, 0x256B, 0x2502, 0x2666, 0x2518, 0x256A, 0x2565, 0x2567, 0x255E, 0x2192, 0x2593,
0x44E, 0x430, 0x431, 0x446, 0x434, 0x435, 0x444, 0x433, 0x445, 0x438, 0x439, 0x43A, 0x43B, 0x43C, 0x43D, 0x43E,
0x43F, 0x44F, 0x440, 0x441, 0x442, 0x443, 0x436, 0x432, 0x44C, 0x44B, 0x437, 0x448, 0x44D, 0x449, 0x447, 0x44A,
0x42E, 0x410, 0x411, 0x426, 0x414, 0x415, 0x424, 0x413, 0x425, 0x418, 0x419, 0x41A, 0x41B, 0x41C, 0x41D, 0x41E,
0x41F, 0x42F, 0x420, 0x421, 0x422, 0x423, 0x416, 0x412, 0x42C, 0x42B, 0x417, 0x428, 0x42D, 0x429, 0x427, 0x42A,
};
// Translate one KOI8-R character to Unicode character
TCHAR Translate_BK_Unicode(BYTE ch)
{
if (ch < 32) return _T('·');
if (ch < 127) return (TCHAR) ch;
if (ch == 127) return (TCHAR) 0x25A0;
if (/*ch >= 128 &&*/ ch < 160) return _T('·');
return BK_CHAR_CODES[ch - 160];
}
// KOI7-R (Russian) to Unicode conversion table
const TCHAR KOI7R_CODES[] =
{
0x44E, 0x430, 0x431, 0x446, 0x434, 0x435, 0x444, 0x433, 0x445, 0x438, 0x439, 0x43A, 0x43B, 0x43C, 0x43D, 0x43E,
0x43F, 0x44F, 0x440, 0x441, 0x442, 0x443, 0x436, 0x432, 0x44C, 0x44B, 0x437, 0x448, 0x44D, 0x449, 0x447, 0x44A,
0x42E, 0x410, 0x411, 0x426, 0x414, 0x415, 0x424, 0x413, 0x425, 0x418, 0x419, 0x41A, 0x41B, 0x41C, 0x41D, 0x41E,
0x41F, 0x42F, 0x420, 0x421, 0x422, 0x423, 0x416, 0x412, 0x42C, 0x42B, 0x417, 0x428, 0x42D, 0x429, 0x427, 0x42A,
};
// Translate one KOI7 character to Cyrillic Unicode character
TCHAR Translate_KOI7R_Unicode(BYTE ch)
{
if (ch < 64 || ch >= 128) return (TCHAR) ch;
return KOI7R_CODES[ch - 64];
}
//////////////////////////////////////////////////////////////////////
// Path funcations
LPCTSTR GetFileNameFromFilePath(LPCTSTR lpfilepath)
{
LPCTSTR lpfilename = _tcsrchr(lpfilepath, _T('\\'));
if (lpfilename == NULL)
return lpfilepath;
else
return lpfilename + 1;
}
//////////////////////////////////////////////////////////////////////