1980 lines
44 KiB
C
1980 lines
44 KiB
C
/*
|
|
* kml.c
|
|
*
|
|
* This file is part of Emu48
|
|
*
|
|
* Copyright (C) 1995 Sebastien Carlier
|
|
*
|
|
*/
|
|
#include "pch.h"
|
|
#include "resource.h"
|
|
#include "Emu48.h"
|
|
#include "kml.h"
|
|
|
|
static VOID FatalError();
|
|
static VOID InitLex(LPSTR szScript);
|
|
static VOID CleanLex();
|
|
static BOOL IsDigit(CHAR cChar);
|
|
static VOID SkipWhite(UINT nMode);
|
|
static TokenId ParseToken(UINT nMode);
|
|
static DWORD ParseInteger();
|
|
static LPSTR ParseString();
|
|
static TokenId Lex(UINT nMode);
|
|
static Line* ParseLine(TokenId eCommand);
|
|
static Line* IncludeLines(LPCSTR szFilename);
|
|
static Line* ParseLines();
|
|
static Block* ParseBlock(TokenId eBlock);
|
|
static Block* IncludeBlocks(LPCSTR szFilename);
|
|
static Block* ParseBlocks();
|
|
static VOID FreeLines(Line* pLine);
|
|
static VOID PressButton(UINT nId);
|
|
static VOID ReleaseButton(UINT nId);
|
|
static VOID PressButtonById(UINT nId);
|
|
static VOID ReleaseButtonById(UINT nId);
|
|
static LPSTR GetStringParam(Block* pBlock, TokenId eBlock, enum eCommand, UINT nParam);
|
|
static DWORD GetIntegerParam(Block* pBlock, TokenId eBlock, enum eCommand, UINT nParam);
|
|
static Line* SkipLines(Line* pLine, enum eCommand);
|
|
static Line* If(Line* pLine, BOOL bCondition);
|
|
static Line* RunLine(Line* pLine);
|
|
static Block* LoadKMLGlobal(LPCSTR szFilename);
|
|
|
|
Block* pKml;
|
|
static Block* pVKey[256];
|
|
static BYTE byVKeyMap[256];
|
|
static Button pButton[256];
|
|
static Annunciator pAnnunciator[6];
|
|
static UINT nButtons = 0;
|
|
static UINT nScancodes = 0;
|
|
static UINT nAnnunciators = 0;
|
|
static BOOL bDebug = TRUE;
|
|
static UINT nLexLine;
|
|
static UINT nLexInteger;
|
|
static UINT nBlocksIncludeLevel;
|
|
static UINT nLinesIncludeLevel;
|
|
static DWORD nKMLFlags = 0;
|
|
static LPSTR szLexString;
|
|
static LPSTR szText;
|
|
static LPSTR szLexDelim[] =
|
|
{
|
|
"",
|
|
" \t\n\r",
|
|
" \t\n\r",
|
|
" \t\r"
|
|
};
|
|
|
|
static Token pLexToken[] =
|
|
{
|
|
{TOK_ANNUNCIATOR,000001,11,"Annunciator"},
|
|
{TOK_BACKGROUND, 000000,10,"Background"},
|
|
{TOK_IFPRESSED, 000001, 9,"IfPressed"},
|
|
{TOK_RESETFLAG, 000001, 9,"ResetFlag"},
|
|
{TOK_SCANCODE, 000001, 8,"Scancode"},
|
|
{TOK_MENUITEM, 000001, 8,"MenuItem"},
|
|
{TOK_SETFLAG, 000001, 7,"SetFlag"},
|
|
{TOK_RELEASE, 000001, 7,"Release"},
|
|
{TOK_VIRTUAL, 000000, 7,"Virtual"},
|
|
{TOK_INCLUDE, 000002, 7,"Include"},
|
|
{TOK_NOTFLAG, 000001, 7,"NotFlag"},
|
|
{TOK_GLOBAL, 000000, 6,"Global"},
|
|
{TOK_AUTHOR, 000002, 6,"Author"},
|
|
{TOK_BITMAP, 000002, 6,"Bitmap"},
|
|
{TOK_OFFSET, 000011, 6,"Offset"},
|
|
{TOK_BUTTON, 000001, 6,"Button"},
|
|
{TOK_IFFLAG, 000001, 6,"IfFlag"},
|
|
{TOK_ONDOWN, 000000, 6,"OnDown"},
|
|
{TOK_NOHOLD, 000000, 6,"NoHold"},
|
|
{TOK_TITLE, 000002, 5,"Title"},
|
|
{TOK_OUTIN, 000011, 5,"OutIn"},
|
|
{TOK_PATCH, 000002, 5,"Patch"},
|
|
{TOK_PRINT, 000002, 5,"Print"},
|
|
{TOK_DEBUG, 000001, 5,"Debug"},
|
|
{TOK_COLOR, 001111, 5,"Color"},
|
|
{TOK_MODEL, 000002, 5,"Model"},
|
|
{TOK_PRESS, 000001, 5,"Press"},
|
|
{TOK_TYPE, 000001, 4,"Type"},
|
|
{TOK_SIZE, 000011, 4,"Size"},
|
|
{TOK_ZOOM, 000001, 4,"Zoom"},
|
|
{TOK_DOWN, 000011, 4,"Down"},
|
|
{TOK_ELSE, 000000, 4,"Else"},
|
|
{TOK_ONUP, 000000, 4,"OnUp"},
|
|
{TOK_MAP, 000011, 3,"Map"},
|
|
{TOK_ROM, 000002, 3,"Rom"},
|
|
{TOK_LCD, 000000, 3,"Lcd"},
|
|
{TOK_END, 000000, 3,"End"},
|
|
{0, 000000, 0,""},
|
|
};
|
|
|
|
static TokenId eIsBlock[] =
|
|
{
|
|
TOK_IFFLAG,
|
|
TOK_IFPRESSED,
|
|
TOK_ONDOWN,
|
|
TOK_ONUP,
|
|
TOK_NONE
|
|
};
|
|
|
|
static BOOL bClicking = FALSE;
|
|
static UINT uButtonClicked = 0;
|
|
|
|
static BOOL bPressed = FALSE; // 01.10.97 cg, no key pressed
|
|
static UINT uLastPressedKey = 0; // 01.10.97 cg, var for last pressed key
|
|
|
|
//################
|
|
//#
|
|
//# Compilation Result
|
|
//#
|
|
//################
|
|
|
|
static UINT nLogLength = 0;
|
|
static LPSTR szLog = NULL;
|
|
static BOOL bKmlLogOkEnabled = FALSE;
|
|
|
|
static VOID ClearLog()
|
|
{
|
|
nLogLength = 0;
|
|
if (szLog != NULL)
|
|
{
|
|
LocalFree(szLog);
|
|
szLog = NULL;
|
|
}
|
|
return;
|
|
}
|
|
|
|
static VOID AddToLog(LPSTR szString)
|
|
{
|
|
UINT nLength = strlen(szString);
|
|
if (szLog == NULL)
|
|
{
|
|
nLogLength = nLength+3;
|
|
szLog = LocalAlloc(0,nLogLength);
|
|
if (szLog==NULL)
|
|
{
|
|
nLogLength = 0;
|
|
return;
|
|
}
|
|
lstrcpy(szLog,szString);
|
|
}
|
|
else
|
|
{
|
|
szLog = LocalReAlloc(szLog,nLogLength+nLength+2,LMEM_MOVEABLE);
|
|
if (szLog == NULL)
|
|
{
|
|
nLogLength = 0;
|
|
return;
|
|
}
|
|
lstrcpy(szLog+nLogLength-1,szString);
|
|
nLogLength += nLength+2;
|
|
}
|
|
szLog[nLogLength-3] = 0x0D;
|
|
szLog[nLogLength-2] = 0x0A;
|
|
szLog[nLogLength-1] = 0;
|
|
return;
|
|
}
|
|
|
|
static VOID __cdecl PrintfToLog(LPCTSTR lpFormat, ...)
|
|
{
|
|
LPSTR lpOutput;
|
|
va_list arglist;
|
|
|
|
va_start(arglist,lpFormat);
|
|
lpOutput = LocalAlloc(0,1024);
|
|
wvsprintf(lpOutput,lpFormat,arglist);
|
|
AddToLog(lpOutput);
|
|
LocalFree(lpOutput);
|
|
va_end(arglist);
|
|
return;
|
|
}
|
|
|
|
static BOOL CALLBACK KMLLogProc(HWND hDlg, UINT message, DWORD wParam, LONG lParam)
|
|
{
|
|
LPSTR szString;
|
|
|
|
switch (message)
|
|
{
|
|
case WM_INITDIALOG:
|
|
// set OK
|
|
EnableWindow(GetDlgItem(hDlg,IDOK),bKmlLogOkEnabled);
|
|
// set IDC_TITLE
|
|
szString = GetStringParam(pKml, TOK_GLOBAL, TOK_TITLE, 0);
|
|
if (szString == NULL) szString = "Untitled";
|
|
SetDlgItemText(hDlg,IDC_TITLE,szString);
|
|
// set IDC_AUTHOR
|
|
szString = GetStringParam(pKml, TOK_GLOBAL, TOK_AUTHOR, 0);
|
|
if (szString == NULL) szString = "<Unknown Author>";
|
|
SetDlgItemText(hDlg,IDC_AUTHOR,szString);
|
|
// set IDC_KMLLOG
|
|
if (szLog == NULL)
|
|
SetDlgItemText(hDlg,IDC_KMLLOG,"Memory Allocation Failure.");
|
|
else
|
|
SetDlgItemText(hDlg,IDC_KMLLOG,szLog);
|
|
// set IDC_ALWAYSDISPLOG
|
|
CheckDlgButton(hDlg,IDC_ALWAYSDISPLOG,bAlwaysDisplayLog);
|
|
// redraw window
|
|
InvalidateRect(hDlg, NULL, TRUE);
|
|
return TRUE;
|
|
case WM_COMMAND:
|
|
bAlwaysDisplayLog = IsDlgButtonChecked(hDlg, IDC_ALWAYSDISPLOG);
|
|
if ((wParam == IDCANCEL)||(wParam == IDOK)) EndDialog(hDlg, wParam);
|
|
break;
|
|
}
|
|
return FALSE;
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
UNREFERENCED_PARAMETER(hDlg);
|
|
}
|
|
|
|
BOOL DisplayKMLLog(BOOL bOkEnabled)
|
|
{
|
|
BOOL bResult;
|
|
bKmlLogOkEnabled = bOkEnabled;
|
|
bResult = DialogBox(hApp, MAKEINTRESOURCE(IDD_KMLLOG), hWnd, (DLGPROC)KMLLogProc);
|
|
return (bResult == IDOK);
|
|
}
|
|
|
|
|
|
|
|
//################
|
|
//#
|
|
//# Choose Script
|
|
//#
|
|
//################
|
|
|
|
typedef struct _KmlScript
|
|
{
|
|
LPSTR szFilename;
|
|
LPSTR szTitle;
|
|
DWORD nId;
|
|
struct _KmlScript* pNext;
|
|
} KmlScript;
|
|
|
|
static UINT nKmlFiles;
|
|
static KmlScript* pKmlList;
|
|
static CHAR cKmlType;
|
|
|
|
static VOID DestroyKmlList()
|
|
{
|
|
KmlScript* pList;
|
|
|
|
while (pKmlList)
|
|
{
|
|
pList = pKmlList->pNext;
|
|
LocalFree(pKmlList->szFilename);
|
|
LocalFree(pKmlList->szTitle);
|
|
LocalFree(pKmlList);
|
|
pKmlList = pList;
|
|
}
|
|
nKmlFiles = 0;
|
|
}
|
|
|
|
static VOID CreateKmlList()
|
|
{
|
|
HANDLE hFindFile;
|
|
WIN32_FIND_DATA pFindFileData;
|
|
|
|
SetCurrentDirectory(szEmu48Directory);
|
|
hFindFile = FindFirstFile("*.KML",&pFindFileData);
|
|
SetCurrentDirectory(szCurrentDirectory);
|
|
nKmlFiles = 0;
|
|
if (hFindFile == INVALID_HANDLE_VALUE) return;
|
|
do
|
|
{
|
|
KmlScript* pScript;
|
|
Block* pBlock;
|
|
LPSTR szTitle;
|
|
|
|
pBlock = LoadKMLGlobal(pFindFileData.cFileName);
|
|
if (pBlock == NULL) continue;
|
|
if (cKmlType)
|
|
{
|
|
szTitle = GetStringParam(pBlock,TOK_GLOBAL,TOK_MODEL,0);
|
|
if ((!szTitle)||(szTitle[0]!=cKmlType))
|
|
{
|
|
FreeBlocks(pBlock);
|
|
continue;
|
|
}
|
|
}
|
|
pScript = LocalAlloc(0, sizeof(KmlScript));
|
|
pScript->szFilename = DuplicateString(pFindFileData.cFileName);
|
|
szTitle = GetStringParam(pBlock,TOK_GLOBAL,TOK_TITLE,0);
|
|
if (szTitle == NULL) szTitle = DuplicateString(pScript->szFilename);
|
|
pScript->szTitle = DuplicateString(szTitle);
|
|
FreeBlocks(pBlock);
|
|
pScript->nId = nKmlFiles;
|
|
pScript->pNext = pKmlList;
|
|
pKmlList = pScript;
|
|
nKmlFiles++;
|
|
} while (FindNextFile(hFindFile,&pFindFileData));
|
|
FindClose(hFindFile);
|
|
return;
|
|
};
|
|
|
|
static BOOL CALLBACK ChooseKMLProc(HWND hDlg, UINT message, DWORD wParam, LONG lParam)
|
|
{
|
|
HWND hList;
|
|
KmlScript* pList;
|
|
UINT nIndex;
|
|
|
|
switch (message)
|
|
{
|
|
case WM_INITDIALOG:
|
|
SetDlgItemText(hDlg,IDC_EMU48DIR,szEmu48Directory);
|
|
hList = GetDlgItem(hDlg,IDC_KMLSCRIPT);
|
|
SendMessage(hList, CB_RESETCONTENT, 0, 0);
|
|
pList = pKmlList;
|
|
while (pList)
|
|
{
|
|
nIndex = SendMessage(hList, CB_ADDSTRING, 0, (LPARAM)pList->szTitle);
|
|
SendMessage(hList, CB_SETITEMDATA, nIndex, (LPARAM)pList->nId);
|
|
pList = pList->pNext;
|
|
}
|
|
SendMessage(hList, CB_SETCURSEL, 0, 0);
|
|
return TRUE;
|
|
case WM_SETTEXT:
|
|
{
|
|
CHAR szBuffer[80];
|
|
wsprintf(szBuffer,"%i %i %i", hDlg, wParam, lParam);
|
|
InfoMessage(szBuffer);
|
|
}
|
|
break;
|
|
case WM_COMMAND:
|
|
if (wParam == IDC_UPDATE)
|
|
{
|
|
DestroyKmlList();
|
|
// 01.02.98 cg, calculate size of buffer
|
|
GetDlgItemText(hDlg,IDC_EMU48DIR,szEmu48Directory,sizeof(szEmu48Directory));
|
|
CreateKmlList();
|
|
hList = GetDlgItem(hDlg,IDC_KMLSCRIPT);
|
|
SendMessage(hList, CB_RESETCONTENT, 0, 0);
|
|
pList = pKmlList;
|
|
while (pList)
|
|
{
|
|
nIndex = SendMessage(hList, CB_ADDSTRING, 0, (LPARAM)pList->szTitle);
|
|
SendMessage(hList, CB_SETITEMDATA, nIndex, (LPARAM)pList->nId);
|
|
pList = pList->pNext;
|
|
}
|
|
SendMessage(hList, CB_SETCURSEL, 0, 0);
|
|
break;
|
|
}
|
|
if (wParam == IDOK)
|
|
{
|
|
// 01.02.98 cg, calculate size of buffer
|
|
GetDlgItemText(hDlg,IDC_EMU48DIR,szEmu48Directory,sizeof(szEmu48Directory));
|
|
hList = GetDlgItem(hDlg,IDC_KMLSCRIPT);
|
|
nIndex = SendMessage(hList, CB_GETCURSEL, 0, 0);
|
|
nIndex = SendMessage(hList, CB_GETITEMDATA, nIndex, 0);
|
|
pList = pKmlList;
|
|
while (pList)
|
|
{
|
|
if (pList->nId == nIndex) break;
|
|
pList = pList->pNext;
|
|
}
|
|
if (pList)
|
|
{
|
|
lstrcpy(szCurrentKml, pList->szFilename);
|
|
EndDialog(hDlg, IDOK);
|
|
}
|
|
break;
|
|
}
|
|
if (wParam == IDCANCEL)
|
|
{
|
|
EndDialog(hDlg, IDCANCEL);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
return FALSE;
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
UNREFERENCED_PARAMETER(hDlg);
|
|
}
|
|
|
|
BOOL DisplayChooseKml(CHAR cType)
|
|
{
|
|
BOOL bResult;
|
|
cKmlType = cType;
|
|
CreateKmlList();
|
|
bResult = DialogBox(hApp, MAKEINTRESOURCE(IDD_CHOOSEKML), hWnd, (DLGPROC)ChooseKMLProc);
|
|
DestroyKmlList();
|
|
return (bResult == IDOK);
|
|
}
|
|
|
|
|
|
|
|
//################
|
|
//#
|
|
//# Script Parsing
|
|
//#
|
|
//################
|
|
|
|
static VOID FatalError()
|
|
{
|
|
PrintfToLog("Fatal Error at line %i", nLexLine);
|
|
szText[0] = 0;
|
|
return;
|
|
}
|
|
|
|
static VOID InitLex(LPSTR szScript)
|
|
{
|
|
nLexLine = 1;
|
|
szText = szScript;
|
|
return;
|
|
}
|
|
|
|
static VOID CleanLex()
|
|
{
|
|
nLexLine = 0;
|
|
nLexInteger = 0;
|
|
szLexString = NULL;
|
|
szText = NULL;
|
|
return;
|
|
}
|
|
|
|
// TODO: Change this poor (and slow!) code
|
|
static BOOL IsBlock(TokenId eId)
|
|
{
|
|
UINT uBlock = 0;
|
|
while (eIsBlock[uBlock] != TOK_NONE)
|
|
{
|
|
if (eId == eIsBlock[uBlock]) return TRUE;
|
|
uBlock++;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
static LPCTSTR GetStringOf(TokenId eId)
|
|
{
|
|
UINT i = 0;
|
|
while (pLexToken[i].nLen)
|
|
{
|
|
if (pLexToken[i].eId == eId) return pLexToken[i].szName;
|
|
i++;
|
|
}
|
|
return "<Undefined>";
|
|
}
|
|
|
|
static BOOL IsDigit(CHAR cChar)
|
|
{
|
|
if (cChar<'0') return FALSE;
|
|
if (cChar>'9') return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
static VOID SkipWhite(UINT nMode)
|
|
{
|
|
UINT i;
|
|
BOOL bStop = FALSE;
|
|
loop:
|
|
i = 0;
|
|
while (szLexDelim[nMode][i])
|
|
{
|
|
if (*szText == szLexDelim[nMode][i]) break;
|
|
i++;
|
|
}
|
|
if (szLexDelim[nMode][i] != 0)
|
|
{
|
|
if (szLexDelim[nMode][i]=='\n') nLexLine++;
|
|
szText++;
|
|
goto loop;
|
|
}
|
|
if (*szText=='#')
|
|
{
|
|
do szText++; while (*szText != '\n');
|
|
if (nMode != LEX_PARAM) goto loop;
|
|
}
|
|
return;
|
|
}
|
|
|
|
static TokenId ParseToken(UINT nMode)
|
|
{
|
|
UINT i, j, k;
|
|
i = 0;
|
|
while (szText[i])
|
|
{
|
|
j = 0;
|
|
while (szLexDelim[nMode][j])
|
|
{
|
|
if (szLexDelim[nMode][j] == szText[i]) break;
|
|
j++;
|
|
}
|
|
if (szLexDelim[nMode][j] == '\n') nLexLine++;
|
|
if (szLexDelim[nMode][j] != 0) break;
|
|
i++;
|
|
}
|
|
if (i==0)
|
|
{
|
|
return TOK_NONE;
|
|
}
|
|
j = 0;
|
|
while (pLexToken[j].nLen)
|
|
{
|
|
if (pLexToken[j].nLen>i)
|
|
{
|
|
j++;
|
|
continue;
|
|
}
|
|
if (pLexToken[j].nLen<i) break;
|
|
k = 0;
|
|
if (strncmp(pLexToken[j].szName, szText, i)==0)
|
|
{
|
|
szText += i;
|
|
return pLexToken[j].eId;
|
|
}
|
|
j++;
|
|
}
|
|
szText[i] = 0;
|
|
if (bDebug)
|
|
{
|
|
PrintfToLog("%i: Undefined token %s", nLexLine, szText);
|
|
return TOK_NONE;
|
|
}
|
|
return TOK_NONE;
|
|
}
|
|
|
|
static DWORD ParseInteger()
|
|
{
|
|
DWORD nNum = 0;
|
|
while (IsDigit(*szText))
|
|
{
|
|
nNum = nNum*10 + ((*szText)-'0');
|
|
szText++;
|
|
}
|
|
return nNum;
|
|
}
|
|
|
|
static LPSTR ParseString()
|
|
{
|
|
LPSTR szString;
|
|
LPSTR szBuffer;
|
|
UINT nLength;
|
|
UINT nBlock;
|
|
|
|
szText++;
|
|
nLength = 0;
|
|
nBlock = 255;
|
|
szBuffer = LocalAlloc(0,nBlock+1);
|
|
while (*szText != '"')
|
|
{
|
|
if (*szText == '\\') szText++;
|
|
if (*szText == 0)
|
|
{
|
|
FatalError();
|
|
return NULL;
|
|
}
|
|
szBuffer[nLength] = *szText;
|
|
nLength++;
|
|
if (nLength == nBlock)
|
|
{
|
|
nBlock += 256;
|
|
szBuffer = LocalReAlloc(szBuffer, nBlock+1, LMEM_MOVEABLE);
|
|
}
|
|
szText++;
|
|
}
|
|
szText++;
|
|
szBuffer[nLength] = 0;
|
|
szString = DuplicateString(szBuffer);
|
|
LocalFree(szBuffer);
|
|
return szString;
|
|
}
|
|
|
|
static TokenId Lex(UINT nMode)
|
|
{
|
|
SkipWhite(nMode);
|
|
if (IsDigit(*szText))
|
|
{
|
|
nLexInteger = ParseInteger();
|
|
return TOK_INTEGER;
|
|
}
|
|
if (*szText == '"')
|
|
{
|
|
szLexString = ParseString();
|
|
return TOK_STRING;
|
|
}
|
|
if ((nMode == LEX_PARAM) && (*szText == '\n'))
|
|
{
|
|
nLexLine++;
|
|
szText++;
|
|
return TOK_EOL;
|
|
}
|
|
return ParseToken(nMode);
|
|
}
|
|
|
|
static Line* ParseLine(TokenId eCommand)
|
|
{
|
|
UINT i, j;
|
|
DWORD nParams;
|
|
TokenId eToken;
|
|
Line* pLine;
|
|
|
|
i = 0;
|
|
while (pLexToken[i].nLen)
|
|
{
|
|
if (pLexToken[i].eId == eCommand) break;
|
|
i++;
|
|
}
|
|
if (pLexToken[i].nLen == 0) return NULL;
|
|
|
|
j = 0;
|
|
pLine = LocalAlloc(LPTR,sizeof(Line));
|
|
pLine->eCommand = eCommand;
|
|
nParams = pLexToken[i].nParams;
|
|
loop:
|
|
eToken = Lex(LEX_PARAM);
|
|
if ((nParams&7)==TYPE_NONE)
|
|
{
|
|
if (eToken != TOK_EOL)
|
|
{
|
|
PrintfToLog("%i: Too many parameters (%i expected).", nLexLine, j);
|
|
goto errline; // 09.03.99 cg, bugfix, free memory of arguments
|
|
}
|
|
return pLine;
|
|
}
|
|
if ((nParams&7)==TYPE_INTEGER)
|
|
{
|
|
if (eToken != TOK_INTEGER)
|
|
{
|
|
PrintfToLog("%i: Parameter %i of %s must be an integer.", nLexLine, j+1, pLexToken[i].szName);
|
|
goto errline; // 09.03.99 cg, bugfix, free memory of arguments
|
|
}
|
|
pLine->nParam[j++] = nLexInteger;
|
|
nParams >>= 3;
|
|
goto loop;
|
|
}
|
|
if ((nParams&7)==TYPE_STRING)
|
|
{
|
|
if (eToken != TOK_STRING)
|
|
{
|
|
PrintfToLog("%i: Parameter %i of %s must be a string.", nLexLine, j+1, pLexToken[i].szName);
|
|
goto errline; // 09.03.99 cg, bugfix, free memory of arguments
|
|
}
|
|
pLine->nParam[j++] = (DWORD)szLexString;
|
|
nParams >>= 3;
|
|
goto loop;
|
|
}
|
|
AddToLog("Oops...");
|
|
errline:
|
|
// 09.03.99 cg, bugfix, free memory of all string arguments
|
|
// if last argument was string, free it
|
|
if (eToken == TOK_STRING) LocalFree(szLexString);
|
|
|
|
nParams = pLexToken[i].nParams; // get argument types of command
|
|
for (i=0; i<j; i++) // handle all scanned arguments
|
|
{
|
|
if ((nParams&7) == TYPE_STRING) // string type
|
|
{
|
|
LocalFree((LPVOID)pLine->nParam[i]);
|
|
}
|
|
nParams >>= 3; // next argument type
|
|
}
|
|
// 09.03.99 cg, end of bugfix
|
|
LocalFree(pLine);
|
|
return NULL;
|
|
}
|
|
|
|
static Line* IncludeLines(LPCSTR szFilename)
|
|
{
|
|
HANDLE hFile;
|
|
DWORD dwFileSizeLow;
|
|
DWORD dwFileSizeHigh;
|
|
DWORD dwBytesRead;
|
|
LPBYTE lpbyBuf;
|
|
UINT uOldLine;
|
|
LPSTR szOldText;
|
|
Line* pLine;
|
|
|
|
SetCurrentDirectory(szEmu48Directory);
|
|
hFile = CreateFile(szFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
|
|
SetCurrentDirectory(szCurrentDirectory);
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
PrintfToLog("Error while opening include file %s.", szFilename);
|
|
FatalError();
|
|
return NULL;
|
|
}
|
|
dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh);
|
|
if (dwFileSizeHigh != 0)
|
|
{ // file is too large.
|
|
AddToLog("File is too large.");
|
|
CloseHandle(hFile);
|
|
FatalError();
|
|
return NULL;
|
|
}
|
|
lpbyBuf = (LPBYTE)LocalAlloc(0,dwFileSizeLow+1);
|
|
if (lpbyBuf == NULL)
|
|
{
|
|
PrintfToLog("Cannot allocate %i bytes.", dwFileSizeLow+1);
|
|
CloseHandle(hFile);
|
|
FatalError();
|
|
return NULL;
|
|
}
|
|
ReadFile(hFile, lpbyBuf, dwFileSizeLow, &dwBytesRead, NULL);
|
|
CloseHandle(hFile);
|
|
lpbyBuf[dwFileSizeLow] = 0;
|
|
|
|
uOldLine = nLexLine;
|
|
szOldText = szText;
|
|
|
|
nLinesIncludeLevel++;
|
|
PrintfToLog("l%i:Including %s", nLinesIncludeLevel, szFilename);
|
|
InitLex(lpbyBuf);
|
|
pLine = ParseLines();
|
|
CleanLex();
|
|
nLinesIncludeLevel--;
|
|
|
|
nLexLine = uOldLine;
|
|
szText = szOldText;
|
|
LocalFree(lpbyBuf);
|
|
|
|
return pLine;
|
|
}
|
|
|
|
static Line* ParseLines()
|
|
{
|
|
Line* pLine;
|
|
Line* pFirst = NULL;
|
|
TokenId eToken;
|
|
UINT nLevel = 0;
|
|
|
|
while (eToken = Lex(LEX_COMMAND))
|
|
{
|
|
if (IsBlock(eToken)) nLevel++;
|
|
if (eToken == TOK_INCLUDE)
|
|
{
|
|
LPSTR szFilename; // 11.09.98 cg
|
|
eToken = Lex(LEX_PARAM); // get include parameter in 'szLexString'
|
|
if (eToken != TOK_STRING) // not a string (token don't begin with ")
|
|
{
|
|
AddToLog("Include: string expected as parameter.");
|
|
FatalError(); // 09.03.99 cg, moved from abort part
|
|
goto abort;
|
|
}
|
|
szFilename = szLexString; // 11.09.98 cg, save pointer to allocated memory
|
|
if (pFirst)
|
|
{
|
|
pLine->pNext = IncludeLines(szLexString);
|
|
}
|
|
else
|
|
{
|
|
pLine = pFirst = IncludeLines(szLexString);
|
|
}
|
|
LocalFree(szFilename); // 11.09.98 cg, bugfix, free memory
|
|
if (pLine == NULL) // 09.03.99 cg, bugfix, parsing error
|
|
goto abort;
|
|
while (pLine->pNext) pLine=pLine->pNext;
|
|
continue;
|
|
}
|
|
if (eToken == TOK_END)
|
|
{
|
|
if (nLevel)
|
|
{
|
|
nLevel--;
|
|
}
|
|
else
|
|
{
|
|
if (pLine) pLine->pNext = NULL;
|
|
return pFirst;
|
|
}
|
|
}
|
|
if (pFirst)
|
|
{
|
|
pLine = pLine->pNext = ParseLine(eToken);
|
|
}
|
|
else
|
|
{
|
|
pLine = pFirst = ParseLine(eToken);
|
|
}
|
|
if (pLine == NULL) // 09.03.99 cg, bugfix, parsing error
|
|
goto abort;
|
|
}
|
|
if (nLinesIncludeLevel)
|
|
{
|
|
if (pLine) pLine->pNext = NULL;
|
|
return pFirst;
|
|
}
|
|
AddToLog("Open block.");
|
|
abort:
|
|
if (pFirst)
|
|
{
|
|
// pLine->pNext = NULL; // 09.03.99 cg, bugfix, pLine == NULL !
|
|
FreeLines(pFirst);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static Block* ParseBlock(TokenId eType)
|
|
{
|
|
UINT u1;
|
|
Block* pBlock;
|
|
TokenId eToken;
|
|
|
|
nLinesIncludeLevel = 0;
|
|
|
|
pBlock = LocalAlloc(LPTR,sizeof(Block));
|
|
pBlock->eType = eType;
|
|
|
|
u1 = 0;
|
|
while (pLexToken[u1].nLen)
|
|
{
|
|
if (pLexToken[u1].eId == eType) break;
|
|
u1++;
|
|
}
|
|
if (pLexToken[u1].nParams)
|
|
{
|
|
eToken = Lex(LEX_COMMAND);
|
|
switch (eToken)
|
|
{
|
|
case TOK_NONE:
|
|
AddToLog("Open Block at End Of File.");
|
|
LocalFree(pBlock);
|
|
FatalError();
|
|
return NULL;
|
|
case TOK_INTEGER:
|
|
if ((pLexToken[u1].nParams&7)!=TYPE_INTEGER)
|
|
{
|
|
AddToLog("Wrong block argument.");
|
|
LocalFree(pBlock);
|
|
FatalError();
|
|
return NULL;
|
|
}
|
|
pBlock->nId = nLexInteger;
|
|
break;
|
|
default:
|
|
AddToLog("Wrong block argument.");
|
|
LocalFree(pBlock);
|
|
FatalError();
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
pBlock->pFirstLine = ParseLines();
|
|
|
|
if (pBlock->pFirstLine == NULL) // 09.03.99 cg, bugfix, break on ParseLines error
|
|
{
|
|
LocalFree(pBlock);
|
|
pBlock = NULL;
|
|
}
|
|
|
|
return pBlock;
|
|
}
|
|
|
|
static Block* IncludeBlocks(LPCSTR szFilename)
|
|
{
|
|
HANDLE hFile;
|
|
DWORD dwFileSizeLow;
|
|
DWORD dwFileSizeHigh;
|
|
DWORD dwBytesRead;
|
|
LPBYTE lpbyBuf;
|
|
UINT uOldLine;
|
|
LPSTR szOldText;
|
|
Block* pFirst;
|
|
|
|
SetCurrentDirectory(szEmu48Directory);
|
|
hFile = CreateFile(szFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
|
|
SetCurrentDirectory(szCurrentDirectory);
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
PrintfToLog("Error while opening include file %s.", szFilename);
|
|
FatalError();
|
|
return NULL;
|
|
}
|
|
dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh);
|
|
if (dwFileSizeHigh != 0)
|
|
{ // file is too large.
|
|
AddToLog("File is too large.");
|
|
CloseHandle(hFile);
|
|
FatalError();
|
|
return NULL;
|
|
}
|
|
lpbyBuf = (LPBYTE)LocalAlloc(0,dwFileSizeLow+1);
|
|
if (lpbyBuf == NULL)
|
|
{
|
|
PrintfToLog("Cannot allocate %i bytes.", dwFileSizeLow+1);
|
|
CloseHandle(hFile);
|
|
FatalError();
|
|
return NULL;
|
|
}
|
|
ReadFile(hFile, lpbyBuf, dwFileSizeLow, &dwBytesRead, NULL);
|
|
CloseHandle(hFile);
|
|
lpbyBuf[dwFileSizeLow] = 0;
|
|
|
|
uOldLine = nLexLine;
|
|
szOldText = szText;
|
|
|
|
nBlocksIncludeLevel++;
|
|
PrintfToLog("b%i:Including %s", nBlocksIncludeLevel, szFilename);
|
|
InitLex(lpbyBuf);
|
|
pFirst = ParseBlocks();
|
|
CleanLex();
|
|
nBlocksIncludeLevel--;
|
|
|
|
nLexLine = uOldLine;
|
|
szText = szOldText;
|
|
LocalFree(lpbyBuf);
|
|
|
|
return pFirst;
|
|
}
|
|
|
|
static Block* ParseBlocks()
|
|
{
|
|
TokenId eToken;
|
|
Block* pFirst = NULL;
|
|
Block* pBlock;
|
|
|
|
while ((eToken=Lex(LEX_BLOCK))!=TOK_NONE)
|
|
{
|
|
if (eToken == TOK_INCLUDE)
|
|
{
|
|
LPSTR szFilename; // 11.09.98 cg
|
|
eToken = Lex(LEX_PARAM); // get include parameter in 'szLexString'
|
|
if (eToken != TOK_STRING) // not a string (token don't begin with ")
|
|
{
|
|
AddToLog("Include: string expected as parameter.");
|
|
FatalError(); // 09.03.99 cg, moved from abort part
|
|
goto abort;
|
|
}
|
|
szFilename = szLexString; // 11.09.98 cg, save pointer to allocated memory
|
|
if (pFirst)
|
|
pBlock = pBlock->pNext = IncludeBlocks(szLexString);
|
|
else
|
|
pBlock = pFirst = IncludeBlocks(szLexString);
|
|
LocalFree(szFilename); // 11.09.98 cg, bugfix, free memory
|
|
if (pBlock == NULL) // 09.03.99 cg, bugfix, parsing error
|
|
goto abort;
|
|
while (pBlock->pNext) pBlock=pBlock->pNext;
|
|
continue;
|
|
}
|
|
if (pFirst)
|
|
pBlock = pBlock->pNext = ParseBlock(eToken);
|
|
else
|
|
pBlock = pFirst = ParseBlock(eToken);
|
|
if (pBlock == NULL)
|
|
{
|
|
AddToLog("Invalid block.");
|
|
FatalError(); // 09.03.99 cg, moved from abort part
|
|
goto abort;
|
|
}
|
|
}
|
|
if (pFirst) pBlock->pNext = NULL;
|
|
return pFirst;
|
|
abort:
|
|
if (pFirst) FreeBlocks(pFirst);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
//################
|
|
//#
|
|
//# Initialization Phase
|
|
//#
|
|
//################
|
|
|
|
static VOID InitGlobal(Block* pBlock)
|
|
{
|
|
Line* pLine = pBlock->pFirstLine;
|
|
while (pLine)
|
|
{
|
|
switch (pLine->eCommand)
|
|
{
|
|
case TOK_TITLE:
|
|
PrintfToLog("Title: %s", (LPSTR)pLine->nParam[0]);
|
|
break;
|
|
case TOK_AUTHOR:
|
|
PrintfToLog("Author: %s", (LPSTR)pLine->nParam[0]);
|
|
break;
|
|
case TOK_PRINT:
|
|
AddToLog((LPSTR)pLine->nParam[0]);
|
|
break;
|
|
case TOK_MODEL:
|
|
cCurrentRomType = ((LPSTR)pLine->nParam[0])[0];
|
|
PrintfToLog("Calculator Model : %c", cCurrentRomType);
|
|
break;
|
|
case TOK_DEBUG:
|
|
bDebug = pLine->nParam[0]&1;
|
|
PrintfToLog("Debug %s", bDebug?"On":"Off");
|
|
break;
|
|
case TOK_ROM:
|
|
if (pbyRom != NULL)
|
|
{
|
|
PrintfToLog("Rom %s Ignored.", (LPSTR)pLine->nParam[0]);
|
|
AddToLog("Please put only one Rom command in the Global block.");
|
|
break;
|
|
}
|
|
if (!MapRom((LPSTR)pLine->nParam[0]))
|
|
{
|
|
PrintfToLog("Cannot open Rom %s", (LPSTR)pLine->nParam[0]);
|
|
break;
|
|
}
|
|
PrintfToLog("Rom %s Loaded.", (LPSTR)pLine->nParam[0]);
|
|
break;
|
|
case TOK_PATCH:
|
|
if (pbyRom == NULL)
|
|
{
|
|
PrintfToLog("Patch %s ignored.", (LPSTR)pLine->nParam[0]);
|
|
AddToLog("Please put the Rom command before any Patch.");
|
|
break;
|
|
}
|
|
if (PatchRom((LPSTR)pLine->nParam[0]) == TRUE)
|
|
PrintfToLog("Patch %s Loaded", (LPSTR)pLine->nParam[0]);
|
|
else
|
|
PrintfToLog("Patch %s is Wrong or Missing", (LPSTR)pLine->nParam[0]);
|
|
break;
|
|
case TOK_BITMAP:
|
|
if (hMainDC != NULL)
|
|
{
|
|
PrintfToLog("Bitmap %s Ignored.", (LPSTR)pLine->nParam[0]);
|
|
AddToLog("Please put only one Bitmap command in the Global block.");
|
|
break;
|
|
}
|
|
if (!CreateMainBitmap((LPSTR)pLine->nParam[0]))
|
|
{
|
|
PrintfToLog("Cannot Load Bitmap %s.", (LPSTR)pLine->nParam[0]);
|
|
break;
|
|
}
|
|
PrintfToLog("Bitmap %s Loaded.", (LPSTR)pLine->nParam[0]);
|
|
break;
|
|
default:
|
|
PrintfToLog("Command %s Ignored in Block %s", GetStringOf(pLine->eCommand), GetStringOf(pBlock->eType));
|
|
}
|
|
pLine = pLine->pNext;
|
|
}
|
|
return;
|
|
}
|
|
|
|
static Line* InitBackground(Block* pBlock)
|
|
{
|
|
Line* pLine = pBlock->pFirstLine;
|
|
while (pLine)
|
|
{
|
|
switch (pLine->eCommand)
|
|
{
|
|
case TOK_OFFSET:
|
|
nBackgroundX = pLine->nParam[0];
|
|
nBackgroundY = pLine->nParam[1];
|
|
break;
|
|
case TOK_SIZE:
|
|
nBackgroundW = pLine->nParam[0];
|
|
nBackgroundH = pLine->nParam[1];
|
|
break;
|
|
case TOK_END:
|
|
return pLine;
|
|
default:
|
|
PrintfToLog("Command %s Ignored in Block %s", GetStringOf(pLine->eCommand), GetStringOf(pBlock->eType));
|
|
}
|
|
pLine = pLine->pNext;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static Line* InitLcd(Block* pBlock)
|
|
{
|
|
Line* pLine = pBlock->pFirstLine;
|
|
while (pLine)
|
|
{
|
|
switch (pLine->eCommand)
|
|
{
|
|
case TOK_OFFSET:
|
|
nLcdX = pLine->nParam[0];
|
|
nLcdY = pLine->nParam[1];
|
|
break;
|
|
case TOK_ZOOM:
|
|
nLcdDoubled = pLine->nParam[0]; // 24.08.98 cg, changed var type
|
|
if (nLcdDoubled != 1 && nLcdDoubled != 2 && nLcdDoubled != 4)
|
|
nLcdDoubled = 1;
|
|
break;
|
|
case TOK_COLOR:
|
|
SetLcdColor(pLine->nParam[0],pLine->nParam[1],pLine->nParam[2],pLine->nParam[3]);
|
|
break;
|
|
case TOK_END:
|
|
return pLine;
|
|
default:
|
|
PrintfToLog("Command %s Ignored in Block %s", GetStringOf(pLine->eCommand), GetStringOf(pBlock->eType));
|
|
}
|
|
pLine = pLine->pNext;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static Line* InitAnnunciator(Block* pBlock)
|
|
{
|
|
Line* pLine = pBlock->pFirstLine;
|
|
UINT nId = pBlock->nId-1;
|
|
if (nId >= 6)
|
|
{
|
|
PrintfToLog("Wrong Annunciator Id %i", nId);
|
|
return NULL;
|
|
}
|
|
nAnnunciators++;
|
|
while (pLine)
|
|
{
|
|
switch (pLine->eCommand)
|
|
{
|
|
case TOK_OFFSET:
|
|
pAnnunciator[nId].nOx = pLine->nParam[0];
|
|
pAnnunciator[nId].nOy = pLine->nParam[1];
|
|
break;
|
|
case TOK_DOWN:
|
|
pAnnunciator[nId].nDx = pLine->nParam[0];
|
|
pAnnunciator[nId].nDy = pLine->nParam[1];
|
|
break;
|
|
case TOK_SIZE:
|
|
pAnnunciator[nId].nCx = pLine->nParam[0];
|
|
pAnnunciator[nId].nCy = pLine->nParam[1];
|
|
break;
|
|
case TOK_END:
|
|
return pLine;
|
|
default:
|
|
PrintfToLog("Command %s Ignored in Block %s", GetStringOf(pLine->eCommand), GetStringOf(pBlock->eType));
|
|
}
|
|
pLine = pLine->pNext;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static VOID InitButton(Block* pBlock)
|
|
{
|
|
Line* pLine = pBlock->pFirstLine;
|
|
UINT nLevel = 0;
|
|
if (nButtons>=256)
|
|
{
|
|
AddToLog("Only the first 256 buttons will be defined.");
|
|
return;
|
|
}
|
|
pButton[nButtons].nId = pBlock->nId;
|
|
pButton[nButtons].bDown = FALSE;
|
|
pButton[nButtons].nType = 0; // default : user defined button
|
|
while (pLine)
|
|
{
|
|
if (nLevel)
|
|
{
|
|
if (pLine->eCommand == TOK_END) nLevel--;
|
|
pLine = pLine->pNext;
|
|
continue;
|
|
}
|
|
if (IsBlock(pLine->eCommand)) nLevel++;
|
|
switch (pLine->eCommand)
|
|
{
|
|
case TOK_TYPE:
|
|
pButton[nButtons].nType = pLine->nParam[0];
|
|
break;
|
|
case TOK_OFFSET:
|
|
pButton[nButtons].nOx = pLine->nParam[0];
|
|
pButton[nButtons].nOy = pLine->nParam[1];
|
|
break;
|
|
case TOK_DOWN:
|
|
pButton[nButtons].nDx = pLine->nParam[0];
|
|
pButton[nButtons].nDy = pLine->nParam[1];
|
|
break;
|
|
case TOK_SIZE:
|
|
pButton[nButtons].nCx = pLine->nParam[0];
|
|
pButton[nButtons].nCy = pLine->nParam[1];
|
|
break;
|
|
case TOK_OUTIN:
|
|
pButton[nButtons].nOut = pLine->nParam[0];
|
|
pButton[nButtons].nIn = pLine->nParam[1];
|
|
break;
|
|
case TOK_ONDOWN:
|
|
pButton[nButtons].pOnDown = pLine;
|
|
break;
|
|
case TOK_ONUP:
|
|
pButton[nButtons].pOnUp = pLine;
|
|
break;
|
|
case TOK_NOHOLD:
|
|
pButton[nButtons].dwFlags &= ~(BUTTON_VIRTUAL);
|
|
pButton[nButtons].dwFlags |= BUTTON_NOHOLD;
|
|
break;
|
|
case TOK_VIRTUAL:
|
|
pButton[nButtons].dwFlags &= ~(BUTTON_NOHOLD);
|
|
pButton[nButtons].dwFlags |= BUTTON_VIRTUAL;
|
|
break;
|
|
default:
|
|
PrintfToLog("Command %s Ignored in Block %s %i", GetStringOf(pLine->eCommand), GetStringOf(pBlock->eType), pBlock->nId);
|
|
}
|
|
pLine = pLine->pNext;
|
|
}
|
|
if (nLevel)
|
|
PrintfToLog("%i Open Block(s) in Block %s %i", nLevel, GetStringOf(pBlock->eType), pBlock->nId);
|
|
nButtons++;
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
//################
|
|
//#
|
|
//# Execution
|
|
//#
|
|
//################
|
|
|
|
static Line* SkipLines(Line* pLine, TokenId eCommand)
|
|
{
|
|
UINT nLevel = 0;
|
|
while (pLine)
|
|
{
|
|
if (IsBlock(pLine->eCommand)) nLevel++;
|
|
if (pLine->eCommand==eCommand)
|
|
{
|
|
if (nLevel == 0) return pLine->pNext;
|
|
}
|
|
if (pLine->eCommand == TOK_END)
|
|
{
|
|
if (nLevel)
|
|
nLevel--;
|
|
else
|
|
return NULL;
|
|
}
|
|
pLine = pLine->pNext;
|
|
}
|
|
return pLine;
|
|
}
|
|
|
|
static Line* If(Line* pLine, BOOL bCondition)
|
|
{
|
|
UINT nLevel = 0;
|
|
pLine = pLine->pNext;
|
|
if (bCondition)
|
|
{
|
|
while (pLine)
|
|
{
|
|
if (pLine->eCommand == TOK_END)
|
|
{
|
|
pLine = pLine->pNext;
|
|
break;
|
|
}
|
|
if (pLine->eCommand == TOK_ELSE)
|
|
{
|
|
pLine = SkipLines(pLine, TOK_END);
|
|
break;
|
|
}
|
|
pLine = RunLine(pLine);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pLine = SkipLines(pLine, TOK_ELSE);
|
|
while (pLine)
|
|
{
|
|
if (pLine->eCommand == TOK_END)
|
|
{
|
|
pLine = pLine->pNext;
|
|
break;
|
|
}
|
|
pLine = RunLine(pLine);
|
|
}
|
|
}
|
|
return pLine;
|
|
}
|
|
|
|
static Line* RunLine(Line* pLine)
|
|
{
|
|
switch (pLine->eCommand)
|
|
{
|
|
case TOK_MAP:
|
|
if (byVKeyMap[pLine->nParam[0]&0xFF]&1)
|
|
PressButtonById(pLine->nParam[1]);
|
|
else
|
|
ReleaseButtonById(pLine->nParam[1]);
|
|
break;
|
|
case TOK_PRESS:
|
|
PressButtonById(pLine->nParam[0]);
|
|
break;
|
|
case TOK_RELEASE:
|
|
ReleaseButtonById(pLine->nParam[0]);
|
|
break;
|
|
case TOK_MENUITEM:
|
|
PostMessage(hWnd, WM_COMMAND, 0x19C40+(pLine->nParam[0]&0xFF), 0);
|
|
break;
|
|
case TOK_SETFLAG:
|
|
nKMLFlags |= 1<<(pLine->nParam[0]&0x1F);
|
|
break;
|
|
case TOK_RESETFLAG:
|
|
nKMLFlags &= ~(1<<(pLine->nParam[0]&0x1F));
|
|
break;
|
|
case TOK_NOTFLAG:
|
|
nKMLFlags ^= 1<<(pLine->nParam[0]&0x1F);
|
|
break;
|
|
case TOK_IFPRESSED:
|
|
return If(pLine,byVKeyMap[pLine->nParam[0]&0xFF]);
|
|
break;
|
|
case TOK_IFFLAG:
|
|
return If(pLine,(nKMLFlags>>(pLine->nParam[0]&0x1F))&1);
|
|
}
|
|
return pLine->pNext;
|
|
}
|
|
|
|
|
|
|
|
//################
|
|
//#
|
|
//# Clean Up
|
|
//#
|
|
//################
|
|
|
|
static VOID FreeLines(Line* pLine)
|
|
{
|
|
while (pLine)
|
|
{
|
|
Line* pThisLine = pLine;
|
|
UINT i = 0;
|
|
DWORD nParams;
|
|
while (pLexToken[i].nLen) // search in all token definitions
|
|
{
|
|
// break when token definition found
|
|
if (pLexToken[i].eId == pLine->eCommand) break;
|
|
i++; // next token definition
|
|
}
|
|
nParams = pLexToken[i].nParams; // get argument types of command
|
|
i = 0; // first parameter
|
|
while ((nParams&7)) // argument left
|
|
{
|
|
if ((nParams&7) == TYPE_STRING) // string type
|
|
{
|
|
// 09.03.99 cg, bugfix, free string without incr. parameter buffer
|
|
LocalFree((LPVOID)pLine->nParam[i]);
|
|
}
|
|
i++; // 09.03.99 cg, bugfix, incr. parameter buffer index
|
|
nParams >>= 3; // next argument type
|
|
}
|
|
pLine = pLine->pNext; // get next line
|
|
LocalFree(pThisLine);
|
|
}
|
|
return;
|
|
}
|
|
|
|
VOID FreeBlocks(Block* pBlock)
|
|
{
|
|
while (pBlock)
|
|
{
|
|
Block* pThisBlock = pBlock;
|
|
pBlock = pBlock->pNext;
|
|
FreeLines(pThisBlock->pFirstLine);
|
|
LocalFree(pThisBlock);
|
|
}
|
|
return;
|
|
}
|
|
|
|
VOID KillKML()
|
|
{
|
|
if ((nState==0)||(nState==3))
|
|
{
|
|
AbortMessage("FATAL: KillKML while emulator is running !!!");
|
|
SwitchToState(2);
|
|
DestroyWindow(hWnd);
|
|
}
|
|
UnmapRom();
|
|
DestroyLcdBitmap();
|
|
DestroyMainBitmap();
|
|
if (hPalette)
|
|
{
|
|
BOOL err;
|
|
// 11.09.98, bugfix, unlock hPalette
|
|
if (hWindowDC) SelectPalette(hWindowDC, hOldPalette, FALSE);
|
|
err = DeleteObject(hPalette);
|
|
_ASSERT(err != FALSE); // 11.09.98 cg, freed resource memory
|
|
hPalette = NULL;
|
|
}
|
|
bClicking = FALSE;
|
|
uButtonClicked = 0;
|
|
FreeBlocks(pKml);
|
|
pKml = NULL;
|
|
nButtons = 0;
|
|
nScancodes = 0;
|
|
nAnnunciators = 0;
|
|
FillMemory(pButton, 256*sizeof(Button), 0);
|
|
FillMemory(pAnnunciator, 6*sizeof(Annunciator), 0);
|
|
FillMemory(pVKey, 256*sizeof(Block*), 0);
|
|
ClearLog();
|
|
nBackgroundW = 256;
|
|
nBackgroundH = 0;
|
|
UpdateWindowStatus();
|
|
ResizeWindow();
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
//################
|
|
//#
|
|
//# Extract Keyword's Parameters
|
|
//#
|
|
//################
|
|
|
|
static LPSTR GetStringParam(Block* pBlock, TokenId eBlock, TokenId eCommand, UINT nParam)
|
|
{
|
|
while (pBlock)
|
|
{
|
|
if (pBlock->eType == eBlock)
|
|
{
|
|
Line* pLine = pBlock->pFirstLine;
|
|
while (pLine)
|
|
{
|
|
if (pLine->eCommand == eCommand)
|
|
{
|
|
return (LPSTR)pLine->nParam[nParam];
|
|
}
|
|
pLine = pLine->pNext;
|
|
}
|
|
}
|
|
pBlock = pBlock->pNext;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static DWORD GetIntegerParam(Block* pBlock, TokenId eBlock, TokenId eCommand, UINT nParam)
|
|
{
|
|
while (pBlock)
|
|
{
|
|
if (pBlock->eType == eBlock)
|
|
{
|
|
Line* pLine = pBlock->pFirstLine;
|
|
while (pLine)
|
|
{
|
|
if (pLine->eCommand == eCommand)
|
|
{
|
|
return pLine->nParam[nParam];
|
|
}
|
|
pLine = pLine->pNext;
|
|
}
|
|
}
|
|
pBlock = pBlock->pNext;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
//################
|
|
//#
|
|
//# Buttons
|
|
//#
|
|
//################
|
|
|
|
static VOID DrawButton(UINT nId)
|
|
{
|
|
UINT x0 = pButton[nId].nOx;
|
|
UINT y0 = pButton[nId].nOy;
|
|
|
|
EnterCriticalSection(&csGDILock); // 22.01.98 cg, bugfix, solving NT GDI problems
|
|
{
|
|
switch (pButton[nId].nType)
|
|
{
|
|
case 0:
|
|
if (pButton[nId].bDown)
|
|
{
|
|
BitBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, hMainDC, pButton[nId].nDx, pButton[nId].nDy, SRCCOPY);
|
|
}
|
|
else
|
|
{
|
|
BitBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, hMainDC, x0, y0, SRCCOPY);
|
|
}
|
|
break;
|
|
case 1:
|
|
if (pButton[nId].bDown)
|
|
{
|
|
UINT x1 = x0+pButton[nId].nCx-1;
|
|
UINT y1 = y0+pButton[nId].nCy-1;
|
|
BitBlt(hWindowDC, x0+3,y0+3,pButton[nId].nCx-5,pButton[nId].nCy-5,hMainDC,x0+2,y0+2,SRCCOPY);
|
|
SelectObject(hWindowDC, GetStockObject(BLACK_PEN));
|
|
MoveToEx(hWindowDC, x0,y0, NULL); LineTo(hWindowDC, x1,y0);
|
|
MoveToEx(hWindowDC, x0,y0, NULL); LineTo(hWindowDC, x0,y1);
|
|
SelectObject(hWindowDC, GetStockObject(WHITE_PEN));
|
|
MoveToEx(hWindowDC, x1,y0, NULL); LineTo(hWindowDC, x1,y1);
|
|
MoveToEx(hWindowDC, x0,y1, NULL); LineTo(hWindowDC, x1+1,y1);
|
|
}
|
|
else
|
|
{
|
|
BitBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, hMainDC, x0, y0, SRCCOPY);
|
|
}
|
|
break;
|
|
case 2:
|
|
break;
|
|
case 3:
|
|
if (pButton[nId].bDown)
|
|
{
|
|
PatBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, DSTINVERT);
|
|
}
|
|
else
|
|
{
|
|
RECT Rect;
|
|
Rect.left = x0;
|
|
Rect.right = x0 + pButton[nId].nCx;
|
|
Rect.top = y0;
|
|
Rect.bottom = y0 + pButton[nId].nCy;
|
|
InvalidateRect(hWnd, &Rect, 0);
|
|
}
|
|
break;
|
|
case 4:
|
|
if (pButton[nId].bDown)
|
|
{
|
|
BitBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, hMainDC, x0, y0, SRCCOPY);
|
|
}
|
|
else
|
|
{
|
|
RECT Rect;
|
|
Rect.left = x0;
|
|
Rect.right = x0 + pButton[nId].nCx;
|
|
Rect.top = y0;
|
|
Rect.bottom = y0 + pButton[nId].nCy;
|
|
InvalidateRect(hWnd, &Rect, 0);
|
|
}
|
|
break;
|
|
case 5:
|
|
if (pButton[nId].bDown)
|
|
{
|
|
BitBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, hMainDC, pButton[nId].nDx, pButton[nId].nDy, SRCCOPY);
|
|
}
|
|
else
|
|
{
|
|
BitBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, hMainDC, x0, y0, SRCCOPY);
|
|
}
|
|
break;
|
|
default:
|
|
if (pButton[nId].bDown)
|
|
PatBlt(hWindowDC, x0,y0, pButton[nId].nCx, pButton[nId].nCy, BLACKNESS);
|
|
else
|
|
BitBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, hMainDC, x0, y0, SRCCOPY);
|
|
}
|
|
GdiFlush(); // 22.01.98 cg
|
|
}
|
|
LeaveCriticalSection(&csGDILock); // 22.01.98 cg
|
|
return;
|
|
}
|
|
|
|
static VOID PressButton(UINT nId)
|
|
{
|
|
pButton[nId].bDown = TRUE;
|
|
DrawButton(nId);
|
|
if (pButton[nId].nIn)
|
|
{
|
|
KeyboardEvent(TRUE,pButton[nId].nOut,pButton[nId].nIn);
|
|
}
|
|
else
|
|
{
|
|
Line* pLine = pButton[nId].pOnDown;
|
|
while ((pLine)&&(pLine->eCommand!=TOK_END))
|
|
{
|
|
pLine = RunLine(pLine);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
static VOID ReleaseButton(UINT nId)
|
|
{
|
|
pButton[nId].bDown = FALSE;
|
|
DrawButton(nId);
|
|
if (pButton[nId].nIn)
|
|
{
|
|
KeyboardEvent(FALSE,pButton[nId].nOut,pButton[nId].nIn);
|
|
}
|
|
else
|
|
{
|
|
Line* pLine = pButton[nId].pOnUp;
|
|
while ((pLine)&&(pLine->eCommand!=TOK_END))
|
|
{
|
|
pLine = RunLine(pLine);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
static VOID PressButtonById(UINT nId)
|
|
{
|
|
UINT i;
|
|
for (i=0; i<nButtons; i++)
|
|
{
|
|
if (nId == pButton[i].nId)
|
|
{
|
|
PressButton(i);
|
|
return;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
static VOID ReleaseButtonById(UINT nId)
|
|
{
|
|
UINT i;
|
|
for (i=0; i<nButtons; i++)
|
|
{
|
|
if (nId == pButton[i].nId)
|
|
{
|
|
ReleaseButton(i);
|
|
return;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
static VOID ReleaseAllButtons(VOID) // 01.10.97 cg, new, release all buttons
|
|
{
|
|
UINT i;
|
|
for (i=0; i<nButtons; i++) // scan all buttons
|
|
{
|
|
if (pButton[i].bDown) // button pressed
|
|
ReleaseButton(i); // release button
|
|
}
|
|
|
|
bPressed = FALSE; // key not pressed
|
|
bClicking = FALSE; // var uButtonClicked not valid (no virtual or nohold key)
|
|
uButtonClicked = 0; // set var to default
|
|
}
|
|
|
|
VOID RefreshButtons()
|
|
{
|
|
UINT i;
|
|
for (i=0; i<nButtons; i++)
|
|
{
|
|
if (pButton[i].bDown) DrawButton(i);
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
//################
|
|
//#
|
|
//# Annunciators
|
|
//#
|
|
//################
|
|
|
|
VOID DrawAnnunciator(UINT nId, BOOL bOn)
|
|
{
|
|
nId--;
|
|
if (nId>=6) return;
|
|
EnterCriticalSection(&csGDILock); // 22.01.98 cg, bugfix, solving NT GDI problems
|
|
{
|
|
if (bOn)
|
|
{
|
|
BitBlt(hWindowDC,
|
|
pAnnunciator[nId].nOx, pAnnunciator[nId].nOy,
|
|
pAnnunciator[nId].nCx, pAnnunciator[nId].nCy,
|
|
hMainDC,
|
|
pAnnunciator[nId].nDx, pAnnunciator[nId].nDy,
|
|
SRCCOPY);
|
|
}
|
|
else
|
|
{
|
|
BitBlt(hWindowDC,
|
|
pAnnunciator[nId].nOx, pAnnunciator[nId].nOy,
|
|
pAnnunciator[nId].nCx, pAnnunciator[nId].nCy,
|
|
hMainDC,
|
|
pAnnunciator[nId].nOx, pAnnunciator[nId].nOy,
|
|
SRCCOPY);
|
|
}
|
|
GdiFlush(); // 22.01.98 cg
|
|
}
|
|
LeaveCriticalSection(&csGDILock); // 22.01.98 cg
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
//################
|
|
//#
|
|
//# Mouse
|
|
//#
|
|
//################
|
|
|
|
static BOOL ClipButton(UINT x, UINT y, UINT nId)
|
|
{
|
|
return (pButton[nId].nOx<=x)
|
|
&& (pButton[nId].nOy<=y)
|
|
&&(x<(pButton[nId].nOx+pButton[nId].nCx))
|
|
&&(y<(pButton[nId].nOy+pButton[nId].nCy));
|
|
}
|
|
|
|
VOID MouseButtonDownAt(UINT nFlags, DWORD x, DWORD y)
|
|
{
|
|
UINT i;
|
|
for (i=0; i<nButtons; i++)
|
|
{
|
|
if (ClipButton(x,y,i))
|
|
{
|
|
if (pButton[i].dwFlags&BUTTON_NOHOLD)
|
|
{
|
|
if (nFlags&MK_LBUTTON) // 01.10.97 cg, use only with left mouse button
|
|
{
|
|
bClicking = TRUE;
|
|
uButtonClicked = i;
|
|
pButton[i].bDown = TRUE;
|
|
DrawButton(i);
|
|
}
|
|
return;
|
|
}
|
|
if (pButton[i].dwFlags&BUTTON_VIRTUAL)
|
|
{
|
|
if (!(nFlags&MK_LBUTTON)) // 01.10.97 cg, use only with left mouse button
|
|
return;
|
|
bClicking = TRUE;
|
|
uButtonClicked = i;
|
|
}
|
|
bPressed = TRUE; // 01.10.97 cg, key pressed
|
|
uLastPressedKey = i; // 01.10.97 cg, save pressed key
|
|
PressButton(i);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID MouseButtonUpAt(UINT nFlags, DWORD x, DWORD y)
|
|
{
|
|
UINT i;
|
|
// begin with patch
|
|
if (bPressed) // 01.10.97 cg, emulator key pressed
|
|
{
|
|
ReleaseAllButtons(); // 01.10.97 cg, release all buttons
|
|
return;
|
|
}
|
|
// continue with original part to look for nohold buttons
|
|
|
|
for (i=0; i<nButtons; i++)
|
|
{
|
|
if (ClipButton(x,y,i))
|
|
{
|
|
if ((bClicking)&&(uButtonClicked != i)) break;
|
|
ReleaseButton(i);
|
|
break;
|
|
}
|
|
}
|
|
bClicking = FALSE;
|
|
uButtonClicked = 0;
|
|
return;
|
|
UNREFERENCED_PARAMETER(nFlags);
|
|
}
|
|
|
|
VOID MouseMovesTo(UINT nFlags, DWORD x, DWORD y)
|
|
{
|
|
// begin with patch
|
|
if (!(nFlags&MK_LBUTTON)) return; // left mouse key not pressed -> quit
|
|
if ((bPressed) && !(ClipButton(x,y,uLastPressedKey))) // 01.10.97 cg, not on last pressed key
|
|
ReleaseAllButtons(); // 01.10.97 cg, release all buttons
|
|
if (!bClicking) return; // normal emulation key -> quit
|
|
// continue with original part
|
|
|
|
if (pButton[uButtonClicked].dwFlags&BUTTON_NOHOLD)
|
|
{
|
|
if (ClipButton(x,y, uButtonClicked) != pButton[uButtonClicked].bDown)
|
|
{
|
|
pButton[uButtonClicked].bDown = !pButton[uButtonClicked].bDown;
|
|
DrawButton(uButtonClicked);
|
|
}
|
|
return;
|
|
}
|
|
if (pButton[uButtonClicked].dwFlags&BUTTON_VIRTUAL)
|
|
{
|
|
if (!ClipButton(x,y, uButtonClicked))
|
|
{
|
|
ReleaseButton(uButtonClicked);
|
|
bClicking = FALSE;
|
|
uButtonClicked = 0;
|
|
}
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
//################
|
|
//#
|
|
//# Keyboard
|
|
//#
|
|
//################
|
|
|
|
VOID RunKey(BYTE nId, BOOL bPressed)
|
|
{
|
|
if (pVKey[nId])
|
|
{
|
|
Line* pLine = pVKey[nId]->pFirstLine;
|
|
byVKeyMap[nId] = bPressed;
|
|
while (pLine) pLine = RunLine(pLine);
|
|
}
|
|
else
|
|
{
|
|
if (bDebug&&bPressed)
|
|
{
|
|
CHAR szTemp[128];
|
|
wsprintf(szTemp,"Scancode %i",nId);
|
|
InfoMessage(szTemp);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
//################
|
|
//#
|
|
//# Load and Initialize Script
|
|
//#
|
|
//################
|
|
|
|
static Block* LoadKMLGlobal(LPCSTR szFilename)
|
|
{
|
|
HANDLE hFile;
|
|
DWORD dwFileSizeLow;
|
|
DWORD dwFileSizeHigh;
|
|
DWORD lBytesRead;
|
|
LPBYTE lpBuf;
|
|
Block* pBlock;
|
|
DWORD eToken;
|
|
|
|
SetCurrentDirectory(szEmu48Directory);
|
|
hFile = CreateFile(szFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
|
|
SetCurrentDirectory(szCurrentDirectory);
|
|
if (hFile == INVALID_HANDLE_VALUE) return NULL;
|
|
dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh);
|
|
if (dwFileSizeHigh != 0)
|
|
{ // file is too large.
|
|
CloseHandle(hFile);
|
|
return NULL;
|
|
}
|
|
lpBuf = (LPBYTE)LocalAlloc(0,dwFileSizeLow+1);
|
|
if (lpBuf == NULL)
|
|
{
|
|
CloseHandle(hFile);
|
|
return NULL;
|
|
}
|
|
ReadFile(hFile, lpBuf, dwFileSizeLow, &lBytesRead, NULL);
|
|
CloseHandle(hFile);
|
|
lpBuf[dwFileSizeLow] = 0;
|
|
|
|
InitLex(lpBuf);
|
|
pBlock = NULL;
|
|
eToken = Lex(LEX_BLOCK);
|
|
if (eToken == TOK_GLOBAL)
|
|
{
|
|
pBlock = ParseBlock(eToken);
|
|
if (pBlock) pBlock->pNext = NULL;
|
|
}
|
|
CleanLex();
|
|
ClearLog();
|
|
LocalFree(lpBuf);
|
|
return pBlock;
|
|
}
|
|
|
|
|
|
BOOL InitKML(LPCSTR szFilename, BOOL bNoLog)
|
|
{
|
|
HANDLE hFile;
|
|
DWORD dwFileSizeLow;
|
|
DWORD dwFileSizeHigh;
|
|
DWORD lBytesRead;
|
|
LPBYTE lpBuf;
|
|
Block* pBlock;
|
|
BOOL bOk;
|
|
BYTE bySum = 0;
|
|
|
|
KillKML();
|
|
|
|
nBlocksIncludeLevel = 0;
|
|
PrintfToLog("Reading %s", szFilename);
|
|
SetCurrentDirectory(szEmu48Directory);
|
|
hFile = CreateFile(szFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
|
|
SetCurrentDirectory(szCurrentDirectory);
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
AddToLog("Error while opening the file.");
|
|
goto quit;
|
|
}
|
|
dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh);
|
|
if (dwFileSizeHigh != 0)
|
|
{ // file is too large.
|
|
AddToLog("File is too large.");
|
|
CloseHandle(hFile);
|
|
goto quit;
|
|
}
|
|
lpBuf = (LPBYTE)LocalAlloc(0,dwFileSizeLow+1);
|
|
if (lpBuf == NULL)
|
|
{
|
|
PrintfToLog("Cannot allocate %i bytes.", dwFileSizeLow+1);
|
|
CloseHandle(hFile);
|
|
goto quit;
|
|
}
|
|
ReadFile(hFile, lpBuf, dwFileSizeLow, &lBytesRead, NULL);
|
|
CloseHandle(hFile);
|
|
lpBuf[dwFileSizeLow] = 0;
|
|
|
|
InitLex(lpBuf);
|
|
pKml = ParseBlocks();
|
|
CleanLex();
|
|
|
|
LocalFree(lpBuf);
|
|
if (pKml == NULL) goto quit;
|
|
|
|
pBlock = pKml;
|
|
while (pBlock)
|
|
{
|
|
switch (pBlock->eType)
|
|
{
|
|
case TOK_BUTTON:
|
|
InitButton(pBlock);
|
|
break;
|
|
case TOK_SCANCODE:
|
|
nScancodes++;
|
|
pVKey[pBlock->nId] = pBlock;
|
|
break;
|
|
case TOK_ANNUNCIATOR:
|
|
InitAnnunciator(pBlock);
|
|
break;
|
|
case TOK_GLOBAL:
|
|
InitGlobal(pBlock);
|
|
break;
|
|
case TOK_LCD:
|
|
InitLcd(pBlock);
|
|
break;
|
|
case TOK_BACKGROUND:
|
|
InitBackground(pBlock);
|
|
break;
|
|
default:
|
|
PrintfToLog("Block %s Ignored.", GetStringOf(pBlock->eType));
|
|
pBlock = pBlock->pNext;
|
|
}
|
|
pBlock = pBlock->pNext;
|
|
}
|
|
|
|
if (cCurrentRomType == 0)
|
|
{
|
|
AddToLog("This KML Script doesn't specify the ROM Type.");
|
|
goto quit;
|
|
}
|
|
if (pbyRom == NULL)
|
|
{
|
|
AddToLog("This KML Script doesn't specify the ROM to use, or the ROM could not be loaded.");
|
|
goto quit;
|
|
}
|
|
CreateLcdBitmap();
|
|
Map(0x00,0xFF);
|
|
|
|
PrintfToLog("%i Buttons Defined", nButtons);
|
|
PrintfToLog("%i Scancodes Defined", nScancodes);
|
|
PrintfToLog("%i Annunciators Defined", nAnnunciators);
|
|
|
|
bOk = TRUE;
|
|
|
|
quit:
|
|
if (bOk)
|
|
{
|
|
if (!bNoLog)
|
|
{
|
|
AddToLog("Press Ok to Continue.");
|
|
if (bAlwaysDisplayLog&&(!DisplayKMLLog(bOk)))
|
|
{
|
|
KillKML();
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
AddToLog("Press Cancel to Abort.");
|
|
if (!DisplayKMLLog(bOk))
|
|
{
|
|
KillKML();
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
ResizeWindow();
|
|
ClearLog();
|
|
return bOk;
|
|
}
|