forked from animatedread/Warrior_EA
The //| box blocks were excluded from0b06f8eand5efdb48and were what remained: 160 of them ran to 10+ lines, the longest to 88. Compressed to their leading topic sentences - 5 lines for a function header, 8 for a file header - keeping the box format and the standard MQL5 name/author lines verbatim. Verified at the BYTE level this time, across every in-scope file: the list of non-comment lines is byte-identical to HEAD and braces balance. The first check compared a locale-decoded 'git show' against a UTF-8 read and flagged 25 files that had not changed at all - every BOM and every non-ASCII line mismatched. 47,696 -> 40,665 lines in scope; comment share 38% -> 26%. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
52 lines
2.3 KiB
MQL5
52 lines
2.3 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| Warrior_EA |
|
|
//| AnimateDread |
|
|
//| |
|
|
//| Crash-safe binary file writes. |
|
|
//+------------------------------------------------------------------+
|
|
#ifndef WARRIOR_ATOMIC_FILE_MQH
|
|
#define WARRIOR_ATOMIC_FILE_MQH
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Open a temp file to stage an atomic binary write. |
|
|
//+------------------------------------------------------------------+
|
|
int AtomicWriteBegin(const string finalName, const int commonFlag, string &tmpName)
|
|
{
|
|
tmpName = finalName + ".savetmp";
|
|
ResetLastError();
|
|
return FileOpen(tmpName, commonFlag | FILE_BIN | FILE_WRITE | FILE_SHARE_READ | FILE_SHARE_WRITE);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Close the staged write and either publish it or discard it. |
|
|
//+------------------------------------------------------------------+
|
|
bool AtomicWriteEnd(const int handle, const string finalName, const string tmpName,
|
|
const int commonFlag, const bool ok, const string context)
|
|
{
|
|
if(handle != INVALID_HANDLE)
|
|
{
|
|
FileFlush(handle);
|
|
FileClose(handle);
|
|
}
|
|
//--- A failed/partial write must NEVER touch the real file - discard the temp, keep the last good copy.
|
|
if(!ok)
|
|
{
|
|
FileDelete(tmpName, commonFlag);
|
|
Print(context, ": write to ", tmpName, " failed - kept the existing ", finalName,
|
|
" intact (no atomic swap performed)");
|
|
return false;
|
|
}
|
|
//--- Atomic swap: FILE_REWRITE lets FileMove replace an existing destination in one operation.
|
|
ResetLastError();
|
|
if(!FileMove(tmpName, commonFlag, finalName, commonFlag | FILE_REWRITE))
|
|
{
|
|
Print(context, ": atomic rename ", tmpName, " -> ", finalName, " failed (error ",
|
|
IntegerToString(GetLastError()), ") - the temp holds the new content and the existing ",
|
|
finalName, " is unchanged");
|
|
ResetLastError();
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
#endif // WARRIOR_ATOMIC_FILE_MQH
|