2010-10-02 14:12:21 -04:00
program CRov;
2010-10-02 14:40:36 -04:00
//Crash recovery extension for Simba by Nielsie95
//http://villavu.com/forum/showthread.php?p=740535
2010-10-02 14:12:21 -04:00
const
Version = '0.6';
2010-10-03 13:33:08 -04:00
SettingsMenuDef = 'False'; //True if you want to be able to set the saving interval through the menu (otherwise it's accessible through plugin settings)
ForceSaveDef = 'True'; //Force user to save the script, instead of opening it
SaveOnRunDef = 'True'; //Make backup when user compiles/runs the script
DirDef = 'CRov\'; //Appended to AppPath
2010-10-02 14:24:24 -04:00
ExtensionDef = 'crov';
2010-10-03 13:33:08 -04:00
DefInterval = '300000'; //every 5 minutes
2010-10-02 14:12:21 -04:00
type
TCharArray = array of Char;
function _DeleteFile(lpFileName: TCharArray{PChar}): Boolean; external 'DeleteFileA@kernel32.dll stdcall';
var
Simba_Menu: TMenuItem;
Timer: TTimer;
PageControl: TPageControl;
Tab: Integer;
FileNames: TStringList;
2010-10-03 13:33:08 -04:00
SettingsMenu, ForceSave, SaveOnRun: Boolean;
2010-10-02 14:24:24 -04:00
Dir, Extension: string;
2010-10-02 14:12:21 -04:00
function StringToCharArray(s: string): TCharArray;
var
i, l: Integer;
begin
l := Length(s);
SetLength(Result, l + 1);
for i := l downto 1 do
Result[i - 1] := s[i];
Result[l] := #0;
end;
function DeleteFile(FileName: string): Boolean;
begin
Result := _DeleteFile(StringToCharArray(FileName));
end;
function FindPageControlWithName(c: TWinControl; Name: string): TPageControl;
var
i: Integer;
begin
Result := nil;
if (c = nil) then
Exit;
Name := LowerCase(Name);
for i := 0 to c.ControlCount - 1 do
if (c.Controls[i] is TPageControl) and (LowerCase(c.Controls[i].Name) = Name) then
begin
Result := TPageControl(c.Controls[i]);
Exit;
end
else if (c.Controls[i] is TWinControl) then
begin
Result := FindPageControlWithName(TWinControl(c.Controls[i]), Name);
if (Result <> nil) then
Exit;
end;
end;
function LastChar(s: string): Char;
begin
if (Length(s) < 1) then
Result := #0
else
Result := s[Length(s)];
end;
function MyTime: string;
var
Hour, Mins, Sec, MSec: Word;
Year, Month, Day: Word;
begin
DecodeTime(Now, Hour, Mins, Sec, MSec);
DecodeDate(Date, Year, Month, Day);
Result :=
PadZ(IntToStr(Day), 2)+PadZ(IntToStr(Month), 2)+PadZ(IntToStr(Year mod 100), 2)+
'_'+
Padz(IntToStr(Hour), 2)+PadZ(IntToStr(Mins), 2);
end;
function GetFileInfo(Tab: Integer; out LastFileName, LastScript: string): Boolean;
var
i: Integer;
v: string;
begin
Result := False;
i := FileNames.IndexOfName(IntToStr(Tab));
if (i < 0) then
Exit;
v := FileNames.Values[IntToStr(Tab)];
LastFileName := Trim(Copy(v, 1, 255));
LastScript := Copy(v, 256, Length(v) - 255);
Result := True;
end;
procedure SetFileInfo(Tab: Integer; FileName, Script: string);
begin
FileNames.Values[IntToStr(Tab)] := PadL(FileName, 255)+Script;
end;
procedure SplitRecoverInfo(Input: string; out FileName, Date, Time: string);
var
i: Integer;
s: TStringArray;
begin
FileName := '';
Date := '';
Time := '';
s := Explode('_', Input);
if (Length(s) < 2) then
Exit
else
begin
Time := s[High(s)];
Insert(':', Time, 3);
Date := s[High(s) - 1];
//Insert('''', Date, 5);
Insert('/', Date, 5);
Insert('/', Date, 3);
for i := 0 to High(s) - 2 do
begin
if (i > 0) then
FileName := FileName + '_';
FileName := FileName + s[i];
end;
end;
end;
procedure SetInterval(Sender: TObject);
var
i, intv: Integer;
begin
intv := Max(TMenuItem(Sender).Tag * 1000, 10000);
2010-10-02 14:24:24 -04:00
Settings.SetKeyValue('Interval', IntToStr(intv));
2010-10-02 14:12:21 -04:00
Timer.Interval := intv;
for i := 0 to Simba_Menu.Count - 1 do
Simba_Menu.Items[i].Checked := False;
TMenuItem(Sender).Checked := True;
end;
procedure ClearFiles(Sender: TObject);
var
i, t: Integer;
begin
if
(MessageDlg('CRov Extension (by Nielsie95)',
'This will erase all recovered files. Are you sure you want to continue?',
mtConfirmation, [mbYes, mbNo], 0
) <> mrYes)
then
Exit;
for i := Simba_Menu.Count - 1 downto 0 do
begin
t := Simba_Menu.Items[0].Tag;
if (t = 1) and FileExists(Simba_Menu.Items[0].Hint) then
DeleteFile(Simba_Menu.Items[0].Hint);
Simba_Menu.Delete(0);
if (t >= 3) then
Break;
end;
Simba_Menu.Visible := Simba_Menu.Count > 0;
end;
procedure TabChanged(Sender: TObject);
begin
Tab := Pointer(TPageControl(Sender).ActivePage);
Timer.Enabled := False;
Timer.Enabled := True; //Reset timer
end;
procedure OnTimer(Sender: TObject);
var
s: TStringList;
LastScript, LastFile,
Script, Title: string;
begin
TTimer(Sender).Enabled := False;
if (TTimer(Sender).Tag = 1) then
begin
TTimer(Sender).Tag := 0;
PageControl := FindPageControlWithName(Simba, 'PageControl1');
if (PageControl <> nil) then
PageControl.OnPageChanged := @TabChanged
else
WriteLn('CRov: PageControl not found!');
2010-10-02 14:24:24 -04:00
TTimer(Sender).Interval := StrToIntDef(Settings.GetKeyValueDef('Interval', DefInterval), 30000);
2010-10-02 14:12:21 -04:00
end;
try
Title := MyTime;
Script := ScriptText;
if (PageControl <> nil) then
if (LastChar(PageControl.ActivePage.Caption) = '*') then
Title := Replace(PageControl.ActivePage.Caption, '*', '', [rfReplaceAll])+'_'+Title
else
begin
//File saved/not modified, delete recovery file
if GetFileInfo(Tab, LastFile, LastScript) and (LastFile <> '') and (FileExists(LastFile)) then
DeleteFile(LastFile);
Exit;
end;
if GetFileInfo(Tab, LastFile, LastScript) and (LastScript = Script) then
Exit;
if (LastFile <> '') and (FileExists(LastFile)) then
DeleteFile(LastFile);
2010-10-02 14:24:24 -04:00
Title := Title+'.'+Extension;
2010-10-02 14:12:21 -04:00
s := TStringList.Create;
try
s.Text := Script;
2010-10-02 14:52:18 -04:00
s.SaveToFile(Dir+Title);
SetFileInfo(Tab, Dir+Title, Script);
2010-10-02 14:12:21 -04:00
finally
s.Free;
end;
finally
TTimer(Sender).Enabled := True;
end;
end;
procedure OnRecover(Sender: TObject);
var
a, b, c: string;
s: TStringList;
begin
a := TMenuItem(Sender).Hint;
2010-10-02 14:24:24 -04:00
Delete(a, Length(a) - Length('.'+Extension) + 1, Length('.'+Extension));
2010-10-02 14:12:21 -04:00
SplitRecoverInfo(a, a, b, c);
if (not ForceSave) then
begin
s := TStringList.Create;
try
s.LoadFromFile(TMenuItem(Sender).Hint);
OpenScript(a, s.Text);
finally
s.Free;
end;
end
else
with TSaveDialog.Create(Simba) do
begin
Title := 'Simba - Save Recovered File';
InitialDir := AppPath;
Filter:= 'Simba Files|*.simba;*.simb;*.cogat;*.mufa;*.txt;*.sex|Any files|*.*';
DefaultExt := 'simba';
FileName := a;
Options := Options + [ofOverwritePrompt];
if Execute then
begin
s := TStringList.Create;
try
s.LoadFromFile(TMenuItem(Sender).Hint);
s.SaveToFile(FileName);
finally
s.Free;
end;
end;
end;
end;
2010-10-03 13:33:08 -04:00
procedure onScriptStart(var Script: string; var Cont: Boolean);
begin
if SaveOnRun then
OnTimer(Timer);
Cont := True;
end;
procedure onScriptCompile(var Cont: Boolean);
begin
if SaveOnRun then
OnTimer(Timer);
Cont := True;
end;
2010-10-02 14:12:21 -04:00
procedure Init;
var
i: Integer;
f: TStringArray;
a, b, c: string;
Item: TMenuItem;
2010-10-02 14:24:24 -04:00
begin
SettingsMenu := LowerCase(Settings.GetKeyValueDef('SettingsInMenu', SettingsMenuDef)) = 'true';
ForceSave := LowerCase(Settings.GetKeyValueDef('ForceSave', ForceSaveDef)) = 'true';
2010-10-03 13:33:08 -04:00
SaveOnRun := LowerCase(Settings.GetKeyValueDef('SaveOnRun', SaveOnRunDef)) = 'true';
2010-10-02 14:52:18 -04:00
Dir := Settings.GetKeyValueDef('Directory', AppPath+DirDef);
2010-10-02 14:24:24 -04:00
Extension := Settings.GetKeyValueDef('Extension', ExtensionDef);
2010-10-02 14:12:21 -04:00
Simba_Menu := TMenuItem.Create(Simba_MainMenu);
Simba_Menu.Caption := 'Recover';
Simba_MainMenu.Items.Items[0].Insert(4, Simba_Menu);
Timer := TTimer.Create(Simba);
Timer.Interval := 2000;
Timer.OnTimer := @OnTimer;
Timer.Enabled := True;
Timer.Tag := 1;
FileNames := TStringList.Create;
2010-10-02 14:52:18 -04:00
if DirectoryExists(Dir) then
2010-10-02 14:12:21 -04:00
begin
2010-10-02 14:52:18 -04:00
f := GetFiles(Dir, Extension);
2010-10-02 14:12:21 -04:00
for i := 0 to High(f) do
begin
Item := TMenuItem.Create(Simba_Menu);
2010-10-02 14:52:18 -04:00
Item.Hint := Dir+f[i];
2010-10-02 14:12:21 -04:00
Item.Tag := 1;
Item.OnClick := @OnRecover;
2010-10-02 14:24:24 -04:00
Delete(f[i], Length(f[i]) - Length('.'+Extension) + 1, Length('.'+Extension));
2010-10-02 14:12:21 -04:00
SplitRecoverInfo(f[i], a, b, c);
if (a = '') then
a := '*UNTITLED*';
Item.Caption := a + ' (at '+c+' '+b+')';
Simba_Menu.Add(Item);
end;
2010-10-02 14:52:18 -04:00
end
else if (not CreateDirectory(Dir)) then
begin
WriteLn('CRov: Unknown directory! Falling back to Simba folder..');
Dir := AppPath;
2010-10-02 14:12:21 -04:00
end;
if (Length(f) > 0) then
begin
Item := TMenuItem.Create(Simba_Menu);
Item.Caption := 'Clear';
Item.Tag := 2;
Item.OnClick := @ClearFiles;
Simba_Menu.Add(Item);
a := 'Simba did not close correctly. There ';
if (Length(f) = 1) then
a := a + 'is 1 file'
else
a := a + 'are ' + IntToStr(Length(f)) + ' files';
a := a + ' found for recovery. You can find the files through the ' +
'"File>Recover" menu. If you do not wish to recover or if you are done ' +
'recovering, please clear the list through the menu.';
MessageDlg('CRov Extension (by Nielsie95)', a, mtInformation, [mbOK], 0);
end;
if SettingsMenu then
begin
if (Length(f) > 0) then
begin
Item := TMenuItem.Create(Simba_Menu);
Item.Caption := '-';
Item.Tag := 3;
Simba_Menu.Add(Item);
end;
Item := TMenuItem.Create(Simba_Menu);
Item.Caption := 'Backup every 30s';
Item.Tag := 30;
2010-10-02 14:24:24 -04:00
Item.Checked := Settings.GetKeyValueDef('Interval', DefInterval) = '30000';
2010-10-02 14:12:21 -04:00
Item.OnClick := @SetInterval;
Simba_Menu.Add(Item);
Item := TMenuItem.Create(Simba_Menu);
Item.Caption := 'Backup every 5m';
Item.Tag := 5 * 60;
2010-10-02 14:24:24 -04:00
Item.Checked := Settings.GetKeyValueDef('Interval', DefInterval) = '300000';
2010-10-02 14:12:21 -04:00
Item.OnClick := @SetInterval;
Simba_Menu.Add(Item);
Item := TMenuItem.Create(Simba_Menu);
Item.Caption := 'Backup every 20m';
Item.Tag := 20 * 60;
2010-10-02 14:24:24 -04:00
Item.Checked := Settings.GetKeyValueDef('Interval', DefInterval) = '1200000';
2010-10-02 14:12:21 -04:00
Item.OnClick := @SetInterval;
Simba_Menu.Add(Item);
end;
Simba_Menu.Visible := Simba_Menu.Count > 0;
end;
procedure Free;
var
i: Integer;
a, b: string;
begin
Timer.Enabled := False;
try
for i := 0 to FileNames.Count - 1 do
begin
if (not GetFileInfo(StrToIntDef(FileNames.Names[i], -1), a, b)) then
Continue;
if (a <> '') and FileExists(a) then
DeleteFile(a);
end;
finally
FileNames.Free;
end;
end;
procedure Attach;
begin
Simba_Menu.Visible := Simba_Menu.Count > 0;
Timer.Enabled := True;
end;
Procedure Detach;
begin
Timer.Enabled := False;
Simba_Menu.Visible := False;
end;
function GetName: string;
begin
Result := 'Crash Recovery (by Nielsie95)';
end;
function GetVersion: string;
begin
Result := Version;
end;
begin
end.