unit ce_ddemangle; {$I ce_defines.inc} interface uses Classes, SysUtils, process, forms, ce_processes, ce_common, ce_stringrange; type TCEDDemangler = class strict private fActive: boolean; fProc: TCEProcess; fList, fOut: TStringList; procedure procTerminate(sender: TObject); public constructor create; destructor destroy; override; procedure demangle(const value: string); property output: TStringList read fList; property active: boolean read fActive; end; // demangle a D name function demangle(const value: string): string; // demangle a list of D names procedure demangle(values, output: TStrings); implementation var demangler: TCEDDemangler; constructor TCEDDemangler.create; var s: string = '.0.'; r: TStringRange; v: integer; begin fList := TStringList.Create; fOut := TStringList.Create; fProc := TCEProcess.create(nil); fProc.Options:= [poUsePipes]; fProc.OnTerminate:=@procTerminate; fProc.ShowWindow:= swoHIDE; // Arch Linux users can have the tool setup w/o DMD {$IFDEF POSIX} fProc.Executable := exeFullName('dtools-ddemangle'); if fProc.Executable.fileExists then begin fProc.execute; fActive := true; exit; end; {$ENDIF} // up to version 2.071 ddemangle cannot be daemon-ized with TProcess.Create(nil) do try Executable := exeFullName('dmd' + exeExt); if Executable.fileExists then begin setLength(s, 128); Parameters.Text:= '--version'; Options:= [poUsePipes]; ShowWindow:= swoHIDE; execute; output.Read(s[1], 128); while Running do sleep(1); end; finally free; end; r := r.create(s); v := r.popUntil('.')^.popFront^.takeUntil('.').yield.toInt; fProc.Executable := exeFullName('ddemangle' + exeExt); if (v >= 72) and fProc.Executable.fileExists then begin fProc.execute; fActive := true; end else fActive := false; end; destructor TCEDDemangler.destroy; begin if fProc.Running then fProc.Terminate(0); fProc.Free; fOut.Free; fList.Free; inherited; end; procedure TCEDDemangler.procTerminate(sender: TObject); begin fActive := false; end; procedure TCEDDemangler.demangle(const value: string); var nb: integer; begin if value.isNotEmpty then fProc.Input.Write(value[1], value.length); fProc.Input.WriteByte(10); while true do begin nb := fProc.NumBytesAvailable; if nb <> 0 then break; end; fProc.fillOutputStack; fProc.getFullLines(fOut); if fOut.Count <> 0 then fList.Add(fOut[0]); end; function demangle(const value: string): string; begin if demangler.active and (pos('_D', value) > 0) then begin demangler.output.Clear; demangler.demangle(value); if demangler.output.Count <> 0 then result := demangler.output[0] else result := value; end else result := value; end; procedure demangle(values, output: TStrings); var value: string; begin if demangler.active then begin for value in values do demangler.demangle(value); output.AddStrings(demangler.output); demangler.output.Clear; end else output.AddStrings(values); end; initialization demangler := TCEDDemangler.create; finalization demangler.Free; end.