(* 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 = 'amxxpc.exe'; procedure AppExit; procedure CompilePlugin(const Name: 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: String); var Output: TStringList; i: Word; cStart,cEnd: Longword; FileName, FilePath, Compiled: String; begin FileName := ExtractFileName(Name); FilePath := ExtractFilePath(Name); Compiled := FilePath+'compiled\'+ChangeFileExt(Filename,'.amxx'); if (FilePath='') then FilePath := ExtractFilePath(ParamStr(0)); WriteLn; WriteLn('//// '+ExtractFileName(FileName)); if FileExists(Compiled) and ( GetAgeFromDat(FileName)=FileAge(Name) ) then begin WriteLn('// Already compiled.'); WriteLn('// ----------------------------------------'); Exit; end; Output := TStringList.Create; try cStart := GetTickCount; if not GetConsoleOutput(ExtractFilePath(ParamStr(0))+COMPILER_EXE+' "'+FilePath+FileName+'" "-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(FileName,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; 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; 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; Stream.Position := 0; Output.LoadFromStream(Stream); finally Stream.Free; end; CloseHandle(PipeOutputRead); try while True do begin Succeed := ReadFile(PipeErrorsRead, Buffer, 255, NumberOfBytesRead, nil); if not Succeed then Break; end; finally end; CloseHandle(PipeErrorsRead); WaitForSingleObject(ProcessInfo.hProcess, INFINITE); CloseHandle(ProcessInfo.hProcess); end else begin Result := False; CloseHandle(PipeOutputRead); CloseHandle(PipeOutputWrite); CloseHandle(PipeErrorsRead); CloseHandle(PipeErrorsWrite); end; end; end.