123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794 |
- {
- pas2jni - JNI bridge generator for Pascal.
- Copyright (c) 2013 by Yury Sidorov.
- 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- ****************************************************************************}
- unit ppuparser;
- {$mode objfpc}{$H+}
- interface
- uses
- Classes, SysUtils, def;
- type
- TCheckItemResult = (crDefault, crInclude, crExclude);
- TOnCheckItem = function (const ItemName: string): TCheckItemResult of object;
- { TPPUParser }
- TPPUParser = class
- private
- FOnCheckItem: TOnCheckItem;
- FDefaultSearchPathAdded: boolean;
- function FindUnit(const AName: string): string;
- function ReadUnit(const AName: string): string;
- function InternalParse(const AUnitName: string): TUnitDef;
- procedure AddSearchPath(const ASearchPath: string);
- function ReadProcessOutput(const AExeName, AParams: string; var AOutput, AError: string): integer;
- procedure AddDefaultSearchPath(const ACPU, AOS: string);
- public
- SearchPath: TStringList;
- Units: TDef;
- OnExceptionProc: TProcDef;
- constructor Create(const ASearchPath: string);
- destructor Destroy; override;
- procedure Parse(const AUnitName: string);
- property OnCheckItem: TOnCheckItem read FOnCheckItem write FOnCheckItem;
- end;
- var
- ppudumpprog: string;
- implementation
- uses process, pipes, fpjson, jsonparser, jsonscanner;
- const
- OnExceptionProcName = 'JNI_OnException';
- type
- TCharSet = set of char;
- function WordPosition(const N: Integer; const S: string;
- const WordDelims: TCharSet): Integer;
- var
- Count, I: Integer;
- begin
- Count := 0;
- I := 1;
- Result := 0;
- while (I <= Length(S)) and (Count <> N) do
- begin
- { skip over delimiters }
- while (I <= Length(S)) and (S[I] in WordDelims) do
- Inc(I);
- { if we're not beyond end of S, we're at the start of a word }
- if I <= Length(S) then
- Inc(Count);
- { if not finished, find the end of the current word }
- if Count <> N then
- while (I <= Length(S)) and not (S[I] in WordDelims) do
- Inc(I)
- else
- Result := I;
- end;
- end;
- function ExtractWord(N: Integer; const S: string;
- const WordDelims: TCharSet): string;
- var
- I: Integer;
- Len: Integer;
- begin
- Len := 0;
- I := WordPosition(N, S, WordDelims);
- if I <> 0 then
- { find the end of the current word }
- while (I <= Length(S)) and not (S[I] in WordDelims) do
- begin
- { add the I'th character to result }
- Inc(Len);
- SetLength(Result, Len);
- Result[Len] := S[I];
- Inc(I);
- end;
- SetLength(Result, Len);
- end;
- { TPPUParser }
- constructor TPPUParser.Create(const ASearchPath: string);
- begin
- SearchPath:=TStringList.Create;
- AddSearchPath(ASearchPath);
- Units:=TDef.Create;
- end;
- destructor TPPUParser.Destroy;
- begin
- Units.Free;
- SearchPath.Free;
- inherited Destroy;
- end;
- procedure TPPUParser.Parse(const AUnitName: string);
- begin
- InternalParse(AUnitName);
- end;
- function TPPUParser.FindUnit(const AName: string): string;
- var
- i: integer;
- fn: string;
- begin
- fn:=ChangeFileExt(LowerCase(AName), '.ppu');
- if FileExists(fn) then begin
- Result:=fn;
- exit;
- end;
- for i:=0 to SearchPath.Count - 1 do begin
- Result:=IncludeTrailingPathDelimiter(SearchPath[i]) + fn;
- if FileExists(Result) then
- exit;
- end;
- raise Exception.CreateFmt('Unable to find PPU file for unit "%s".', [AName]);
- end;
- function TPPUParser.ReadUnit(const AName: string): string;
- var
- s, un, err: ansistring;
- ec: integer;
- begin
- un:=FindUnit(AName);
- if ppudumpprog = '' then begin
- ppudumpprog:='ppudump';
- // Check for ppudump in the same folder as pas2jni
- s:=ExtractFilePath(ParamStr(0));
- if s <> '' then begin
- s:=s + ppudumpprog + ExtractFileExt(ParamStr(0));
- if FileExists(s) then
- ppudumpprog:=s;
- end;
- end;
- ec:=ReadProcessOutput(ppudumpprog, '-Fj' + LineEnding + un, s, err);
- err:=Trim(err);
- if (Copy(s, 1, 1) <> '[') and ((ec = 0) or (err = '')) then begin
- ec:=-1;
- err:='Output of ppudump is not in JSON format.' + LineEnding + 'Probably old version of ppudump has been used.';
- end;
- if ec <> 0 then begin
- if err = '' then
- if Length(s) < 300 then
- err:=s;
- raise Exception.CreateFmt('Error reading contents of unit "%s" using "%s".'+LineEnding+'Error code: %d'+LineEnding+'%s', [un, ppudumpprog, ec, err]);
- end;
- Result:=s;
- {$ifopt D+}
- // Lines.SaveToFile(AName + '-dump.txt');
- {$endif}
- end;
- function TPPUParser.InternalParse(const AUnitName: string): TUnitDef;
- var
- junit: TJSONObject;
- deref: array of TUnitDef;
- CurUnit: TUnitDef;
- IsSystemUnit: boolean;
- AMainUnit: boolean;
- CurObjName: string;
- function _GetRef(Ref: TJSONObject; ExpectedClass: TDefClass = nil): TDef;
- var
- j: integer;
- u: TUnitDef;
- begin
- Result:=nil;
- if Ref = nil then
- exit;
- u:=CurUnit;
- j:=Ref.Get('Unit', -1);
- if j >= 0 then begin
- u:=deref[j];
- if u.DefType = dtNone then begin
- // Reading unit
- u:=InternalParse(LowerCase(u.Name));
- if u = nil then
- exit;
- if u.CPU <> CurUnit.CPU then
- raise Exception.CreateFmt('Invalid target CPU of unit "%s": %s', [u.Name, u.CPU]);
- if u.OS <> CurUnit.OS then
- raise Exception.CreateFmt('Invalid target OS of unit "%s": %s', [u.Name, u.OS]);
- if u.PPUVer <> CurUnit.PPUVer then
- raise Exception.CreateFmt('Invalid PPU version of unit "%s": %s', [u.Name, u.PPUVer]);
- deref[j].Free;
- deref[j]:=u;
- end;
- end;
- j:=Ref.Integers['Id'];
- Result:=u.FindDef(j);
- if Result = nil then begin
- if ExpectedClass <> nil then
- Result:=ExpectedClass.Create(u, dtNone)
- else
- Result:=TDef.Create(u, dtNone);
- Result.DefId:=j;
- end;
- if (ExpectedClass <> nil) and (Result <> nil) then
- if (Result.DefType <> dtNone) and not (Result is ExpectedClass) then
- raise Exception.CreateFmt('Unexpected class. Expected: %s, got: %s', [ExpectedClass.ClassName, Result.ClassName]);
- end;
- procedure _ReadDefs(CurDef: TDef; jobj: TJSONObject; const ItemsName: string);
- var
- i, j: integer;
- jt, s: string;
- d: TDef;
- it: TJSONObject;
- jarr, arr: TJSONArray;
- ct: TClassType;
- begin
- jarr:=jobj.Get(ItemsName, TJSONArray(nil));
- if jarr = nil then
- exit;
- with jarr do
- for i:=0 to Count - 1 do begin
- it:=Objects[i];
- CurObjName:=it.Get('Name', '');
- jt:=it.Strings['Type'];
- if jt = 'obj' then begin
- s:=it.Strings['ObjType'];
- if s = 'class' then
- ct:=ctClass
- else
- if s = 'interface' then
- ct:=ctInterface
- else
- if s = 'object' then
- ct:=ctObject
- else
- continue;
- d:=TClassDef.Create(CurDef, dtClass);
- TClassDef(d).CType:=ct;
- if ct = ctInterface then
- TClassDef(d).IID:=it.Get('IID', '');
- end
- else
- if jt = 'rec' then begin
- if IsSystemUnit and (CompareText(CurObjName, 'tguid') = 0) then begin
- d:=TTypeDef.Create(CurDef, dtType);
- TTypeDef(d).BasicType:=btGuid;
- end
- else begin
- d:=TClassDef.Create(CurDef, dtClass);
- TClassDef(d).CType:=ctRecord;
- end;
- end
- else
- if jt = 'proc' then
- d:=TProcDef.Create(CurDef, dtProc)
- else
- if jt = 'proctype' then begin
- d:=TProcDef.Create(CurDef, dtProcType);
- TProcDef(d).ProcType:=ptProcedure;
- end
- else
- if jt = 'param' then begin
- d:=TVarDef.Create(CurDef, dtParam);
- TVarDef(d).VarOpt:=[voRead];
- end
- else
- if jt = 'prop' then begin
- d:=TVarDef.Create(CurDef, dtProp);
- TVarDef(d).VarOpt:=[];
- end
- else
- if jt = 'field' then
- d:=TVarDef.Create(CurDef, dtField)
- else
- if jt = 'var' then
- d:=TVarDef.Create(CurDef, dtVar)
- else
- if jt = 'ord' then begin
- d:=TTypeDef.Create(CurDef, dtType);
- with TTypeDef(d) do begin
- s:=it.Strings['OrdType'];
- j:=it.Get('Size', 0);
- if s = 'void' then
- BasicType:=btVoid
- else
- if s = 'uint' then begin
- case j of
- 1: BasicType:=btByte;
- 2: BasicType:=btWord;
- 4: BasicType:=btLongWord;
- else BasicType:=btInt64;
- end;
- end
- else
- if s = 'sint' then begin
- case j of
- 1: BasicType:=btShortInt;
- 2: BasicType:=btSmallInt;
- 4: BasicType:=btLongInt;
- else BasicType:=btInt64;
- end;
- end
- else
- if (s = 'pasbool') or (s = 'bool') then
- BasicType:=btBoolean
- else
- if s = 'char' then begin
- if j = 1 then
- BasicType:=btChar
- else
- BasicType:=btWideChar;
- end
- else
- if s = 'currency' then
- BasicType:=btDouble;
- end;
- end
- else
- if jt = 'float' then begin
- d:=TTypeDef.Create(CurDef, dtType);
- with TTypeDef(d) do
- if it.Strings['FloatType'] = 'single' then
- BasicType:=btSingle
- else
- BasicType:=btDouble;
- end
- else
- if jt = 'string' then begin
- d:=TTypeDef.Create(CurDef, dtType);
- s:=it.Strings['StrType'];
- with TTypeDef(d) do
- if (s = 'wide') or (s = 'unicode') or (s = 'long') then
- BasicType:=btWideString
- else
- BasicType:=btString;
- if not (IsSystemUnit and (CompareText(CurObjName, 'rawbytestring') = 0)) then
- CurObjName:=s + 'string';
- end
- else
- if jt = 'enum' then begin
- d:=TTypeDef.Create(CurDef, dtEnum);
- TTypeDef(d).BasicType:=btEnum;
- end
- else
- if jt = 'set' then
- d:=TSetDef.Create(CurDef, dtSet)
- else
- if jt = 'ptr' then begin
- d:=TPointerDef.Create(CurDef, dtPointer);
- end
- else
- if jt = 'const' then
- d:=TConstDef.Create(CurDef, dtConst)
- else
- if jt = 'array' then
- d:=TArrayDef.Create(CurDef, dtArray)
- else
- if jt = 'classref' then
- d:=TClassRefDef.Create(CurDef, dtClassRef)
- else
- continue;
- if (CurObjName = '') and not (d.DefType in [dtEnum, dtArray]) then begin
- d.Free;
- continue;
- end;
- // Common def attributes
- d.Name:=CurObjName;
- d.DefId:=it.Get('Id', -1);
- d.SymId:=it.Get('SymId', -1);
- s:=it.Get('Visibility', '');
- d.IsPrivate:=(s <> '') and (s <> 'public') and (s <> 'published');
- if Copy(d.Name, 1, 1) = '$' then
- d.IsPrivate:=True;
- // Specific def attributes
- case d.DefType of
- dtClass:
- with TClassDef(d) do begin
- if CType <> ctRecord then
- AncestorClass:=TClassDef(_GetRef(it.Get('Ancestor', TJSONObject(nil)), TClassDef));
- if CType in [ctObject, ctRecord] then
- Size:=it.Integers['Size'];
- arr:=it.Get('Options', TJSONArray(nil));
- if arr <> nil then
- for j:=0 to arr.Count - 1 do begin
- s:=arr.Strings[j];
- if s = 'abstract_methods' then
- HasAbstractMethods:=True;
- end;
- _ReadDefs(d, it, 'Fields');
- end;
- dtProc, dtProcType:
- with TProcDef(d) do begin
- arr:=it.Get('Options', TJSONArray(nil));
- if arr <> nil then
- for j:=0 to arr.Count - 1 do begin
- s:=arr.Strings[j];
- if s = 'procedure' then
- ProcType:=ptProcedure
- else
- if s = 'function' then
- ProcType:=ptFunction
- else
- if s = 'constructor' then begin
- ProcType:=ptConstructor;
- if CompareText(Name, 'create') = 0 then
- Name:='Create'; // fix char case for standard constructors
- end
- else
- if s = 'destructor' then
- ProcType:=ptDestructor
- else
- if s = 'overriding' then begin
- ProcType:=ptDestructor;
- ProcOpt:=ProcOpt + [poOverride];
- if ProcType <> ptConstructor then
- IsPrivate:=True;
- end
- else
- if s = 'overload' then
- ProcOpt:=ProcOpt + [poOverload]
- else
- if s = 'abstract' then
- TClassDef(Parent).HasAbstractMethods:=True
- else
- if s = 'classmethod' then
- ProcOpt:=ProcOpt + [poClassMethod];
- end;
- ReturnType:=_GetRef(it.Get('RetType', TJSONObject(nil)));
- if (DefType = dtProcType) and not ( (ReturnType is TTypeDef) and (TTypeDef(ReturnType).BasicType = btVoid) ) then
- ProcType:=ptFunction;
- if it.Get('MethodPtr', False) then
- ProcOpt:=ProcOpt + [poMethodPtr];
- if IsSystemUnit and (ProcType = ptFunction) and (Name = 'int') then
- Name:='Int';
- _ReadDefs(d, it, 'Params');
- for j:=0 to d.Count - 1 do
- with d[j] do begin
- if DefType <> dtParam then
- continue;
- s:=Name;
- Name:=Format('p%d', [j + 1]);
- AliasName:=s;
- end;
- // Check for user exception handler proc
- if AMainUnit and (Parent = CurUnit) and (OnExceptionProc = nil) and (AnsiCompareText(Name, OnExceptionProcName) = 0) then
- OnExceptionProc:=TProcDef(d);
- end;
- dtVar, dtField, dtParam:
- with TVarDef(d) do begin
- VarType:=_GetRef(it.Objects['VarType']);
- s:=it.Get('Spez', '');
- if s = 'out' then
- VarOpt:=[voWrite, voOut]
- else
- if s = 'var' then
- VarOpt:=[voRead, voWrite, voVar]
- else
- if s = 'const' then
- VarOpt:=[voRead, voConst];
- end;
- dtProp:
- with TVarDef(d) do begin
- VarType:=_GetRef(it.Objects['PropType']);
- if it.Get('Getter', TJSONObject(nil)) <> nil then
- VarOpt:=VarOpt + [voRead];
- if it.Get('Setter', TJSONObject(nil)) <> nil then
- VarOpt:=VarOpt + [voWrite];
- _ReadDefs(d, it, 'Params');
- end;
- dtEnum:
- _ReadDefs(d, it, 'Elements');
- dtSet:
- with TSetDef(d) do begin
- Size:=it.Integers['Size'];
- Base:=it.Integers['Base'];
- ElMax:=it.Integers['Max'];
- ElType:=TTypeDef(_GetRef(it.Objects['ElType'], TTypeDef));
- if (ElType <> nil) and (ElType.Name = '') then
- ElType.Name:=CurObjName + 'El';
- end;
- dtConst:
- with TConstDef(d) do begin
- VarType:=_GetRef(it.Get('TypeRef', TJSONObject(nil)));
- s:=it.Strings['ValType'];
- if s = 'int' then
- Value:=IntToStr(it.Int64s['Value'])
- else
- if s = 'float' then begin
- Str(it.Floats['Value'], s);
- Value:=s;
- end
- else
- if s = 'string' then begin
- s:=it.Strings['Value'];
- s:=StringReplace(s, '\', '\\', [rfReplaceAll]);
- s:=StringReplace(s, '"', '\"', [rfReplaceAll]);
- s:=StringReplace(s, #9, '\t', [rfReplaceAll]);
- s:=StringReplace(s, #10, '\n', [rfReplaceAll]);
- s:=StringReplace(s, #13, '\r', [rfReplaceAll]);
- Value:='"' + s + '"';
- end
- else
- FreeAndNil(d);
- end;
- dtPointer:
- with TPointerDef(d) do begin
- PtrType:=_GetRef(it.Get('Ptr', TJSONObject(nil)));;
- if AMainUnit and (Parent = CurUnit) and (CompareText(Name, 'TJavaObject') = 0) then
- DefType:=dtJniObject;
- end;
- dtArray:
- with TArrayDef(d) do begin
- _ReadDefs(d, it, 'Types');
- RangeLow:=it.Get('Low', -1);
- RangeHigh:=it.Get('High', -1);
- RangeType:=_GetRef(it.Get('RangeType', TJSONObject(nil)));
- ElType:=_GetRef(it.Get('ElType', TJSONObject(nil)));
- end;
- dtClassRef:
- with TClassRefDef(d) do begin
- ClassRef:=_GetRef(it.Get('Ref', TJSONObject(nil)));;
- end;
- end;
- end;
- end;
- var
- i, j: integer;
- s: string;
- chkres: TCheckItemResult;
- jp: TJSONParser;
- jdata: TJSONData;
- begin
- Result:=nil;
- for i:=0 to Units.Count - 1 do
- if CompareText(Units[i].Name, AUnitName) = 0 then begin
- Result:=TUnitDef(Units[i]);
- exit;
- end;
- chkres:=FOnCheckItem(AUnitName);
- if chkres = crExclude then
- exit;
- AMainUnit:=chkres = crInclude;
- if not AMainUnit and ( (CompareText(AUnitName, 'windows') = 0) or (CompareText(AUnitName, 'unix') = 0) ) then
- exit;
- s:=ReadUnit(AUnitName);
- try
- jdata:=nil;
- try
- jp:=TJSONParser.Create(s, [joUTF8]);
- try
- s:='';
- jdata:=jp.Parse;
- junit:=TJSONObject(jdata.Items[0]);
- finally
- jp.Free;
- end;
- IsSystemUnit:=CompareText(AUnitName, 'system') = 0;
- Result:=TUnitDef.Create(nil, dtUnit);
- Units.Add(Result);
- Result.Name:=junit.Strings['Name'];
- Result.PPUVer:=junit.Integers['Version'];
- Result.CPU:=junit.Strings['TargetCPU'];
- Result.OS:=junit.Strings['TargetOS'];
- j:=Length(Result.CPU);
- if AnsiLowerCase(Copy(Result.OS, Length(Result.OS) - j, j + 1)) = AnsiLowerCase('-' + Result.CPU) then
- Result.OS:=Copy(Result.OS, 1, Length(Result.OS) - j - 1);
- Result.IntfCRC:=junit.Strings['InterfaceCRC'];
- if IsSystemUnit then
- Result.IsUsed:=True;
- if not FDefaultSearchPathAdded then begin
- FDefaultSearchPathAdded:=True;
- AddDefaultSearchPath(AnsiLowerCase(Result.CPU), AnsiLowerCase(Result.OS));
- end;
- if junit.Find('Units') <> nil then
- with junit.Arrays['Units'] do begin
- SetLength(deref, Count);
- for i:=0 to Count - 1 do begin
- deref[i]:=TUnitDef.Create(nil, dtNone);
- deref[i].Name:=Strings[i];
- end;
- end;
- CurUnit:=Result;
- _ReadDefs(CurUnit, junit, 'Interface');
- Result.ResolveDefs;
- if CompareText(AUnitName, 'jni') = 0 then begin
- for i:=0 to Result.Count - 1 do
- with Result[i] do
- if CompareText(Name, 'PJNIEnv') = 0 then
- DefType:=dtJniEnv;
- end;
- if AMainUnit then
- Result.IsUsed:=True;
- SetLength(Result.UsedUnits, Length(deref));
- j:=0;
- for i:=0 to High(deref) do
- if deref[i].DefType = dtNone then
- deref[i].Free
- else begin
- Result.UsedUnits[j]:=deref[i];
- Inc(j);
- end;
- SetLength(Result.UsedUnits, j);
- finally
- jdata.Free;
- end;
- except
- if CurObjName <> '' then
- CurObjName:=Format('; Object: "%s"', [CurObjName]);
- raise Exception.CreateFmt('%s' + LineEnding + 'Unit: "%s"%s', [Exception(ExceptObject).Message, AUnitName, CurObjName]);
- end;
- end;
- procedure TPPUParser.AddSearchPath(const ASearchPath: string);
- var
- i, j: integer;
- s, d: string;
- sr: TSearchRec;
- sl: TStringList;
- begin
- sl:=TStringList.Create;
- try
- sl.Delimiter:=';';
- sl.DelimitedText:=ASearchPath;
- i:=0;
- while i < sl.Count do begin
- s:=sl[i];
- if (Pos('*', s) > 0) or (Pos('?', s) > 0) then begin
- d:=ExtractFilePath(s);
- j:=FindFirst(s, faDirectory, sr);
- while j = 0 do begin
- if (sr.Name <> '.') and (sr.Name <> '..') then
- sl.Add(d + sr.Name);
- j:=FindNext(sr);
- end;
- FindClose(sr);
- sl.Delete(i);
- end
- else
- Inc(i);
- end;
- SearchPath.AddStrings(sl);
- finally
- sl.Free;
- end;
- end;
- function TPPUParser.ReadProcessOutput(const AExeName, AParams: string; var AOutput, AError: string): integer;
- procedure _ReadOutput(o: TInputPipeStream; var s: string; var idx: integer);
- var
- i: integer;
- begin
- with o do
- while NumBytesAvailable > 0 do begin
- i:=NumBytesAvailable;
- if idx + i > Length(s) then
- SetLength(s, idx + i*10 + idx div 10);
- ReadBuffer(s[idx + 1], i);
- Inc(idx, i);
- end;
- end;
- var
- p: TProcess;
- oidx, eidx: integer;
- begin
- AOutput:='';
- AError:='';
- oidx:=0;
- eidx:=0;
- p:=TProcess.Create(nil);
- try
- p.Executable:=AExeName;
- p.Parameters.Text:=AParams;
- p.Options:=[poUsePipes, poNoConsole];
- p.ShowWindow:=swoHIDE;
- p.StartupOptions:=[suoUseShowWindow];
- try
- p.Execute;
- except
- raise Exception.CreateFmt('Unable to run "%s".'+LineEnding+'%s', [p.Executable, Exception(ExceptObject).Message]);
- end;
- repeat
- if p.Output.NumBytesAvailable = 0 then
- TThread.Yield;
- _ReadOutput(p.Output, AOutput, oidx);
- _ReadOutput(p.Stderr, AError, eidx);
- until not p.Running and (p.Output.NumBytesAvailable = 0) and (p.Stderr.NumBytesAvailable = 0);
- SetLength(AOutput, oidx);
- SetLength(AError, eidx);
- Result:=p.ExitStatus;
- finally
- p.Free;
- end;
- end;
- procedure TPPUParser.AddDefaultSearchPath(const ACPU, AOS: string);
- var
- fpc, s, e: string;
- sl: TStringList;
- i, j: integer;
- begin
- try
- fpc:=ExtractFilePath(ppudumpprog) + 'fpc' + ExtractFileExt(ParamStr(0));
- if not FileExists(fpc) then
- exit;
- // Find the compiler binary
- if ReadProcessOutput(fpc, '-P' + ACPU + LineEnding + '-T' + AOS + LineEnding + '-PB', s, e) <> 0 then
- exit;
- fpc:=Trim(s);
- // Get units path from the compiler output
- ReadProcessOutput(fpc, '-P' + ACPU + LineEnding + '-T' + AOS + LineEnding + '-vt' + LineEnding + '.', s, e);
- sl:=TStringList.Create;
- try
- sl.Text:=s;
- s:='';
- for i:=0 to sl.Count - 1 do begin
- s:=sl[i];
- j:=Pos(':', s);
- if j > 0 then begin
- s:=Trim(Copy(s, j + 1, MaxInt));
- s:=ExcludeTrailingPathDelimiter(s);
- if (Copy(s, Length(s) - 3, 4) = DirectorySeparator + 'rtl') and DirectoryExists(s) then begin
- AddSearchPath(ExtractFilePath(s) + '*');
- exit;
- end;
- end;
- end;
- finally
- sl.Free;
- end;
- except
- // Ignore exceptions
- end;
- end;
- end.
|