1
0
mirror of https://github.com/moparisthebest/Simba synced 2024-11-17 23:05:00 -05:00
Simba/Units/MMLAddon/mmlpsthread.pas

990 lines
30 KiB
ObjectPascal

{
This file is part of the Mufasa Macro Library (MML)
Copyright (c) 2009 by Raymond van Venetië and Merlijn Wajer
MML 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 3 of the License, or
(at your option) any later version.
MML 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 MML. If not, see <http://www.gnu.org/licenses/>.
See the file COPYING, included in this distribution,
for details about the copyright.
MMLPSThread for the Mufasa Macro Library
}
unit mmlpsthread;
{$Define PS_USESSUPPORT}
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, client, uPSComponent,uPSCompiler,
uPSRuntime,stdCtrls, uPSPreProcessor,MufasaTypes,MufasaBase, web,
bitmaps, plugins, libloader, dynlibs,internets,scriptproperties,
settingssandbox;
type
{ TMMLPSThread }
TSyncInfo = record
V : MufasaTypes.PVariantArray;
MethodName : string;
Res : ^Variant;
SyncMethod : procedure of object;
OldThread : TThread;
end;
TClearDebugProc = procedure;
TDbgImgInfo = record
DispSize : ^TPoint;
ShowForm : procedure of object;
ToDrawBitmap : ^TMufasaBitmap;
DrawBitmap : procedure of object;
GetDebugBitmap : ^TMufasaBitmap;
GetBitmap : procedure of object;
end;
PSyncInfo = ^TSyncInfo;
TErrorType = (errRuntime,errCompile);
TOnError = procedure of object;
TErrorData = record
Row,Col,Position : integer;
Error : string;
ErrType : TErrorType;
Module : string;
IncludePath : string;
end;
PErrorData = ^TErrorData;
TExpMethod = record
Section : string;
FuncDecl : string;
FuncPtr : Pointer;
end;
TExpMethodArr = array of TExpMethod;
TInputQueryData = record
ACaption, APrompt,Value : String;
Res : boolean;
end;
{ TMThread }
TMThread = class(TThread)
private
procedure SetOpenConnectionEvent(const AValue: TOpenConnectionEvent);
procedure SetOpenFileEvent(const AValue: TOpenFileEvent);
procedure SetWriteFileEvent(const AValue: TWriteFileEvent);
protected
ScriptPath, AppPath, IncludePath, PluginPath, FontPath: string;
DebugTo: TWritelnProc;
DebugClear : TClearDebugProc;
DebugImg : TDbgImgInfo;
ExportedMethods : TExpMethodArr;
Includes : TStringList;
Prop: TScriptProperties;
FOpenConnectionEvent : TOpenConnectionEvent;
FWriteFileEvent : TWriteFileEvent;
FOpenFileEvent : TOpenFileEvent;
procedure LoadPlugin(plugidx: integer); virtual; abstract;
public
Client : TClient;
MInternet : TMInternet;
StartTime : LongWord;
Sett: TMMLSettingsSandbox;
InputQueryData : TInputQueryData;//We need this for InputQuery
SyncInfo : PSyncInfo; //We need this for callthreadsafe
ErrorData : PErrorData; //We need this for thread-safety etc
OnError : TOnError; //Error handeler
CompileOnly : boolean;
procedure mInputQuery;
procedure HandleError(ErrorRow,ErrorCol,ErrorPosition : integer; ErrorStr : string; ErrorType : TErrorType; ErrorModule : string);
function ProcessDirective(DirectiveName, DirectiveArgs: string): boolean;
function LoadFile(ParentFile : string; var filename, contents: string): boolean;
procedure AddMethod(meth: TExpMethod); virtual;
procedure SetDebug( writelnProc : TWritelnProc );
procedure SetDebugClear( clearProc : TClearDebugProc );
procedure SetDbgImg( DebugImageInfo : TDbgImgInfo);
procedure SetPaths(ScriptP,AppP,IncludeP,PluginP,FontP : string);
procedure SetSettings(S: TMMLSettingsSandbox);
procedure OnThreadTerminate(Sender: TObject);
procedure SetScript(script: string); virtual; abstract;
procedure Execute; override; abstract;
procedure Terminate; virtual; abstract;
constructor Create(CreateSuspended: boolean; TheSyncInfo : PSyncInfo; plugin_dir: string);
destructor Destroy; override;
class function GetExportedMethods : TExpMethodArr;
property OpenConnectionEvent : TOpenConnectionEvent read FOpenConnectionEvent write SetOpenConnectionEvent;
property WriteFileEvent : TWriteFileEvent read FWriteFileEvent write SetWriteFileEvent;
property OpenFileEvent : TOpenFileEvent read FOpenFileEvent write SetOpenFileEvent;
end;
{ TPSThread }
TPSThread = class(TMThread)
public
procedure OnProcessDirective(Sender: TPSPreProcessor;
Parser: TPSPascalPreProcessorParser; const Active: Boolean;
const DirectiveName, DirectiveParam: string; var Continue: Boolean);
function PSScriptFindUnknownFile(Sender: TObject;
const OrginFileName: string; var FileName, Output: string): Boolean;
procedure PSScriptProcessUnknowDirective(Sender: TPSPreProcessor;
Parser: TPSPascalPreProcessorParser; const Active: Boolean;
const DirectiveName, DirectiveParam: string; var Continue: Boolean);
protected
PluginsToload : array of integer;
procedure LoadPlugin(plugidx: integer); override;
procedure OnCompile(Sender: TPSScript);
function RequireFile(Sender: TObject; const OriginFileName: String;
var FileName, OutPut: string): Boolean;
procedure OnCompImport(Sender: TObject; x: TPSPascalCompiler);
procedure OnExecImport(Sender: TObject; se: TPSExec; x: TPSRuntimeClassImporter);
procedure OutputMessages;
procedure HandleScriptTerminates;
public
PSScript : TPSScript;
constructor Create(CreateSuspended: Boolean; TheSyncInfo : PSyncInfo; plugin_dir: string);
destructor Destroy; override;
procedure SetScript(script: string); override;
procedure Execute; override;
procedure Terminate; override;
end;
TPrecompiler_Callback = function(name, args: PChar): boolean; stdcall;
TErrorHandeler_Callback = procedure(line, pos: integer; err: PChar; runtime: boolean); stdcall;
TCPThread = class(TMThread)
protected
instance: pointer;
added_methods: array of TExpMethod;
procedure LoadPlugin(plugidx: integer); override;
public
constructor Create(CreateSuspended: Boolean; TheSyncInfo : PSyncInfo; plugin_dir: string);
destructor Destroy; override;
procedure SetScript(script: string); override;
procedure Execute; override;
procedure Terminate; override;
procedure AddMethod(meth: TExpMethod); override;
end;
threadvar
CurrThread : TMThread;
var
PluginsGlob: TMPlugins;
libcpascal: integer;
interp_init: function(precomp: TPrecompiler_Callback; err: TErrorHandeler_Callback): Pointer; cdecl;
interp_meth: procedure(interp: Pointer; addr: Pointer; def: PChar); cdecl;
interp_type: procedure(interp: Pointer; def: PChar); cdecl;
interp_set: procedure(interp: Pointer; ppg: PChar); cdecl;
interp_comp: function(interp: Pointer): boolean; cdecl;
interp_run: function(interp: Pointer): boolean; cdecl;
interp_free: procedure(interp: Pointer); cdecl;
implementation
uses
colour_conv,dtmutil,
{$ifdef mswindows}windows, MMSystem,{$endif}//MMSystem -> Sounds
uPSC_std, uPSC_controls,uPSC_classes,uPSC_graphics,uPSC_stdctrls,uPSC_forms, uPSC_menus,
uPSC_extctrls, uPSC_mml, //Compile-libs
uPSUtils,
fontloader,
IOmanager,//TTarget_Exported
IniFiles,//Silly INI files
stringutil, //String st00f
uPSR_std, uPSR_controls,uPSR_classes,uPSR_graphics,uPSR_stdctrls,uPSR_forms, uPSR_mml,
uPSR_menus, uPSI_ComCtrls, uPSI_Dialogs,
files,
dialogs,
dtm, //Dtms!
uPSR_extctrls, //Runtime-libs
Graphics, //For Graphics types
math, //Maths!
mmath, //Real maths!
strutils,
fileutil,
tpa, //Tpa stuff
forms,//Forms
SynRegExpr,
lclintf // for GetTickCount and others.
;
{$ifdef Linux}
{$define PS_SafeCall}
{$else}
//{$define PS_SafeCall}
{$endif}
{$MACRO ON}
{$ifdef PS_SafeCall}
{$define extdecl := safecall}
{$else}
{$define extdecl := register}
{$endif}
{Some General PS Functions here}
procedure psWriteln(str : string); extdecl;
begin
if CurrThread.Prop.WriteTimeStamp then
str := format('[%s]: %s', [TimeToStr(TimeStampToDateTime(MSecsToTimeStamp(GetTickCount - CurrThread.StartTime))), str]);
if Assigned(CurrThread.DebugTo) then
CurrThread.DebugTo(str)
else
mDebugLn(str);
end;
procedure ps_DebugLn(str : string); extdecl;
begin
if CurrThread.Prop.WriteTimeStamp then
str := format('[%s]: %s', [TimeToStr(TimeStampToDateTime(MSecsToTimeStamp(GetTickCount - CurrThread.StartTime))), str]);
mDebugLn(str);
end;
function MakeString(data : TPSVariantIFC) : string;
begin;
if data.Dta = nil then
result := 'Nil'
else
if data.aType.basetype in [btString,btChar] then
result := PSGetAnsiString(Data.Dta,data.aType)
else if data.aType.ExportName = 'BOOLEAN' then
result := BoolToStr(PSGetInt(Data.Dta,data.aType) <> 0,true)
else
result := PSVariantToString(data,'');
end;
function writeln_(Caller: TPSExec; p: TPSExternalProcRec; Global, Stack: TPSStack): Boolean;
begin
Result:=true;
psWriteln(makeString(NewTPSVariantIFC(Stack[Stack.Count-1],false)));
end;
function swap_(Caller: TPSExec; p: TPSExternalProcRec; Global, Stack: TPSStack): Boolean;
var
Param1,Param2: TPSVariantIFC;
tempCopy : pointer;
begin
Result:=true;
Param1 := NewTPSVariantIFC(Stack[Stack.count-1],true);
Param2 := NewTPSVariantIFC(Stack[Stack.count-2],true);
if Param1.aType.BaseType <> Param2.aType.BaseType then
exit(false)
else
begin
Param1.aType.CalcSize;
param2.aType.CalcSize;
if Param1.aType.RealSize <> Param2.aType.RealSize then
exit(false);
GetMem(tempcopy,Param1.aType.RealSize);
Move(Param1.Dta^,tempCopy^,param1.atype.realsize);
Move(Param2.Dta^,Param1.Dta^,param1.atype.realsize);
Move(tempCopy^,Param2.Dta^,param1.atype.realsize);
Freemem(tempcopy);
end;
end;
function ToStr_(Caller: TPSExec; p: TPSExternalProcRec; Global, Stack: TPSStack): Boolean;
begin
result := true;
Stack.SetAnsiString(-1, MakeString(NewTPSVariantIFC(Stack[Stack.Count-2],false)));
end;
{***implementation TMThread***}
constructor TMThread.Create(CreateSuspended: boolean; TheSyncInfo: PSyncInfo; plugin_dir: string);
begin
inherited Create(CreateSuspended);
Client := TClient.Create(plugin_dir);
if Assigned(WriteFileEvent) then
Client.MFiles.WriteFileEvent := WriteFileEvent;
if Assigned(OpenFileEvent) then
Client.MFiles.OpenFileEvent := OpenFileEvent;
MInternet := TMInternet.Create(Client);
if Assigned(OpenConnectionEvent) then
MInternet.OpenConnectionEvent := Self.OpenConnectionEvent;
SyncInfo:= TheSyncInfo;
ExportedMethods:= GetExportedMethods;
FreeOnTerminate := True;
CompileOnly := false;
OnTerminate := @OnThreadTerminate;
OnError:= nil;
Includes := TStringList.Create;
Includes.CaseSensitive:= {$ifdef linux}true{$else}false{$endif};
Sett := nil;
Prop := TScriptProperties.Create;
end;
destructor TMThread.Destroy;
begin
MInternet.Free;
Client.Free;
Includes.free;
Prop.Free;
if Sett <> nil then
Sett.Free;
inherited Destroy;
end;
procedure TMThread.SetOpenConnectionEvent(const AValue: TOpenConnectionEvent);
begin
FOpenConnectionEvent:= AValue;
if Assigned(MInternet) then
self.MInternet.OpenConnectionEvent := AValue;
end;
procedure TMThread.SetOpenFileEvent(const AValue: TOpenFileEvent);
begin
FOpenFileEvent:= AValue;
if Assigned(Client) then
self.Client.MFiles.OpenFileEvent := AValue;
end;
procedure TMThread.SetWriteFileEvent(const AValue: TWriteFileEvent);
begin
FWriteFileEvent:= AValue;
if Assigned(Client) then
self.Client.MFiles.WriteFileEvent := AValue;;
end;
procedure TMThread.mInputQuery;
begin
InputQueryData.Res:= InputQuery(InputQueryData.ACaption,InputQueryData.APrompt,
InputQueryData.Value);
end;
procedure TMThread.HandleError(ErrorRow,ErrorCol, ErrorPosition: integer; ErrorStr: string; ErrorType: TErrorType; ErrorModule : string);
begin
if OnError = nil then
exit;
ErrorData^.Row:= ErrorRow - 1;
ErrorData^.Col := ErrorCol;
ErrorData^.Position:= ErrorPosition;
ErrorData^.Error:= ErrorStr;
ErrorData^.ErrType:= ErrorType;
ErrorData^.Module:= ErrorModule;
ErrorData^.IncludePath:= IncludePath;
CurrThread.Synchronize(OnError);
end;
procedure TMThread.OnThreadTerminate(Sender: TObject);
begin
end;
procedure TMThread.AddMethod(meth: TExpMethod);
begin
end;
function TMThread.LoadFile(ParentFile : string; var filename, contents: string): boolean;
var
path: string;
f: TFileStream;
begin
path := FindFile(filename,[includepath,ScriptPath,IncludeTrailingPathDelimiter(ExtractFileDir(parentfile))]);
if path = '' then
begin
psWriteln(Path + ' doesn''t exist');
Result := false;
Exit;
end;
filename := path;//Yeah!
Includes.Add(path);
try
f:= TFileStream.Create(UTF8ToSys(Path), fmOpenRead or fmShareDenyWrite);
SetLength(contents, f.Size);
f.Read(contents[1], Length(contents));
result:= true;
f.free;
except
Result := false;
psWriteln('ERROR in TMThread.LoadFile');
end;
end;
function TMThread.ProcessDirective(DirectiveName, DirectiveArgs: string): boolean;
var
plugin_idx, i: integer;
path : string;
begin
Result := False;
if CompareText(DirectiveName,'LOADLIB') = 0 then
begin
if DirectiveArgs <> '' then
begin;
plugin_idx:= PluginsGlob.LoadPlugin(DirectiveArgs);
if plugin_idx < 0 then
psWriteln(Format('Your DLL %s has not been found',[DirectiveArgs]))
else
begin
LoadPlugin(plugin_idx);
Result:= True;
end;
end
else
psWriteln('Your LoadLib directive has no params, thus cannot find the plugin');
end
else if CompareText(DirectiveName,'INCLUDE_ONCE') = 0 then
begin
Result := True; //Lets to the actual file checking later on in the preprocessor ;-)
if (DirectiveArgs <> '') then
begin
path := FindFile(DirectiveArgs,[ScriptPath,IncludePath]);
if (path <> '') then
if Includes.Find(path,i) then
begin
psWriteln('Include_Once file already included');
Result := False;
end;
end;
end else
Result := True;
end;
procedure TMThread.SetDebug(writelnProc: TWritelnProc);
begin
DebugTo := writelnProc;
Client.WritelnProc:= writelnProc;
end;
procedure TMThread.SetDebugClear(clearProc: TClearDebugProc);
begin
DebugClear:= clearProc;
end;
procedure TMThread.SetDbgImg(DebugImageInfo: TDbgImgInfo);
begin
DebugImg := DebugImageInfo;
end;
procedure TMThread.SetSettings(S: TMMLSettingsSandbox);
begin
Self.Sett := S;
end;
procedure TMThread.SetPaths(ScriptP, AppP,IncludeP,PluginP,FontP: string);
begin
AppPath:= AppP;
ScriptPath:= ScriptP;
IncludePath:= IncludeP;
PluginPath:= PluginP;
FontPath:= FontP;
end;
function ThreadSafeCall(ProcName: string; var V: TVariantArray): Variant; extdecl;
begin
if GetCurrentThreadId = MainThreadID then
begin
with TPSThread(currthread).PSScript do
Result := Exec.RunProcPVar(V,Exec.GetProc(Procname));
end else
begin
CurrThread.SyncInfo^.MethodName:= ProcName;
CurrThread.SyncInfo^.V:= @V;
CurrThread.SyncInfo^.OldThread := CurrThread;
CurrThread.SyncInfo^.Res := @Result;
CurrThread.Synchronize(CurrThread.SyncInfo^.SyncMethod);
end;
end;
{$I PSInc/Wrappers/other.inc}
{$I PSInc/Wrappers/settings.inc}
{$I PSInc/Wrappers/bitmap.inc}
{$I PSInc/Wrappers/window.inc}
{$I PSInc/Wrappers/tpa.inc}
{$I PSInc/Wrappers/strings.inc}
{$I PSInc/Wrappers/colour.inc}
{$I PSInc/Wrappers/colourconv.inc}
{$I PSInc/Wrappers/math.inc}
{$I PSInc/Wrappers/mouse.inc}
{$I PSInc/Wrappers/file.inc}
{$I PSInc/Wrappers/keyboard.inc}
{$I PSInc/Wrappers/dtm.inc}
{$I PSInc/Wrappers/ocr.inc}
{$I PSInc/Wrappers/internets.inc}
class function TMThread.GetExportedMethods: TExpMethodArr;
var
c : integer;
CurrSection : string;
procedure SetCurrSection(str : string);
begin;
CurrSection := Str;
end;
procedure AddFunction( Ptr : Pointer; DeclStr : String);
begin;
if c >= 400 then
raise exception.create('PSThread.LoadMethods: Exported more than 400 functions');
Result[c].FuncDecl:= DeclStr;
Result[c].FuncPtr:= Ptr;
Result[c].Section:= CurrSection;
inc(c);
end;
begin
c := 0;
CurrSection := 'Other';
SetLength(Result,400);
{$i PSInc/psexportedmethods.inc}
SetLength(Result,c);
end;
{***implementation TPSThread***}
constructor TPSThread.Create(CreateSuspended : boolean; TheSyncInfo : PSyncInfo; plugin_dir: string);
var
I : integer;
begin
inherited Create(CreateSuspended, TheSyncInfo, plugin_dir);
PSScript := TPSScript.Create(nil);
PSScript.UsePreProcessor:= True;
PSScript.CompilerOptions := PSScript.CompilerOptions + [icBooleanShortCircuit];
PSScript.OnNeedFile := @RequireFile;
PSScript.OnProcessDirective:=@OnProcessDirective;
PSScript.OnProcessUnknowDirective:=@PSScriptProcessUnknowDirective;
PSScript.OnCompile:= @OnCompile;
PSScript.OnCompImport:= @OnCompImport;
PSScript.OnExecImport:= @OnExecImport;
PSScript.OnFindUnknownFile:=@PSScriptFindUnknownFile;
// Set some defines
{$I PSInc/psdefines.inc}
for i := 0 to high(ExportedMethods) do
if pos('Writeln',exportedmethods[i].FuncDecl) > 0 then
begin
ExportedMethods[i].FuncPtr := nil;
break;
end;
end;
destructor TPSThread.Destroy;
begin
PSScript.Free;
inherited;
end;
procedure TPSThread.OnProcessDirective(Sender: TPSPreProcessor;
Parser: TPSPascalPreProcessorParser; const Active: Boolean;
const DirectiveName, DirectiveParam: string; var Continue: Boolean);
begin
if CompareText(DirectiveName, 'LOADLIB') = 0 then
Continue := not ProcessDirective(DirectiveName,DirectiveParam);
end;
function TPSThread.PSScriptFindUnknownFile(Sender: TObject;
const OrginFileName: string; var FileName, Output: string): Boolean;
begin
mDebugLn(OrginFileName + '-' + Output + '-' + FileName);
Result := false;
end;
procedure TPSThread.PSScriptProcessUnknowDirective(Sender: TPSPreProcessor;
Parser: TPSPascalPreProcessorParser; const Active: Boolean;
const DirectiveName, DirectiveParam: string; var Continue: Boolean);
begin
Continue:= not ProcessDirective(DirectiveName, DirectiveParam);
end;
function Muf_Conv_to_PS_Conv( conv : integer) : TDelphiCallingConvention;
begin
case conv of
cv_StdCall : result := cdStdCall;
cv_Register: result := cdRegister;
else
raise exception.createfmt('Unknown Calling Convention[%d]',[conv]);
end;
end;
procedure TPSThread.LoadPlugin(plugidx: integer);
var
i: integer;
begin
for i := High(PluginsToLoad) downto 0 do
if PluginsToLoad[i] = plugidx then
Exit;
SetLength(PluginsToLoad,Length(PluginsToLoad)+1);
PluginsToLoad[High(PluginsToLoad)]:= plugidx;
end;
procedure TPSThread.OnCompile(Sender: TPSScript);
var
i,ii : integer;
Fonts : TMFonts;
begin
Fonts := Client.MOCR.Fonts;
for i := fonts.count - 1 downto 0 do
Sender.Comp.AddConstantN(Fonts[i].Name,'string').SetString(Fonts[i].Name);
for i := high(PluginsToLoad) downto 0 do
for ii := 0 to PluginsGlob.MPlugins[PluginsToLoad[i]].MethodLen - 1 do
Sender.AddFunctionEx(PluginsGlob.MPlugins[PluginsToLoad[i]].Methods[ii].FuncPtr,
PluginsGlob.MPlugins[PluginsToLoad[i]].Methods[ii].FuncStr,
Muf_Conv_to_PS_Conv(PluginsGlob.MPlugins[PluginsToLoad[i]].Methods[ii].FuncConv));
for i := 0 to high(VirtualKeys) do
Sender.Comp.AddConstantN(Format('VK_%S',[VirtualKeys[i].Str]),'Byte').SetInt(VirtualKeys[i].Key);
// Here we add all the Consts/Types to the engine.
//Export all the methods
for i := 0 to high(ExportedMethods) do
if ExportedMethods[i].FuncPtr <> nil then
Sender.AddFunctionEx(ExportedMethods[i].FuncPtr,ExportedMethods[i].FuncDecl,
{$ifdef PS_SafeCall}cdSafeCall{$else}cdRegister{$endif});
end;
function TPSThread.RequireFile(Sender: TObject;
const OriginFileName: String; var FileName, OutPut: string): Boolean;
begin
Result := LoadFile(OriginFileName,FileName,OutPut);
if Result then
Output :=
'{$IFNDEF IS_INCLUDE}{$DEFINE IS_INCLUDE}{$DEFINE __REMOVE_IS_INCLUDE}{$ENDIF}' + LineEnding +
Output + LineEnding +
'{$IFDEF __REMOVE_IS_INCLUDE}{$UNDEF IS_INCLUDE}{$ENDIF}';
end;
procedure SIRegister_Mufasa(cl: TPSPascalCompiler);
begin
SIRegister_MML(cl);
end;
procedure TPSThread.OnCompImport(Sender: TObject; x: TPSPascalCompiler);
begin
SIRegister_Std(x);
SIRegister_Controls(x);
SIRegister_Classes(x, true);
SIRegister_Graphics(x, true);
SIRegister_stdctrls(x);
SIRegister_Forms(x);
SIRegister_ExtCtrls(x);
SIRegister_Menus(x);
SIRegister_ComCtrls(x);
SIRegister_Dialogs(x);
{$I PSInc/pscompile.inc}
SIRegister_Mufasa(x);
with x.AddFunction('procedure writeln;').decl do
with AddParam do
begin
OrgName:= 'x';
Mode:= pmIn;
end;
with x.AddFunction('function ToStr:string').decl do
with addparam do
begin
OrgName:= 'x';
Mode:= pmIn;
end;
with x.AddFunction('procedure swap;').decl do
begin
with addparam do
begin
OrgName:= 'x';
Mode:= pmInOut;
end;
with addparam do
begin
OrgName:= 'y';
Mode:= pmInOut;
end;
end;
end;
function TMufasaBitmapCreate : TMufasaBitmap;
begin;
result := TMufasaBitmap.Create;
CurrThread.Client.MBitmaps.AddBMP(result);
end;
procedure TMufasaBitmapFree(Self : TMufasaBitmap);begin; CurrThread.Client.MBitmaps.FreeBMP(Self.Index); end;
function TMufasaBitmapCopy(Self : TMufasaBitmap;const xs,ys,xe,ye : integer) : TMufasaBitmap;
begin
result := Self.Copy(xs,ys,xe,ye);
CurrThread.Client.MBitmaps.AddBMP(result);
end;
procedure TMufasaBitmapCopyClientToBitmap(self : TMufasaBitmap; Resize : boolean;x,y : integer; xs, ys, xe, ye: Integer);
begin
self.CopyClientToBitmap(CurrThread.Client.IOManager,resize,x,y,xs,ys,xe,ye);
end;
function TMDTMCreate : TMDTM;
begin
result := TMDTM.Create;
CurrThread.Client.MDTMs.AddDTM(result);
end;
procedure TMDTMFree(Self : TMDTM);
begin
CurrThread.Client.MDTMs.FreeDTM(self.Index);
end;
procedure RIRegister_Mufasa(CL: TPSRuntimeClassImporter);
begin
RIRegister_MML(cl);
//Overwrites the default stuff
with cl.FindClass('TMufasaBitmap') do
begin
RegisterConstructor(@TMufasaBitmapCreate,'Create');
RegisterMethod(@TMufasaBitmapFree,'Free');
RegisterMethod(@TMufasaBitmapCopy,'Copy');
RegisterMethod(@TMufasaBitmapCopyClientToBitmap,'CopyClientToBitmap');
end;
With cl.FindClass('TMDTM') do
begin
RegisterConstructor(@TMDTMCreate,'Create');
RegisterMethod(@TMDTMFree,'Free');
end;
end;
procedure TPSThread.OnExecImport(Sender: TObject; se: TPSExec;
x: TPSRuntimeClassImporter);
begin
RIRegister_Std(x);
RIRegister_Classes(x, True);
RIRegister_Controls(x);
RIRegister_Graphics(x, True);
RIRegister_stdctrls(x);
RIRegister_Forms(x);
RIRegister_ExtCtrls(x);
RIRegister_Menus(x);
RIRegister_Mufasa(x);
RIRegister_ComCtrls(x);
RIRegister_Dialogs(x);
se.RegisterFunctionName('WRITELN',@Writeln_,nil,nil);
se.RegisterFunctionName('TOSTR',@ToStr_,nil,nil);
se.RegisterFunctionName('SWAP',@swap_,nil,nil);
end;
procedure TPSThread.OutputMessages;
var
l: Longint;
b: Boolean;
begin
b := False;
for l := 0 to PSScript.CompilerMessageCount - 1 do
begin
if (not b) and (PSScript.CompilerMessages[l] is TIFPSPascalCompilerError) then
begin
b := True;
if OnError <> nil then
with PSScript.CompilerMessages[l] do
HandleError(Row, Col, Pos, MessageToString,errCompile, ModuleName)
else
psWriteln(PSScript.CompilerErrorToStr(l) + ' at line ' + inttostr(PSScript.CompilerMessages[l].Row - 1));
end else
psWriteln(PSScript.CompilerErrorToStr(l) + ' at line ' + inttostr(PSScript.CompilerMessages[l].Row - 1));
end;
end;
procedure TPSThread.HandleScriptTerminates;
var
I : integer;
begin
if (PSScript.Exec.ExceptionCode =ErNoError) and (SP_OnTerminate in Prop.Properties) then
begin;
for i := 0 to Prop.OnTerminateProcs.Count - 1 do
begin
try
PSScript.ExecuteFunction([],Prop.OnTerminateProcs[i]);
finally
end;
end;
end;
end;
procedure TPSThread.Execute;
begin
CurrThread := Self;
Starttime := lclintf.GetTickCount;
try
if PSScript.Compile then
begin
OutputMessages;
psWriteln('Compiled succesfully in ' + IntToStr(GetTickCount - Starttime) + ' ms.');
if CompileOnly then
exit;
// if not (ScriptState = SCompiling) then
if not PSScript.Execute then
HandleError(PSScript.ExecErrorRow,PSScript.ExecErrorCol,PSScript.ExecErrorPosition,PSScript.ExecErrorToString,
errRuntime, PSScript.ExecErrorFileName)
else
begin
HandleScriptTerminates;
psWriteln('Successfully executed.');
end;
end else
begin
OutputMessages;
psWriteln('Compiling failed.');
end;
except
on E : Exception do
psWriteln('Exception in Script: ' + e.message);
end;
end;
procedure TPSThread.Terminate;
begin
PSScript.Stop;
end;
procedure TPSThread.SetScript(script: string);
begin
PSScript.Script.Text:= LineEnding+Script; //A LineEnding to create space for future extra's in first line (defines?)
end;
{***implementation TCPThread***}
procedure LoadCPascal(plugin_dir: string);
begin
libcpascal:= LoadLibrary(PChar(plugin_dir + 'libcpascal' + {$ifdef LINUX} '.so' {$else} '.dll' {$endif}));
if libcpascal = 0 then
raise Exception.Create('CPascal library not found');
Pointer(interp_init):= GetProcAddress(libcpascal, PChar('interp_init'));
Pointer(interp_meth):= GetProcAddress(libcpascal, PChar('interp_meth'));
Pointer(interp_type):= GetProcAddress(libcpascal, PChar('interp_type'));
Pointer(interp_set):= GetProcAddress(libcpascal, PChar('interp_set'));
Pointer(interp_comp):= GetProcAddress(libcpascal, PChar('interp_comp'));
Pointer(interp_run):= GetProcAddress(libcpascal, PChar('interp_run'));
Pointer(interp_free):= GetProcAddress(libcpascal, PChar('interp_free'));
end;
function Interpreter_Precompiler(name, args: PChar): boolean; stdcall;
begin
result:= CurrThread.ProcessDirective(name, args);
end;
procedure Interpreter_ErrorHandler(line, pos: integer; err: PChar; runtime: boolean); stdcall;
begin
if runtime then
CurrThread.HandleError(line,-1,pos,err,errRuntime,'')
else
CurrThread.HandleError(line,-1,pos,err,errCompile,'')
end;
constructor TCPThread.Create(CreateSuspended: Boolean; TheSyncInfo : PSyncInfo; plugin_dir: string);
var
plugin_idx: integer;
begin
inherited Create(CreateSuspended, TheSyncInfo, plugin_dir);
if libcpascal = 0 then
LoadCPascal(plugin_dir);
instance:= interp_init(@Interpreter_Precompiler, @Interpreter_ErrorHandler);
end;
destructor TCPThread.Destroy;
begin
interp_free(instance);
inherited Destroy;
end;
procedure TCPThread.SetScript(script: string);
begin
interp_set(instance,PChar(script));
end;
procedure TCPThread.AddMethod(meth: TExpMethod);
begin
interp_meth(instance,meth.FuncPtr,PChar(meth.FuncDecl));
end;
procedure TCPThread.LoadPlugin(plugidx: integer);
var
i: integer;
begin
with PluginsGlob.MPlugins[plugidx] do
for i := 0 to MethodLen - 1 do
with Methods[i] do
begin
pswriteln(FuncStr);
interp_meth(self.instance,FuncPtr,PChar(FuncStr));
end;
pswriteln('done')
end;
procedure TCPThread.Execute;
var
i: integer;
begin
CurrThread := Self;
Starttime := GetTickCount;
psWriteln('Invoking CPascal Interpreter');
interp_type(self.instance,'type longword = integer;');
interp_type(self.instance,'type word = integer;');
interp_type(self.instance,'type longint = integer;');
interp_type(self.instance,'type pointer = integer;');
interp_type(self.instance,'type byte = integer;');
interp_type(self.instance,'type extended = real;');
interp_type(self.instance,'type tcolor = integer;');
interp_type(self.instance,'type TExtendedArray = array of extended;');
interp_type(self.instance,'type T2DExtendedArray = array of array of extended;');
interp_type(self.instance,'type TIntegerArray = array of integer;');
interp_type(self.instance,'type TBox = record X1,Y1,X2,Y2: integer; end;');
interp_type(self.instance,'type TPoint = record x,y: integer; end;');
interp_type(self.instance,'type TPointArray = array of TPoint;'); ;
interp_type(self.instance,'type T2DPointArray = array of array of TPoint;'); ;
interp_type(self.instance,'type TPointArrayArray = T2DPointArray;');
interp_type(self.instance,'type TTarget_Exported = record int1,int2,int3,int4,int5,int6,int7,int8,int9,int10,int11,int12,int13,int14, int15:integer; end;');
interp_type(self.instance,'type TMask = record White, Black : TPointArray; WhiteHi,BlackHi : integer; W,H : integer;end;');
interp_type(self.instance,'type TDTMPointDef = record x, y, Color, Tolerance, AreaSize, AreaShape: integer; end;');
interp_type(self.instance,'type TDTMPointDefArray = Array Of TDTMPointDef;');
interp_type(self.instance,'type TDTM = record MainPoint: TDTMPointDef; SubPoints: TDTMPointDefArray; end;');
interp_type(self.instance,'type pDTM = record l: Integer;p: TPointArray;c, t, asz, ash: TIntegerArray; bp: Array Of Boolean; n: String; end;');
for i := 0 to high(ExportedMethods) do
if ExportedMethods[i].FuncPtr <> nil then
with ExportedMethods[i] do
interp_meth(self.instance,FuncPtr,PChar(FuncDecl));
if interp_comp(instance) then
begin
psWriteln('Compiled Successfully in ' + IntToStr(GetTickCount - Starttime) + 'ms');
if CompileOnly then
exit;
if interp_run(instance) then
psWriteln('Executed Successfully')
else
psWriteln('Execution Failed');
end else
psWriteln('Compile Failed');
end;
procedure TCPThread.Terminate;
begin
raise Exception.Create('Stopping Interpreter not yet implemented');
end;
initialization
PluginsGlob := TMPlugins.Create;
libcpascal:= 0;
finalization
//PluginsGlob.Free;
//Its a nice idea, but it will segfault... the program is closing anyway.
end.