123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 |
- {$MODE objfpc}{$H+}
- uses
- SysUtils, StrUtils, Process;
- const
- use_temp_dir : boolean = true;
- hide_execution : boolean = true;
- do_exit : boolean =true;
- var
- OutputFileName : String;
- function GenerateTempDir: string;
- var
- FileName: string;
- TempDir: string;
- Done: Boolean = False;
- begin
- TempDir := GetTempDir(False);
- repeat
- try
- FileName := TempDir + 'dosboxwrappertmp_' + IntToStr(Random(100000));
- MkDir(FileName);
- Done := True;
- except
- on E: EInOutError do
- begin
- { 5 = Access Denied, returned when a file is duplicated }
- if E.ErrorCode <> 5 then
- raise;
- end;
- end;
- until Done;
- Result := FileName + DirectorySeparator;
- end;
- procedure GenerateDosBoxConf(const ADosBoxDir: string);
- var
- SourceConfFileName, TargetConfFileName: string;
- SourceFile, TargetFile: TextFile;
- S: string;
- begin
- SourceConfFileName := ExtractFilePath(ParamStr(0)) + 'dosbox.conf';
- TargetConfFileName := ADosBoxDir + 'dosbox.conf';
- OutputFileName := ADosBoxDir + 'dosbox.out';
- Writeln('Using target dosbox.conf ',TargetConfFileName);
- AssignFile(SourceFile, SourceConfFileName);
- AssignFile(TargetFile, TargetConfFileName);
- Reset(SourceFile);
- try
- Rewrite(TargetFile);
- try
- while not EoF(SourceFile) do
- begin
- Readln(SourceFile, S);
- S := AnsiReplaceStr(S, '$DosBoxDir', ADosBoxDir);
- S := AnsiReplaceStr(S, '$wrapper_output', OutputFileName);
- if do_exit then
- S := AnsiReplaceStr(S, '$exit', 'exit')
- else
- S := AnsiReplaceStr(S, '$exit', '');
- Writeln(TargetFile, S);
- end;
- finally
- CloseFile(TargetFile);
- end;
- finally
- CloseFile(SourceFile);
- end;
- end;
- procedure CopyFile(ASrcFileName, ADestFileName: string);
- var
- SrcF, DestF: File;
- OldFileMode: Integer;
- Buf: array [0..4095] of Byte;
- BytesRead: Integer;
- begin
- Writeln('CopyFile ', ASrcFileName, '->', ADestFileName);
- if not AnsiEndsText('.exe', ASrcFileName) then
- ASrcFileName := ASrcFileName + '.exe';
- OldFileMode := FileMode;
- try
- AssignFile(SrcF, ASrcFileName);
- AssignFile(DestF, ADestFileName);
- FileMode := fmOpenRead;
- Reset(SrcF, 1);
- try
- FileMode := fmOpenWrite;
- try
- Rewrite(DestF, 1);
- repeat
- BlockRead(SrcF, Buf, SizeOf(Buf), BytesRead);
- BlockWrite(DestF, Buf, BytesRead);
- until BytesRead < SizeOf(Buf);
- finally
- CloseFile(DestF);
- end;
- finally
- CloseFile(SrcF);
- end;
- finally
- FileMode := OldFileMode;
- end;
- end;
- { On modified dosbox executable it is possible to get
- a copy of all output to CON into a file, simply write it
- back to output, so it ends up into testname.elg file }
- procedure EchoOutput;
- var
- StdText : TextFile;
- st : string;
- line : longint;
- begin
- if FileExists(OutputFileName) then
- begin
- Writeln('Trying to open ',OutputFileName);
- try
- AssignFile(StdText, OutputFileName);
- Reset(StdText);
- Writeln('Successfully opened ',OutputFileName,', copying content to output');
- try
- line:=0;
- while not eof(StdText) do
- begin
- Readln(StdText,st);
- inc(line);
- Writeln(line,': ',st);
- end;
- finally
- CloseFile(StdText);
- end;
- finally
- if use_temp_dir then
- DeleteFile(OutputFileName);
- end;
- end;
- end;
- function ReadExitCode(const ADosBoxDir: string): Integer;
- var
- F: TextFile;
- begin
- AssignFile(F, ADosBoxDir + 'EXITCODE.TXT');
- Reset(F);
- try
- Readln(F, Result);
- if Result <> 0 then
- Writeln('ExitCode=',Result);
- except
- Writeln('Unable to read exitcode value');
- ReadExitCode:=127*256;
- end;
- CloseFile(F);
- end;
- procedure ExecuteDosBox(const ADosBoxBinaryPath, ADosBoxDir: string);
- const
- Timeout = 10*15; { 15 seconds }
- var
- Process: TProcess;
- Time: Integer = 0;
- begin
- Process := TProcess.Create(nil);
- try
- Process.Executable := ADosBoxBinaryPath;
- Process.Parameters.Add('-conf');
- Process.Parameters.Add(ADosBoxDir + 'dosbox.conf');
- if hide_execution then
- Process.ShowWindow := swoHIDE;
- Process.Execute;
- repeat
- Inc(Time);
- if (Time > Timeout) and do_exit then
- break;
- Sleep(100);
- until not Process.Running;
- if Process.Running then
- Process.Terminate(254);
- finally
- Process.Free;
- EchoOutput;
- end;
- end;
- procedure Cleanup(const ADosBoxDir: string);
- procedure DeleteIfExists(const AFileName: string);
- begin
- if FileExists(AFileName) then
- DeleteFile(AFileName);
- end;
- begin
- DeleteIfExists(ADosBoxDir + 'dosbox.conf');
- DeleteIfExists(ADosBoxDir + 'EXITCODE.TXT');
- DeleteIfExists(ADosBoxDir + 'EXITCODE.EXE');
- DeleteIfExists(ADosBoxDir + 'TEST.EXE');
- RmDir(ADosBoxDir);
- end;
- var
- DosBoxDir: string;
- ExitCode: Integer = 255;
- DosBoxBinaryPath: string;
- begin
- Randomize;
- if GetEnvironmentVariable('DOSBOX_NO_TEMPDIR')<>'' then
- begin
- use_temp_dir:=false;
- Writeln('use_temp_dir set to false');
- end;
- if GetEnvironmentVariable('DOSBOX_NO_HIDE')<>'' then
- begin
- hide_execution:=false;
- Writeln('hide_execution set to false');
- end;
- if GetEnvironmentVariable('DOSBOX_NO_EXIT')<>'' then
- begin
- do_exit:=false;
- Writeln('do_exit set to false');
- end;
- if ParamCount = 0 then
- begin
- Writeln('Usage: ' + ParamStr(0) + ' <executable>');
- Writeln('Set DOSBOX_NO_TEMPDIR env variable to 1 to avoid using a temporary directory');
- Writeln('Set DOSBOX_NO_HIDE to avoid running dosbox in an hidden window');
- Writeln('Set DOSBOX_NO_EXIT to avoid exiting dosbox after test has been run');
- halt(1);
- end;
- DosBoxBinaryPath := GetEnvironmentVariable('DOSBOX');
- if DosBoxBinaryPath = '' then
- begin
- Writeln('Please set the DOSBOX environment variable to the dosbox executable');
- halt(1);
- end
- else
- begin
- Writeln('Using DOSBOX executable: ',DosBoxBinaryPath);
- end;
- { DosBoxDir is used inside dosbox.conf as a MOUNT parameter }
- if use_temp_dir then
- DosBoxDir := GenerateTempDir
- else
- begin
- Writeln('Using ',ParamStr(1));
- DosBoxDir:=ExtractFilePath(ParamStr(1));
- if DosBoxDir='' then
- DosBoxDir:=GetCurrentDir+DirectorySeparator;
- Writeln('Using DosBoxDir=',DosBoxDir);
- end;
- try
- GenerateDosBoxConf(DosBoxDir);
- CopyFile(ExtractFilePath(ParamStr(0)) + 'exitcode.exe', DosBoxDir + 'EXITCODE.EXE');
- CopyFile(ParamStr(1), DosBoxDir + 'TEST.EXE');
- ExecuteDosBox(DosBoxBinaryPath, DosBoxDir);
- ExitCode := ReadExitCode(DosBoxDir);
- finally
- if use_temp_dir then
- Cleanup(DosBoxDir);
- end;
- halt(ExitCode);
- end.
|