pas2jscompilerproxy.pas 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. unit Pas2jsCompilerProxy;
  2. {$IFDEF FPC}
  3. {$mode objfpc}{$H+}
  4. {$ENDIF}
  5. {$IFDEF darwin}
  6. {$DEFINE UseCDecl}
  7. {$ENDIF}
  8. interface
  9. uses
  10. Classes, SysUtils, LibPas2jsIntf;
  11. Type
  12. { TPas2JSCompilerProxy }
  13. TPas2JSCompilerProxy = class(TObject)
  14. Private
  15. FCompiler : PPas2JSCompiler;
  16. FPasFile: TFileStream;
  17. Protected
  18. Procedure WriteLog(Const S : AnsiString);
  19. Procedure WriteJS(Const AFileName,AFileData : AnsiString);
  20. Procedure StartReadPasFile(Const AFileName : AnsiString);
  21. Procedure ReadChunk(ABuffer : PAnsiChar; Var AChunkSize : Cardinal);
  22. Procedure DoneReadPasFile;
  23. Public
  24. Constructor Create; virtual;
  25. Destructor Destroy; override;
  26. Procedure Run(ACompilerExe, AWorkingDir : String; CommandLine : TStringList; DoReset : Boolean);
  27. Procedure Execute;
  28. Property PasFile : TFileStream Read FPasFile;
  29. end;
  30. implementation
  31. {$ifndef fpc}
  32. const
  33. AllFilesMask = '*.*';
  34. type
  35. TUnicodeSearchRec = TSearchRec;
  36. {$endif}
  37. Procedure DoLog(Data : Pointer; Msg : PansiChar; MsgLen : Integer); {$IFDEF UseCDecl}cdecl{$ELSE}stdcall{$ENDIF};
  38. Var
  39. S : AnsiString;
  40. begin
  41. SetLength(S{%H-},MsgLen);
  42. if MsgLen>0 then
  43. Move(Msg^,S[1],MsgLen);
  44. TPas2JSCompilerProxy(Data).WriteLog(S);
  45. end;
  46. Procedure DoWriteJS(Data : Pointer; AFileName: PAnsiChar; AFileNameLen : Integer;
  47. AFileData : PAnsiChar; AFileDataLen: Int32); {$IFDEF UseCDecl}cdecl{$ELSE}stdcall{$ENDIF};
  48. Var
  49. Src,DestFileName : AnsiString;
  50. begin
  51. SetLength(DestFileName{%H-},AFileNameLen);
  52. if AFileNameLen>0 then
  53. Move(AFileName^,DestFileName[1],AFileNameLen);
  54. SetLength(Src{%H-},AFileDataLen);
  55. if AFileDataLen>0 then
  56. Move(AFileData^,Src[1],AFileDataLen);
  57. TPas2JSCompilerProxy(Data).WriteJS(DestFileName,Src);
  58. end;
  59. procedure DoReadPasJS(Data: Pointer; AFileName: PAnsiChar; AFileNameLen: Integer;
  60. AFileData: PAnsiChar; Var AFileDataLen: Cardinal);
  61. {$IFDEF UseCDecl}cdecl{$ELSE}stdcall{$ENDIF};
  62. Var
  63. DestFileName : AnsiString;
  64. BytesToRead : Cardinal;
  65. begin
  66. SetLength(DestFileName{%H-},AFileNameLen);
  67. if AFileNameLen>0 then
  68. Move(AFileName^,DestFileName[1],AFileNameLen);
  69. TPas2JSCompilerProxy(Data).StartReadPasFile(AFileName);
  70. BytesToRead:=AFileDatalen;
  71. TPas2JSCompilerProxy(Data).ReadChunk(AFileData,AFileDataLen);
  72. if AFileDatalen<BytesToRead then
  73. TPas2JSCompilerProxy(Data).DoneReadPasFile;
  74. end;
  75. function DoReadDir(Data: Pointer; P: PDirectoryCache; ADirPath: PAnsiChar): boolean;
  76. {$IFDEF UseCDecl}cdecl{$ELSE}stdcall{$ENDIF};
  77. var
  78. Info: TUnicodeSearchRec;
  79. Filename: String;
  80. Path: PAnsiChar;
  81. begin
  82. if Data=nil then ;
  83. Path:=ADirPath;
  84. // Note: do not add a 'if not DirectoryExists then exit'.
  85. // This will not work on automounted directories. You must use FindFirst.
  86. if FindFirst(UnicodeString(Path+AllFilesMask),faAnyFile,Info)=0 then begin
  87. repeat
  88. // check if special file
  89. if (Info.Name='.') or (Info.Name='..') or (Info.Name='')
  90. then
  91. continue;
  92. // add file
  93. Filename:=AnsiString(Info.Name);
  94. AddPas2JSDirectoryEntry(P,PAnsiChar(Filename),Info.Time,Info.Attr,Info.Size);
  95. until FindNext(Info)<>0;
  96. end;
  97. FindClose(Info);
  98. Result:=true;
  99. end;
  100. Function DoUnitAlias(Data: Pointer; AUnitName: PAnsiChar;
  101. AUnitNameMaxLen: Integer): boolean; {$IFDEF UseCDecl}cdecl{$ELSE}stdcall{$ENDIF};
  102. var
  103. Old, New: AnsiString;
  104. begin
  105. Result:=false;
  106. Old:=AUnitName;
  107. if Data=nil then ;
  108. New:='';
  109. if SameText(Old,'Test.Foo.Alias1') then
  110. New:='Bar'
  111. else if SameText(Old,'Test.Foo.Alias2') then
  112. New:='Test.Foo.SomeLongUnitName';
  113. if New<>'' then
  114. begin
  115. writeln('Info: DoUnitAlias Old="',Old,'" New="',New,'"');
  116. if AUnitNameMaxLen<length(New) then
  117. raise Exception.Create('unit alias too long');
  118. System.Move(New[1],AUnitName^,length(New)+1);
  119. Result:=true;
  120. end;
  121. end;
  122. { TPas2JSCompilerProxy }
  123. procedure TPas2JSCompilerProxy.WriteLog(const S: AnsiString);
  124. begin
  125. Writeln('Log : ',S);
  126. end;
  127. procedure TPas2JSCompilerProxy.WriteJS(const AFileName, AFileData: AnsiString);
  128. Var
  129. F : TFileStream;
  130. begin
  131. F:=TFileStream.Create(AFileName,fmCreate);
  132. try
  133. F.WriteBuffer(AFileData[1],Length(AFileData));
  134. finally
  135. F.Free;
  136. end;
  137. end;
  138. procedure TPas2JSCompilerProxy.StartReadPasFile(const AFileName: AnsiString);
  139. begin
  140. If Assigned(FPasFile) and SameFileName(AFileName,FPasFile.FileName) then
  141. exit;
  142. FreeAndNil(FPasFile);
  143. FPasFile:=TFileStream.Create(aFileName,fmOpenRead or fmShareDenyWrite);
  144. end;
  145. procedure TPas2JSCompilerProxy.ReadChunk(ABuffer: PAnsiChar; Var AChunkSize: Cardinal);
  146. begin
  147. if Not assigned(FPasFile) then
  148. AChunkSize:=0
  149. else
  150. AChunkSize:=FPasFile.Read(ABuffer^,AChunkSize);
  151. end;
  152. procedure TPas2JSCompilerProxy.DoneReadPasFile;
  153. begin
  154. FreeAndNil(FPasFile);
  155. end;
  156. constructor TPas2JSCompilerProxy.Create;
  157. begin
  158. FCompiler:=GetPas2JSCompiler();
  159. SetPas2JSCompilerLogCallBack(FCompiler,@DoLog,Self);
  160. SetPas2JSWriteJSCallBack(FCompiler,@DoWriteJS,Self);
  161. SetPas2JSReadPasCallBack(FCompiler,@DoReadPasJS,Self,16*1024);
  162. SetPas2JSReadDirCallBack(FCompiler,@DoReadDir,Self);
  163. SetPas2JSUnitAliasCallBack(FCompiler,@DoUnitAlias,Self);
  164. end;
  165. destructor TPas2JSCompilerProxy.Destroy;
  166. begin
  167. inherited Destroy;
  168. end;
  169. procedure TPas2JSCompilerProxy.Run(ACompilerExe, AWorkingDir: String; CommandLine: TStringList; DoReset: Boolean);
  170. Var
  171. SCmdLn : Array Of AnsiString;
  172. CmdLn : Array Of PAnsiChar;
  173. Err,ErrClassname : AnsiString;
  174. I,ErrorLength,ErrorClassLength : Integer;
  175. begin
  176. SetLength(SCmdLn{%H-},CommandLine.Count);
  177. SetLength(CmdLn{%H-},CommandLine.Count+1);
  178. For I:=0 to CommandLine.Count-1 do
  179. begin
  180. SCmdLn[i]:=CommandLine[i]; // CommandLine[i] might return a temporary string -> make sure it is valid during this proc
  181. CmdLn[i]:=PAnsiChar(SCmdLn[i]);
  182. end;
  183. CmdLn[CommandLine.Count]:=Nil;
  184. if not RunPas2JSCompiler(FCompiler,PAnsiChar(ACompilerExe),PAnsiChar(AWorkingDir),PPAnsiChar(Cmdln),DoReset) then
  185. begin
  186. ErrorLength:=1024;
  187. ErrorClassLength:=1024;
  188. SetLength(Err{%H-},ErrorLength);
  189. SetLength(ErrClassname{%H-},ErrorClassLength);
  190. GetPas2JSCompilerLastError(FCompiler,@Err[1],ErrorLength,@ErrClassname[1],ErrorClassLength);
  191. SetLength(Err,ErrorLength);
  192. SetLength(ErrClassname,ErrorClassLength);
  193. writeln(Format('Error of class "%s" raised when compiling : %s',[ErrClassname,Err]));
  194. ExitCode:=1;
  195. end;
  196. end;
  197. procedure TPas2JSCompilerProxy.Execute;
  198. Var
  199. Cmd : TStringList;
  200. I : integer;
  201. begin
  202. Cmd:=TStringList.Create;
  203. try
  204. for I:=1 to ParamCount do
  205. Cmd.Add(Paramstr(i));
  206. Run(ParamStr(0),GetCurrentDir,Cmd,False);
  207. finally
  208. Cmd.Free;
  209. end;
  210. end;
  211. end.