fpc/compiler/browlog.pas
peter cb246eb781 * Remove dos,strings units, use SysUtils instead
* replace split* functions with Extract* functions
  * Add Directory caching

git-svn-id: trunk@5102 -
2006-10-30 23:29:35 +00:00

511 lines
14 KiB
ObjectPascal

{
Copyright (c) 1998-2002 by Florian Klaempfl and Pierre Muller
Support routines for creating the browser log
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 browlog;
{$i fpcdefs.inc}
interface
uses
cclasses,
globtype,
fmodule,finput,
symbase,symconst,symtype,symsym,symdef,symtable;
const
logbufsize = 16384;
type
pbrowserlog=^tbrowserlog;
tbrowserlog=object
fname : string;
logopen : boolean;
stderrlog : boolean;
f : file;
elements_to_list : tstringlist;
buf : pchar;
bufidx : longint;
identidx : longint;
constructor init;
destructor done;
procedure setfilename(const fn:string);
procedure createlog;
procedure flushlog;
procedure addlog(const s:string);
procedure addlogrefs(p:tref);
procedure closelog;
procedure ident;
procedure unident;
procedure browse_symbol(const sr : string);
procedure list_elements;
procedure list_debug_infos;
end;
var
browserlog : tbrowserlog;
procedure WriteBrowserLog;
procedure InitBrowserLog;
procedure DoneBrowserLog;
implementation
uses
cutils,cfileutils,comphook,
globals,systems,
ppu;
function get_file_line(ref:tref): string;
var
inputfile : tinputfile;
begin
get_file_line:='';
with ref do
begin
inputfile:=get_source_file(moduleindex,posinfo.fileindex);
if assigned(inputfile) then
if status.use_gccoutput then
{ for use with rhide
add warning so that it does not interpret
this as an error !! }
get_file_line:=lower(inputfile.name^)
+':'+tostr(posinfo.line)+': warning: '+tostr(posinfo.column)+':'
else
get_file_line:=inputfile.name^
+'('+tostr(posinfo.line)+','+tostr(posinfo.column)+')'
else
if status.use_gccoutput then
get_file_line:='file_unknown:'
+tostr(posinfo.line)+': warning: '+tostr(posinfo.column)+':'
else
get_file_line:='file_unknown('
+tostr(posinfo.line)+','+tostr(posinfo.column)+')'
end;
end;
{****************************************************************************
TBrowser
****************************************************************************}
constructor tbrowserlog.init;
begin
fname:=FixFileName('browser.log');
logopen:=false;
elements_to_list:=TStringList.Create;
end;
destructor tbrowserlog.done;
begin
if logopen then
closelog;
elements_to_list.free;
end;
procedure tbrowserlog.setfilename(const fn:string);
begin
fname:=FixFileName(fn);
end;
procedure tbrowserlog.createlog;
begin
if logopen then
closelog;
assign(f,fname);
{$I-}
rewrite(f,1);
{$I+}
if ioresult<>0 then
exit;
logopen:=true;
getmem(buf,logbufsize);
bufidx:=0;
identidx:=0;
end;
procedure tbrowserlog.flushlog;
begin
if logopen then
if not stderrlog then
blockwrite(f,buf^,bufidx)
else
begin
buf[bufidx]:=#0;
write(stderr,buf);
end;
bufidx:=0;
end;
procedure tbrowserlog.closelog;
begin
if logopen then
begin
flushlog;
close(f);
freemem(buf,logbufsize);
logopen:=false;
end;
end;
procedure tbrowserlog.list_elements;
begin
stderrlog:=true;
getmem(buf,logbufsize);
logopen:=true;
while not elements_to_list.empty do
browse_symbol(elements_to_list.getfirst);
flushlog;
logopen:=false;
freemem(buf,logbufsize);
stderrlog:=false;
end;
procedure tbrowserlog.list_debug_infos;
{$ifndef debug}
begin
end;
{$else debug}
var
hp : tmodule;
ff : tinputfile;
begin
hp:=tmodule(loaded_units.first);
while assigned(hp) do
begin
addlog('Unit '+hp.modulename^+' has index '+tostr(hp.unit_index));
ff:=hp.sourcefiles.files;
while assigned(ff) do
begin
addlog('File '+ff.name^+' index '+tostr(ff.ref_index));
ff:=ff.ref_next;
end;
hp:=tmodule(hp.next);
end;
end;
{$endif debug}
procedure tbrowserlog.addlog(const s:string);
begin
if not logopen then
exit;
{ add ident }
if (identidx>0) and not stderrlog then
begin
if bufidx+identidx>logbufsize then
flushlog;
fillchar(buf[bufidx],identidx,' ');
inc(bufidx,identidx);
end;
{ add text }
if bufidx+length(s)>logbufsize-2 then
flushlog;
move(s[1],buf[bufidx],length(s));
inc(bufidx,length(s));
{ add crlf }
buf[bufidx]:=target_info.newline[1];
inc(bufidx);
if length(target_info.newline)=2 then
begin
buf[bufidx]:=target_info.newline[2];
inc(bufidx);
end;
end;
procedure tbrowserlog.addlogrefs(p:tref);
var
ref : tref;
begin
ref:=p;
Ident;
while assigned(ref) do
begin
Browserlog.AddLog(get_file_line(ref));
ref:=ref.nextref;
end;
Unident;
end;
procedure tbrowserlog.browse_symbol(const sr : string);
var
sym : tsym;
symb : tstoredsym;
symt : tsymtable;
hp : tmodule;
s,ss : string;
p : byte;
procedure next_substring;
begin
p:=pos('.',s);
if p>0 then
begin
ss:=copy(s,1,p-1);
s:=copy(s,p+1,255);
end
else
begin
ss:=s;
s:='';
end;
addlog('substring : '+ss);
end;
begin
{ don't create a new reference when
looking for the symbol !! }
make_ref:=false;
s:=sr;
symt:=symtablestack.top;
next_substring;
if assigned(symt) then
begin
sym:=tstoredsym(symt.search(ss));
if sym=nil then
sym:=tstoredsym(symt.search(upper(ss)));
end
else
sym:=nil;
if assigned(sym) and (sym.typ=unitsym) and (s<>'') then
begin
addlog('Unitsym found !');
symt:=tmodule(tunitsym(sym).module).globalsymtable;
if assigned(symt) then
begin
next_substring;
sym:=tstoredsym(symt.search(ss));
end
else
sym:=nil;
end;
if not assigned(sym) then
begin
symt:=nil;
{ try all loaded_units }
hp:=tmodule(loaded_units.first);
while assigned(hp) do
begin
if hp.modulename^=upper(ss) then
begin
symt:=hp.globalsymtable;
break;
end;
hp:=tmodule(hp.next);
end;
if not assigned(symt) then
begin
addlog('!!!Symbol '+ss+' not found !!!');
make_ref:=true;
exit;
end
else
begin
next_substring;
sym:=tstoredsym(symt.search(ss));
if sym=nil then
sym:=tstoredsym(symt.search(upper(ss)));
end;
end;
while assigned(sym) and (s<>'') do
begin
next_substring;
case sym.typ of
typesym :
begin
if ttypesym(sym).typedef.deftype in [recorddef,objectdef] then
begin
if ttypesym(sym).typedef.deftype=recorddef then
symt:=trecorddef(ttypesym(sym).typedef).symtable
else
symt:=tobjectdef(ttypesym(sym).typedef).symtable;
sym:=tstoredsym(symt.search(ss));
if sym=nil then
sym:=tstoredsym(symt.search(upper(ss)));
end;
end;
globalvarsym,
localvarsym,
paravarsym,
fieldvarsym :
begin
if tabstractvarsym(sym).vardef.deftype in [recorddef,objectdef] then
begin
symt:=tabstractvarsym(sym).vardef.getsymtable(gs_record);
sym:=tstoredsym(symt.search(ss));
if sym=nil then
sym:=tstoredsym(symt.search(upper(ss)));
end;
end;
procsym :
begin
symt:=tprocsym(sym).first_procdef.parast;
symb:=tstoredsym(symt.search(ss));
if symb=nil then
symb:=tstoredsym(symt.search(upper(ss)));
if not assigned(symb) then
begin
symt:=tprocsym(sym).first_procdef.localst;
sym:=tstoredsym(symt.search(ss));
if symb=nil then
symb:=tstoredsym(symt.search(upper(ss)));
end
else
sym:=symb;
end;
end;
end;
if assigned(sym) then
begin
if assigned(sym.defref) then
begin
browserlog.AddLog('***'+sym.name+'***');
browserlog.AddLogRefs(sym.defref);
end;
end
else
addlog('!!!Symbol '+ss+' not found !!!');
make_ref:=true;
end;
procedure tbrowserlog.ident;
begin
inc(identidx,2);
end;
procedure tbrowserlog.unident;
begin
dec(identidx,2);
end;
procedure writesymtable(p:Tsymtable);forward;
procedure writelocalsymtables(p:Tprocdef;arg:pointer);
begin
if assigned(p.defref) then
begin
browserlog.AddLog('***'+p.mangledname);
browserlog.AddLogRefs(p.defref);
if (current_module.flags and uf_local_browser)<>0 then
begin
if assigned(p.parast) then
writesymtable(p.parast);
if assigned(p.localst) then
writesymtable(p.localst);
end;
end;
end;
procedure writesymtable(p:tsymtable);
var
hp : tsym;
begin
if cs_browser in current_settings.moduleswitches then
begin
if assigned(p.name) then
Browserlog.AddLog('---Symtable '+p.name^)
else
begin
if (p.symtabletype=recordsymtable) and
assigned(tdef(p.defowner).typesym) then
Browserlog.AddLog('---Symtable '+tdef(p.defowner).typesym.name)
else
Browserlog.AddLog('---Symtable with no name');
end;
Browserlog.Ident;
hp:=tstoredsym(p.symindex.first);
while assigned(hp) do
begin
if assigned(hp.defref) then
begin
browserlog.AddLog('***'+hp.name+'***');
browserlog.AddLogRefs(hp.defref);
end;
case hp.typ of
typesym :
begin
if (ttypesym(hp).typedef.deftype=recorddef) then
writesymtable(trecorddef(ttypesym(hp).typedef).symtable);
if (ttypesym(hp).typedef.deftype=objectdef) then
writesymtable(tobjectdef(ttypesym(hp).typedef).symtable);
end;
procsym :
Tprocsym(hp).foreach_procdef_static(@writelocalsymtables,nil);
end;
hp:=tstoredsym(hp.indexnext);
end;
browserlog.Unident;
end;
end;
{****************************************************************************
Helpers
****************************************************************************}
procedure WriteBrowserLog;
var
p : tstoredsymtable;
hp : tmodule;
begin
browserlog.CreateLog;
browserlog.list_debug_infos;
hp:=tmodule(loaded_units.first);
while assigned(hp) do
begin
p:=tstoredsymtable(hp.globalsymtable);
if assigned(p) then
writesymtable(p);
if cs_local_browser in current_settings.moduleswitches then
begin
p:=tstoredsymtable(hp.localsymtable);
if assigned(p) then
writesymtable(p);
end;
hp:=tmodule(hp.next);
end;
browserlog.CloseLog;
end;
procedure InitBrowserLog;
begin
browserlog.init;
end;
procedure DoneBrowserLog;
begin
browserlog.done;
end;
end.