dosbox_wrapper.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678
  1. {$MODE objfpc}{$H+}
  2. uses
  3. SysUtils, StrUtils,
  4. {$ifdef UseSignals}
  5. signals,
  6. {$endif def UseSignals}
  7. tsutils, tstypes, classes,
  8. Process;
  9. const
  10. use_temp_dir : boolean = true;
  11. temp_dir_generated : boolean = false;
  12. need_cwsdpmi : boolean = false;
  13. cwsdpmi_file : string = '';
  14. hide_execution : boolean = true;
  15. do_exit : boolean = true;
  16. verbose : boolean = false;
  17. DosBoxProcess: TProcess = nil;
  18. dosbox_timeout : integer = 400; { default timeout in seconds }
  19. DosBoxExitStatus : integer = -1;
  20. no_temp_dir_generated = '/no/temp/dir/generated/';
  21. var
  22. OutputFileName : String;
  23. SourceFileName : String;
  24. StartDir, DosBoxDir: string;
  25. TempDir: String;
  26. ExitCode: Integer = 255;
  27. DosBoxBinaryPath: string;
  28. TmpFileList : TStringList;
  29. function GenerateTempDir: string;
  30. const
  31. max_attempts = 10;
  32. var
  33. TempDirName: string;
  34. BaseTempDir: string;
  35. Done: Boolean = False;
  36. attempt: longint;
  37. begin
  38. BaseTempDir := GetTempDir(False);
  39. Result := no_temp_dir_generated;
  40. attempt := 0;
  41. repeat
  42. inc(attempt);
  43. try
  44. TempDirName := BaseTempDir + 'dosboxwrappertmp_' + IntToStr(Random(100000));
  45. if verbose then
  46. writeln('Trying to create directory ',TempDirName);
  47. MkDir(TempDirName);
  48. Done := True;
  49. temp_dir_generated := True;
  50. TempDir := TempDirName + DirectorySeparator;
  51. except
  52. on E: EInOutError do
  53. begin
  54. { 5 = Access Denied, returned when a file is duplicated }
  55. if E.ErrorCode <> 5 then
  56. begin
  57. Writeln('Directory creation failed');
  58. raise;
  59. end;
  60. end;
  61. on E: Exception do
  62. begin
  63. Writeln('Exception ',E.Message);
  64. Sleep(1000);
  65. end;
  66. end;
  67. until Done or (attempt > max_attempts);
  68. Result := TempDirName + DirectorySeparator;
  69. end;
  70. procedure GenerateDosBoxConf(const ADosBoxDir: string);
  71. var
  72. SourceConfFileName, TargetConfFileName: string;
  73. SourceFile, TargetFile: TextFile;
  74. OrigS, S: string;
  75. begin
  76. SourceConfFileName := ExtractFilePath(ParamStr(0)) + 'dosbox.conf';
  77. TargetConfFileName := ADosBoxDir + 'dosbox.conf';
  78. OutputFileName := ADosBoxDir + 'dosbox.out';
  79. if verbose then
  80. Writeln('Using target dosbox.conf ',TargetConfFileName);
  81. AssignFile(SourceFile, SourceConfFileName);
  82. AssignFile(TargetFile, TargetConfFileName);
  83. Reset(SourceFile);
  84. try
  85. Rewrite(TargetFile);
  86. try
  87. while not EoF(SourceFile) do
  88. begin
  89. Readln(SourceFile, S);
  90. OrigS:=S;
  91. S := AnsiReplaceStr(S, '$DosBoxDir', ADosBoxDir);
  92. S := AnsiReplaceStr(S, '$wrapper_output', OutputFileName);
  93. if do_exit then
  94. S := AnsiReplaceStr(S, '$exit', 'exit')
  95. else
  96. S := AnsiReplaceStr(S, '$exit', '');
  97. If verbose and (OrigS <> S) then
  98. Writeln('"',OrigS,'" transformed into "',S,'"');
  99. Writeln(TargetFile, S);
  100. end;
  101. finally
  102. CloseFile(TargetFile);
  103. end;
  104. finally
  105. CloseFile(SourceFile);
  106. end;
  107. end;
  108. { File names in Config entries assume that
  109. executables have no suffix }
  110. function TargetFileExists(AName : string) : boolean;
  111. begin
  112. result:=SysUtils.FileExists(AName);
  113. if not result then
  114. result:=SysUtils.FileExists(AName+'.exe');
  115. if not result then
  116. result:=SysUtils.FileExists(AName+'.EXE');
  117. end;
  118. procedure CopyFile(ASrcFileName, ADestFileName: string);
  119. var
  120. SrcF, DestF: File;
  121. OldFileMode: Integer;
  122. Buf: array [0..4095] of Byte;
  123. BytesRead: Integer;
  124. begin
  125. if not AnsiEndsText('.exe', ASrcFileName) and AnsiEndsText('.EXE',ADestFileName) then
  126. ASrcFileName := ASrcFileName + '.exe';
  127. if not FileExists(ASrcFileName) then
  128. begin
  129. ASrcFileName:=ASrcFileName+'.exe';
  130. ADestFileName:=ADestFileName+'.exe';
  131. end;
  132. if verbose then
  133. Writeln('CopyFile "', ASrcFileName, '" -> "', ADestFileName,'"');
  134. OldFileMode := FileMode;
  135. try
  136. try
  137. AssignFile(SrcF, ASrcFileName);
  138. AssignFile(DestF, ADestFileName);
  139. FileMode := fmOpenRead;
  140. Reset(SrcF, 1);
  141. try
  142. FileMode := fmOpenWrite;
  143. try
  144. Rewrite(DestF, 1);
  145. repeat
  146. BlockRead(SrcF, Buf, SizeOf(Buf), BytesRead);
  147. BlockWrite(DestF, Buf, BytesRead);
  148. until BytesRead < SizeOf(Buf);
  149. finally
  150. CloseFile(DestF);
  151. end;
  152. finally
  153. CloseFile(SrcF);
  154. end;
  155. finally
  156. FileMode := OldFileMode;
  157. end;
  158. except
  159. on E : Exception do
  160. writeln('Error: '+ E.ClassName + #13#10 + E.Message );
  161. end;
  162. end;
  163. function ForceExtension(Const HStr,ext:String):String;
  164. {
  165. Return a filename which certainly has the extension ext
  166. }
  167. var
  168. j : longint;
  169. begin
  170. j:=length(Hstr);
  171. while (j>0) and (Hstr[j]<>'.') do
  172. dec(j);
  173. if j=0 then
  174. j:=length(Hstr)+1;
  175. if Ext<>'' then
  176. begin
  177. if Ext[1]='.' then
  178. ForceExtension:=Copy(Hstr,1,j-1)+Ext
  179. else
  180. ForceExtension:=Copy(Hstr,1,j-1)+'.'+Ext
  181. end
  182. else
  183. ForceExtension:=Copy(Hstr,1,j-1);
  184. end;
  185. procedure CopyNeededFiles;
  186. var
  187. Config : TConfig;
  188. LocalFile, RemoteFile, s: string;
  189. LocalPath: string;
  190. i : integer;
  191. FileList : TStringList;
  192. RelativeToConfigMarker : TObject;
  193. function SplitPath(const s:string):string;
  194. var
  195. i : longint;
  196. begin
  197. i:=Length(s);
  198. while (i>0) and not(s[i] in ['/','\'{$IFDEF MACOS},':'{$ENDIF}]) do
  199. dec(i);
  200. SplitPath:=Copy(s,1,i);
  201. end;
  202. function BuildFileList: TStringList;
  203. var
  204. dfl, fl : string;
  205. begin
  206. fl:=Trim(Config.Files);
  207. dfl:=Trim(Config.DelFiles);
  208. if (fl='') and (dfl='') and (Config.ConfigFileSrc='') then
  209. begin
  210. Result:=nil;
  211. exit;
  212. end;
  213. Result:=TStringList.Create;
  214. while fl<>'' do
  215. begin
  216. LocalFile:=Trim(GetToken(fl, [' ',',',';']));
  217. Result.Add(LocalFile);
  218. if verbose then
  219. writeln('Adding file ',LocalFile,' from Config.Files');
  220. end;
  221. if Config.ConfigFileSrc<>'' then
  222. begin
  223. if Config.ConfigFileSrc=Config.ConfigFileDst then
  224. Result.AddObject(Config.ConfigFileSrc,RelativeToConfigMarker)
  225. else
  226. Result.AddObject(Config.ConfigFileSrc+'='+Config.ConfigFileDst,RelativeToConfigMarker);
  227. if verbose then
  228. writeln('Adding config file Src=',Config.ConfigFileSrc,' Dst=',Config.ConfigFileDst);
  229. end;
  230. while dfl <> '' do
  231. begin
  232. LocalFile:=Trim(GetToken(dfl, [' ',',',';']));
  233. Result.Add(LocalFile);
  234. if verbose then
  235. writeln('Adding file ',LocalFile,' from Config.DelFiles');
  236. end;
  237. end;
  238. var
  239. ddir : string;
  240. param1_dir : string;
  241. begin
  242. param1_dir:=ExtractFilePath(ParamStr(1));
  243. if not IsAbsolute(SourceFileName) and not TargetFileExists(SourceFileName) then
  244. begin
  245. ddir:=GetEnvironmentVariable('BASEDIR');
  246. if ddir='' then
  247. GetDir(0,ddir);
  248. // writeln('Start ddir=',ddir);
  249. while (ddir<>'') do
  250. begin
  251. if TargetFileExists(ddir+DirectorySeparator+SourceFileName) then
  252. begin
  253. SourceFileName:=ddir+DirectorySeparator+SourceFileName;
  254. break;
  255. end
  256. else
  257. begin
  258. if ddir=splitpath(ddir) then
  259. break
  260. else
  261. ddir:=splitpath(ddir);
  262. if ddir[length(ddir)]=DirectorySeparator then
  263. ddir:=copy(ddir,1,length(ddir)-1);
  264. // writeln('Next ddir=',ddir);
  265. end;
  266. end;
  267. end;
  268. if not TargetFileExists(SourceFileName) then
  269. begin
  270. writeln('File ',SourceFileName,' not found');
  271. exit;
  272. end
  273. else if verbose then
  274. writeln('Analyzing source file ',SourceFileName);
  275. if not GetConfig('',SourceFileName,config) then
  276. exit;
  277. RelativeToConfigMarker:=TObject.Create;
  278. FileList:=BuildFileList;
  279. TmpFileList:=TStringList.Create;
  280. if assigned(FileList) then
  281. begin
  282. LocalPath:=SplitPath(SourceFileName);
  283. if (Length(LocalPath) > 0) and (LocalPath[Length(LocalPath)]<>DirectorySeparator) then
  284. LocalPath:=LocalPath+DirectorySeparator;
  285. for i:=0 to FileList.count-1 do
  286. begin
  287. if FileList.Names[i]<>'' then
  288. begin
  289. LocalFile:=FileList.Names[i];
  290. RemoteFile:=FileList.ValueFromIndex[i];
  291. end
  292. else
  293. begin
  294. LocalFile:=FileList[i];
  295. RemoteFile:=LocalFile;
  296. end;
  297. if FileList.Objects[i]=RelativeToConfigMarker then
  298. s:='config/'+LocalFile
  299. else
  300. s:=LocalPath+LocalFile;
  301. if not TargetFileExists(s) then
  302. if TargetFileExists(param1_dir+DirectorySeparator+LocalFile) then
  303. s:=param1_dir+DirectorySeparator+LocalFile;
  304. CopyFile(s,DosBoxDir+RemoteFile);
  305. TmpFileList.Add(RemoteFile);
  306. end;
  307. FileList.Free;
  308. end;
  309. RelativeToConfigMarker.Free;
  310. end;
  311. { On modified dosbox executable it is possible to get
  312. a copy of all output to CON into a file, simply write it
  313. back to output, so it ends up into testname.elg file.
  314. Skip all until line beginning with 'Drive C is mounted as' }
  315. procedure EchoOutput;
  316. const
  317. SkipUntilText = 'Drive C is mounted as ';
  318. var
  319. StdText : TextFile;
  320. st : string;
  321. line : longint;
  322. SkipUntilSeen : boolean;
  323. begin
  324. if FileExists(OutputFileName) then
  325. begin
  326. if verbose then
  327. Writeln('Trying to open ',OutputFileName);
  328. try
  329. AssignFile(StdText, OutputFileName);
  330. Reset(StdText);
  331. if verbose then
  332. Writeln('Successfully opened ',OutputFileName,', copying content to output');
  333. try
  334. line:=0;
  335. SkipUntilSeen:=false;
  336. while not eof(StdText) do
  337. begin
  338. Readln(StdText,st);
  339. inc(line);
  340. if not SkipUntilSeen then
  341. SkipUntilSeen:=pos(SkipUntilText,st)>0;
  342. if SkipUntilSeen then
  343. Writeln(line,': ',st);
  344. end;
  345. finally
  346. if not SkipUntilSeen then
  347. Writeln('Could not find "',SkipUntilText,'" in file ',OutputFilename);
  348. Flush(output);
  349. CloseFile(StdText);
  350. end;
  351. finally
  352. if use_temp_dir and SkipUntilSeen then
  353. DeleteFile(OutputFileName);
  354. if use_temp_dir and not SkipUntilSeen then
  355. begin
  356. writeln('Setting temp_dir_generated to false');
  357. temp_dir_generated:=false;
  358. end;
  359. end;
  360. end;
  361. end;
  362. function ReadExitCode(const ADosBoxDir: string): Integer;
  363. var
  364. F: TextFile;
  365. S : ShortString;
  366. value : Integer;
  367. errpos : Word;
  368. begin
  369. AssignFile(F, ADosBoxDir + 'EXITCODE.TXT');
  370. if verbose and not FileExists(ADosBoxDir + 'EXITCODE.TXT') then
  371. writeln('ReadExitCode: '+ADosBoxDir + 'EXITCODE.TXT does not exist');
  372. try
  373. Reset(F);
  374. if verbose then
  375. begin
  376. Readln(F, S);
  377. system.Val(S,Value,errpos);
  378. if errpos=0 then
  379. Result:=value
  380. else
  381. begin
  382. writeln('ReadExitCode: First line "'+S+'" generated error at pos=',errpos);
  383. ReadExitCode:=126*256;
  384. exit;
  385. end;
  386. end
  387. else
  388. Readln(F, Result);
  389. if Result <> 0 then
  390. Writeln('ExitCode=',Result);
  391. CloseFile(F);
  392. except
  393. Writeln('Unable to read exitcode value');
  394. if (DosBoxExitStatus <> 0) then
  395. Writeln('DosBox exit status = ',DosBoxExitStatus);
  396. temp_dir_generated:=false;
  397. ReadExitCode:=127*256;
  398. end;
  399. if verbose then
  400. writeln('Test finished with ExitCode=',ReadExitCode);
  401. end;
  402. function ExecuteDosBox(const ADosBoxBinaryPath, ADosBoxDir: string) : Integer;
  403. var
  404. Time: Integer = 0;
  405. begin
  406. DosBoxProcess := TProcess.Create(nil);
  407. result:=-1;
  408. try
  409. DosBoxProcess.Executable := ADosBoxBinaryPath;
  410. DosBoxProcess.Parameters.Add('-conf');
  411. DosBoxProcess.Parameters.Add(ADosBoxDir + 'dosbox.conf');
  412. if hide_execution then
  413. DosBoxProcess.ShowWindow := swoHIDE;
  414. if verbose then
  415. writeln('Starting ',ADosBoxBinaryPath+' -conf dosbox.conf');
  416. DosBoxProcess.Execute;
  417. repeat
  418. Inc(Time);
  419. if (Time > 10*dosbox_timeout) and do_exit then
  420. break;
  421. Sleep(100);
  422. until not DosBoxProcess.Running;
  423. if DosBoxProcess.Running then
  424. begin
  425. Writeln('Timeout exceeded. Killing dosbox...');
  426. DosBoxProcess.Terminate(254);
  427. Sleep(100);
  428. end;
  429. finally
  430. result:=DosBoxProcess.ExitStatus;
  431. DosBoxProcess.Free;
  432. DosBoxProcess:=nil;
  433. EchoOutput;
  434. end;
  435. end;
  436. function DeleteIfExists(const AFileName: string) : boolean;
  437. begin
  438. result:=false;
  439. if FileExists(AFileName) then
  440. result:=DeleteFile(AFileName);
  441. if not result and FileExists(AFileName+'.exe') then
  442. result:=DeleteFile(AFileName+'.exe');
  443. if not result and FileExists(AFileName+'.EXE') then
  444. result:=DeleteFile(AFileName+'.EXE');
  445. end;
  446. { RemoveDir, with removal of files or subdirectories inside first.
  447. ADirName is supposed to finish with DirectorySeparator }
  448. function RemoveDir(const ADirName: string) : boolean;
  449. var
  450. Info : TSearchRec;
  451. begin
  452. Result:=true;
  453. If FindFirst (AdirName+'*',faAnyFile and faDirectory,Info)=0 then
  454. begin
  455. repeat
  456. with Info do
  457. begin
  458. If (Attr and faDirectory) = faDirectory then
  459. begin
  460. { Skip present and parent directory }
  461. if (Name<>'..') and (Name<>'.') then
  462. if not RemoveDir(ADirName+Name+DirectorySeparator) then
  463. begin
  464. writeln('Failed to remove dir '+ADirName+Name+DirectorySeparator);
  465. result:=false;
  466. FindClose(Info);
  467. exit;
  468. end;
  469. end
  470. else
  471. if not DeleteFile(ADirName+Name) then
  472. begin
  473. writeln('Failed to remove file '+ADirName+Name);
  474. result:=false;
  475. FindClose(Info);
  476. exit;
  477. end;
  478. end;
  479. Until FindNext(info)<>0;
  480. end;
  481. FindClose(Info);
  482. RemoveDir:=SysUtils.RemoveDir(ADirName);
  483. end;
  484. procedure Cleanup(const ADosBoxDir: string);
  485. var
  486. i : longint;
  487. begin
  488. if verbose then
  489. writeln('Cleanup '+ADosBoxDir);
  490. DeleteIfExists(ADosBoxDir + 'dosbox.conf');
  491. DeleteIfExists(ADosBoxDir + 'EXITCODE.TXT');
  492. DeleteIfExists(ADosBoxDir + 'EXITCODE.EXE');
  493. DeleteIfExists(ADosBoxDir + 'CWSDPMI.EXE');
  494. DeleteIfExists(ADosBoxDir + 'TEST.EXE');
  495. if Assigned(TmpFileList) then
  496. begin
  497. for i:=0 to TmpFileList.count-1 do
  498. if TmpFileList[i]<>'' then
  499. DeleteIfExists(ADosBoxDir + TmpFileList[i]);
  500. end;
  501. TmpFileList.Free;
  502. ChDir(StartDir);
  503. if not RemoveDir(ADosBoxDir) then
  504. writeln('Failed to remove dir ',ADosBoxDir);
  505. end;
  506. {$ifdef UseSignals}
  507. const
  508. SignalCalled : boolean = false;
  509. SignalNb : longint = 0;
  510. function DosBoxSignal(signal:longint):longint; cdecl;
  511. begin
  512. SignalCalled:=true;
  513. SignalNb:=signal;
  514. end;
  515. {$endif def UseSignals}
  516. procedure ExitProc;
  517. var
  518. count : longint;
  519. begin
  520. if assigned(DosBoxProcess) and (DosBoxProcess.Running) then
  521. begin
  522. Writeln('In ExitProc. Killing dosbox...');
  523. DosBoxProcess.Terminate(254*1024);
  524. Sleep(100);
  525. count:=1;
  526. while (DosBoxProcess.Running) do
  527. begin
  528. Sleep(100);
  529. inc(count);
  530. if (count mod 20=0) then
  531. DosBoxProcess.Terminate(254*1024+count);
  532. end;
  533. if count>1 then
  534. Writeln('In ExitProc. Wait for termination dosbox..., time=',count/10);
  535. EchoOutput;
  536. end;
  537. end;
  538. begin
  539. Randomize;
  540. if GetEnvironmentVariable('DOSBOX_NO_TEMPDIR')<>'' then
  541. begin
  542. use_temp_dir:=false;
  543. Writeln('use_temp_dir set to false');
  544. end;
  545. if GetEnvironmentVariable('DOSBOX_NO_HIDE')<>'' then
  546. begin
  547. hide_execution:=false;
  548. Writeln('hide_execution set to false');
  549. end;
  550. if GetEnvironmentVariable('DOSBOX_NO_EXIT')<>'' then
  551. begin
  552. do_exit:=false;
  553. Writeln('do_exit set to false');
  554. end;
  555. if GetEnvironmentVariable('DOSBOX_VERBOSE')<>'' then
  556. begin
  557. verbose:=true;
  558. Writeln('verbose set to true');
  559. end;
  560. if (GetEnvironmentVariable('DOSBOX_NEEDS_CWSDPMI')<>'') or
  561. (GetEnvironmentVariable('TEST_OS_TARGET')='go32v2') then
  562. begin
  563. need_cwsdpmi:=true;
  564. Writeln('need_cwsdpmi set to true');
  565. end;
  566. if GetEnvironmentVariable('DOSBOX_TIMEOUT')<>'' then
  567. begin
  568. dosbox_timeout:=StrToInt(GetEnvironmentVariable('DOSBOX_TIMEOUT'));
  569. Writeln('dosbox_timeout set to ', dosbox_timeout, ' seconds');
  570. end;
  571. if ParamCount = 0 then
  572. begin
  573. Writeln('Usage: ' + ParamStr(0) + ' <executable> (-Ssourcename)');
  574. Writeln('Set DOSBOX_NO_TEMPDIR env variable to 1 to avoid using a temporary directory');
  575. Writeln('Set DOSBOX_NO_HIDE to avoid running dosbox in an hidden window');
  576. Writeln('Set DOSBOX_NO_EXIT to avoid exiting dosbox after test has been run');
  577. Writeln('Set DOSBOX_TIMEOUT to set the timeout in seconds before killing the dosbox process, assuming the test has hanged');
  578. halt(1);
  579. end;
  580. DosBoxBinaryPath := GetEnvironmentVariable('DOSBOX');
  581. if DosBoxBinaryPath = '' then
  582. begin
  583. Writeln('Please set the DOSBOX environment variable to the dosbox executable');
  584. halt(1);
  585. end
  586. else
  587. begin
  588. Writeln('Using DOSBOX executable: ',DosBoxBinaryPath);
  589. end;
  590. { DosBoxDir is used inside dosbox.conf as a MOUNT parameter }
  591. if use_temp_dir then
  592. begin
  593. GetDir(0,StartDir);
  594. Try
  595. DosBoxDir := GenerateTempDir;
  596. Except
  597. Writeln('GenerateTempDir call failed');
  598. halt(1);
  599. end;
  600. { All executable test have t.*.pp pattern }
  601. if (paramcount>1) and (copy(paramstr(2),1,2)='-S') then
  602. SourceFileName:=copy(paramstr(2),3,length(paramstr(2)))
  603. else
  604. SourceFileName:=ForceExtension(Paramstr(1),'.pp');
  605. CopyNeededFiles;
  606. end
  607. else
  608. begin
  609. Writeln('Using ',ParamStr(1));
  610. DosBoxDir:=ExtractFilePath(ParamStr(1));
  611. if DosBoxDir='' then
  612. DosBoxDir:=GetCurrentDir+DirectorySeparator;
  613. Writeln('Using DosBoxDir=',DosBoxDir);
  614. { Get rid of previous exicode.txt file }
  615. DeleteIfExists(DosBoxDir + 'EXITCODE.TXT');
  616. end;
  617. try
  618. {$ifdef UseSignals}
  619. Signal(SIGINT,@DosBoxSignal);
  620. Signal(SIGQUIT,@DosBoxSignal);
  621. Signal(SIGTERM,@DosBoxSignal);
  622. {$endif def UseSignals}
  623. GenerateDosBoxConf(DosBoxDir);
  624. CopyFile(ExtractFilePath(ParamStr(0)) + 'exitcode.exe', DosBoxDir + 'EXITCODE.EXE');
  625. CopyFile(ParamStr(1), DosBoxDir + 'TEST.EXE');
  626. if need_cwsdpmi then
  627. begin
  628. cwsdpmi_file:=FileSearch('cwsdpmi.exe',GetEnvironmentVariable('PATH'));
  629. if cwsdpmi_file<>'' then
  630. CopyFile(cwsdpmi_file, DosBoxDir + 'CWSDPMI.EXE')
  631. else if verbose then
  632. writeln('cwsdpmi executable missing');
  633. end;
  634. DosBoxExitStatus:=ExecuteDosBox(DosBoxBinaryPath, DosBoxDir);
  635. finally
  636. ExitProc;
  637. end;
  638. {$ifdef UseSignals}
  639. if SignalCalled then
  640. begin
  641. Writeln('Signal ',SignalNb,' called');
  642. end;
  643. {$endif def UseSignals}
  644. ExitProc;
  645. ExitCode:=ReadExitCode(DosBoxDir);
  646. if use_temp_dir and temp_dir_generated then
  647. Cleanup(DosBoxDir);
  648. halt(ExitCode);
  649. end.