--HG-- branch : refac-jit extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/branches/refac-jit%402369
		
			
				
	
	
		
			225 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			225 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
| (* AMX Mod X
 | |
| *    compile.exe
 | |
| *
 | |
| * by the AMX Mod X Development Team
 | |
| *
 | |
| *
 | |
| *  This program is free software; you can redistribute it and/or modify it
 | |
| *  under the terms of the GNU General Public License as published by the
 | |
| *  Free Software Foundation; either version 2 of the License, or (at
 | |
| *  your option) any later version.
 | |
| *
 | |
| *  This program is distributed in the hope that it will be useful, but
 | |
| *  WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 | |
| *  General Public License for more details.
 | |
| *
 | |
| *  You should have received a copy of the GNU General Public License
 | |
| *  along with this program; if not, write to the Free Software Foundation,
 | |
| *  Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 | |
| *
 | |
| *  In addition, as a special exception, the author gives permission to
 | |
| *  link the code of this program with the Half-Life Game Engine ("HL
 | |
| *  Engine") and Modified Game Libraries ("MODs") developed by Valve,
 | |
| *  L.L.C ("Valve"). You must obey the GNU General Public License in all
 | |
| *  respects for all of the code used other than the HL Engine and MODs
 | |
| *  from Valve. If you modify this file, you may extend this exception
 | |
| *  to your version of the file, but you are not obligated to do so. If
 | |
| *  you do not wish to do so, delete this exception statement from your
 | |
| *  version.
 | |
| *)
 | |
| 
 | |
| unit uFunc;
 | |
| 
 | |
| interface
 | |
| 
 | |
| uses
 | |
|   Windows, SysUtils, Classes, Math, IniFiles;
 | |
| 
 | |
| resourcestring
 | |
|   COMPILER_EXE = 'spcomp.exe';
 | |
| 
 | |
| procedure AppExit;
 | |
| procedure CompilePlugin(const Name, OutputDir: String);
 | |
| function GetAgeFromDat(const FileName: String): Integer;
 | |
| procedure SetAgeToDat(const FileName: String; const Age: Integer);
 | |
| function GetConsoleOutput(const Command: String; var Output: TStringList): Boolean;
 | |
| 
 | |
| implementation
 | |
| 
 | |
| procedure AppExit;
 | |
| begin
 | |
|   WriteLn;
 | |
|   Write('Press enter to exit ...');
 | |
|   ReadLn;
 | |
|   Halt;
 | |
| end;
 | |
| 
 | |
| procedure CompilePlugin(const Name, OutputDir: String);
 | |
| var
 | |
|   Output: TStringList;
 | |
|   i: Word;
 | |
|   cStart,cEnd: Longword;
 | |
|   FileName, FilePath, Compiled: String;
 | |
| begin
 | |
|   FileName := ExtractFileName(Name);
 | |
|   FilePath := ExtractFilePath(Name);
 | |
|   if (OutputDir = '') then
 | |
|     Compiled := FilePath+'compiled\'+ChangeFileExt(Filename,'.smx')
 | |
|   else
 | |
|     Compiled := OutputDir+ChangeFileExt(Filename,'.smx');
 | |
| 
 | |
|   if (FilePath='') then
 | |
|     FilePath := ExtractFilePath(ParamStr(0));
 | |
| 
 | |
|   WriteLn;
 | |
|   WriteLn('//// '+ExtractFileName(FileName));
 | |
| 
 | |
|   if FileExists(Compiled) and ( GetAgeFromDat(Name)=FileAge(Name) ) then
 | |
|   begin
 | |
|     WriteLn('// Already compiled.');
 | |
|     WriteLn('// ----------------------------------------');
 | |
|     Exit;
 | |
|   end;
 | |
| 
 | |
|   Output := TStringList.Create;
 | |
| 
 | |
|   try
 | |
|     cStart := GetTickCount;
 | |
|     if not GetConsoleOutput(ExtractFilePath(ParamStr(0))+COMPILER_EXE+' "'+Name+'" "-o'+Compiled+'"',Output) then
 | |
|     begin
 | |
|       WriteLn('// Internal error.');
 | |
|       AppExit;
 | |
|     end;
 | |
|     cEnd := GetTickCount;
 | |
| 
 | |
|     for i := 3 to (Output.Count-1) do
 | |
|     begin
 | |
|       WriteLn('// '+Output.Strings[i]);
 | |
|     end;
 | |
| 
 | |
|     WriteLn('//');
 | |
|     WriteLn('// Compilation Time: '+FloatToStr(SimpleRoundTo((cEnd-cStart) / 1000,-2))+' sec');
 | |
|     WriteLn('// ----------------------------------------');
 | |
|     Output.Free;
 | |
|   except
 | |
|     WriteLn('// Internal error.');
 | |
|     AppExit;
 | |
|   end;
 | |
| 
 | |
|   SetAgeToDat(Name,FileAge(Name));
 | |
| end;
 | |
| 
 | |
| function GetAgeFromDat(const FileName: String): Integer;
 | |
| var
 | |
|   Ini: TIniFile;
 | |
| begin
 | |
|   Ini := TIniFile.Create(ExtractFilePath(ParamStr(0))+'compile.dat');
 | |
|   Result := Ini.ReadInteger(FileName,'Age',-1);
 | |
|   Ini.Free;
 | |
| end;
 | |
| 
 | |
| procedure SetAgeToDat(const FileName: String; const Age: Integer);
 | |
| var
 | |
|   Ini: TIniFile;
 | |
| begin
 | |
|   Ini := TIniFile.Create(ExtractFilePath(ParamStr(0))+'compile.dat');
 | |
|   Ini.WriteInteger(FileName,'Age',Age);
 | |
|   Ini.UpdateFile;
 | |
|   Ini.Free;
 | |
|   SetFileAttributes(PChar(ExtractFilePath(ParamStr(0))+'compile.dat'), faHidden);
 | |
| end;
 | |
| 
 | |
| function GetConsoleOutput(const Command: String; var Output: TStringList): Boolean;
 | |
| var
 | |
|   StartupInfo: TStartupInfo;
 | |
|   ProcessInfo: TProcessInformation;
 | |
|   SecurityAttr: TSecurityAttributes;
 | |
|   PipeOutputRead: THandle;
 | |
|   PipeOutputWrite: THandle;
 | |
|   PipeErrorsRead: THandle;
 | |
|   PipeErrorsWrite: THandle;
 | |
|   Succeed: Boolean;
 | |
|   Buffer: array [0..255] of Char;
 | |
|   NumberOfBytesRead: DWORD;
 | |
|   Stream: TMemoryStream;
 | |
|   Errors: String;
 | |
| begin
 | |
|   FillChar(ProcessInfo, SizeOf(TProcessInformation), 0);
 | |
|   FillChar(SecurityAttr, SizeOf(TSecurityAttributes), 0);
 | |
| 
 | |
|   SecurityAttr.nLength := SizeOf(SecurityAttr);
 | |
|   SecurityAttr.bInheritHandle := True;
 | |
|   SecurityAttr.lpSecurityDescriptor := nil;
 | |
| 
 | |
|   CreatePipe(PipeOutputRead, PipeOutputWrite, @SecurityAttr, 0);
 | |
|   CreatePipe(PipeErrorsRead, PipeErrorsWrite, @SecurityAttr, 0);
 | |
| 
 | |
|   FillChar(StartupInfo, SizeOf(TStartupInfo), 0);
 | |
|   StartupInfo.cb:=SizeOf(StartupInfo);
 | |
|   StartupInfo.hStdInput := 0;
 | |
|   StartupInfo.hStdOutput := PipeOutputWrite;
 | |
|   StartupInfo.hStdError := PipeErrorsWrite;
 | |
|   StartupInfo.wShowWindow := SW_HIDE;
 | |
|   StartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
 | |
| 
 | |
|   if  CreateProcess(nil, PChar(command), nil, nil, true, CREATE_DEFAULT_ERROR_MODE or CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS, nil, nil, StartupInfo, ProcessInfo) then begin
 | |
|     Result := True;
 | |
|     CloseHandle(PipeOutputWrite);
 | |
|     CloseHandle(PipeErrorsWrite);
 | |
| 
 | |
|     Stream := TMemoryStream.Create;
 | |
|     try
 | |
|       while True do begin
 | |
|         Succeed := ReadFile(PipeOutputRead, Buffer, 255, NumberOfBytesRead, nil);
 | |
|         if not Succeed then Break;
 | |
|         Stream.Write(Buffer, NumberOfBytesRead);
 | |
|       end;
 | |
|     finally
 | |
|       // nothing
 | |
|     end;
 | |
|     Stream.Position := 0;
 | |
|     Output.LoadFromStream(Stream);
 | |
|     Stream.Free;
 | |
|     CloseHandle(PipeOutputRead);
 | |
| 
 | |
|     Errors := '';
 | |
|     try
 | |
|       while True do
 | |
|       begin
 | |
|         Succeed := ReadFile(PipeErrorsRead, Buffer, 255, NumberOfBytesRead, nil);
 | |
|         if not Succeed then Break;
 | |
|         Errors := Errors + Copy(Buffer, 1, NumberOfBytesRead);
 | |
|       end;
 | |
|     finally
 | |
|       // nothing
 | |
|     end;
 | |
|     CloseHandle(PipeErrorsRead);
 | |
| 
 | |
|     WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
 | |
|     CloseHandle(ProcessInfo.hProcess);
 | |
|   end
 | |
|   else
 | |
|   begin
 | |
|     Result := False;
 | |
|     CloseHandle(PipeOutputRead);
 | |
|     CloseHandle(PipeOutputWrite);
 | |
|     CloseHandle(PipeErrorsRead);
 | |
|     CloseHandle(PipeErrorsWrite);
 | |
|   end;
 | |
|   // error management
 | |
|   if (Errors <> '') then begin
 | |
|     if (Output.Count > 1) then begin
 | |
|       if (Trim(Output[Output.Count -2]) = '') then
 | |
|         Output.Strings[Output.Count -2] := TrimRight(Errors)
 | |
|       else
 | |
|         Output.Insert(Output.Count -1, TrimRight(Errors));
 | |
|     end
 | |
|     else
 | |
|       Output.Add(Errors);
 | |
|     Output.Text := Output.Text; // pseudo-rearrangement
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| end.
 |