dosbox_wrapper.pas 18 KB

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