124 lines
3.6 KiB
MQL5
124 lines
3.6 KiB
MQL5
|
//+------------------------------------------------------------------+
|
||
|
//| FileHolder.mqh |
|
||
|
//| Copyright 2021, MetaQuotes Ltd. |
|
||
|
//| https://www.mql5.com |
|
||
|
//+------------------------------------------------------------------+
|
||
|
|
||
|
#include "MqlError.mqh"
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Base auxiliry class just to clean up internal error flags, |
|
||
|
//| which may remain after previous function calls |
|
||
|
//+------------------------------------------------------------------+
|
||
|
class FileBase
|
||
|
{
|
||
|
protected:
|
||
|
FileBase()
|
||
|
{
|
||
|
ResetLastError();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Single file-handle guard to prevent resource leak, |
|
||
|
//| closes file automatically on object deletion |
|
||
|
//+------------------------------------------------------------------+
|
||
|
class FileOpener : public FileBase
|
||
|
{
|
||
|
public:
|
||
|
const int handle;
|
||
|
const string name;
|
||
|
FileOpener(const string filename, const int flags, const ushort delimiter = '\t', const uint codepage = CP_ACP) :
|
||
|
handle(FileOpen(filename, flags, delimiter, codepage)), name(filename)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
~FileOpener()
|
||
|
{
|
||
|
ResetLastError();
|
||
|
FileGetInteger(handle, FILE_SIZE); // marks internal error if handle is incorrect
|
||
|
if(handle != INVALID_HANDLE)
|
||
|
{
|
||
|
if(_LastError == 0)
|
||
|
{
|
||
|
#ifdef FILE_DEBUG_PRINT
|
||
|
Print(__FUNCTION__, ": Automatic close for handle: ", handle);
|
||
|
#endif
|
||
|
FileClose(handle);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
PrintFormat("%s: handle %d is incorrect, %s(%d)",
|
||
|
__FUNCTION__, handle, E2S(_LastError), _LastError);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
#define CONTEXT_MARK NULL
|
||
|
#define CLEAR(P) if(CheckPointer(P) == POINTER_DYNAMIC) delete P;
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Multiple file-handle guard to prevent resource leak, |
|
||
|
//| generates FileOpener objects upon requests, then delete them |
|
||
|
//| automatically on leaving local contexts |
|
||
|
//+------------------------------------------------------------------+
|
||
|
class FileHolder
|
||
|
{
|
||
|
static FileOpener *files[];
|
||
|
int expand()
|
||
|
{
|
||
|
return ArrayResize(files, ArraySize(files) + 1) - 1;
|
||
|
}
|
||
|
public:
|
||
|
FileHolder()
|
||
|
{
|
||
|
const int n = expand();
|
||
|
if(n > -1)
|
||
|
{
|
||
|
files[n] = CONTEXT_MARK;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
~FileHolder()
|
||
|
{
|
||
|
for(int i = ArraySize(files) - 1; i >= 0; --i)
|
||
|
{
|
||
|
if(files[i] == CONTEXT_MARK)
|
||
|
{
|
||
|
// shrink array and exit
|
||
|
ArrayResize(files, i);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
CLEAR(files[i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int FileOpen(const string filename, const int flags, const ushort delimiter = '\t', const uint codepage = CP_ACP)
|
||
|
{
|
||
|
const int n = expand();
|
||
|
if(n > -1)
|
||
|
{
|
||
|
files[n] = new FileOpener(filename, flags, delimiter, codepage);
|
||
|
return files[n].handle;
|
||
|
}
|
||
|
return INVALID_HANDLE;
|
||
|
}
|
||
|
|
||
|
static string GetFilename(const int h)
|
||
|
{
|
||
|
for(int i = 0; i < ArraySize(files); ++i)
|
||
|
{
|
||
|
if(files[i] != NULL && files[i].handle == h)
|
||
|
{
|
||
|
return files[i].name;
|
||
|
}
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
static FileOpener *FileHolder::files[];
|
||
|
//+------------------------------------------------------------------+
|