mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-10-26 02:11:40 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			538 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			538 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
| {
 | |
|     $Id$
 | |
|     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,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;
 | |
| {$ifdef FPC}
 | |
|              write(stderr,buf);
 | |
| {$else FPC}
 | |
|              write(buf);
 | |
| {$endif FPC}
 | |
|            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,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;
 | |
|          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:=tunitsym(sym).unitsymtable;
 | |
|               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).restype.def.deftype in [recorddef,objectdef] then
 | |
|                        begin
 | |
|                           if ttypesym(sym).restype.def.deftype=recorddef then
 | |
|                             symt:=trecorddef(ttypesym(sym).restype.def).symtable
 | |
|                           else
 | |
|                             symt:=tobjectdef(ttypesym(sym).restype.def).symtable;
 | |
|                           sym:=tstoredsym(symt.search(ss));
 | |
|                           if sym=nil then
 | |
|                             sym:=tstoredsym(symt.search(upper(ss)));
 | |
|                        end;
 | |
|                   end;
 | |
|                 varsym :
 | |
|                   begin
 | |
|                      if tvarsym(sym).vartype.def.deftype in [recorddef,objectdef] then
 | |
|                        begin
 | |
|                           if tvarsym(sym).vartype.def.deftype=recorddef then
 | |
|                             symt:=trecorddef(tvarsym(sym).vartype.def).symtable
 | |
|                           else
 | |
|                             symt:=tobjectdef(tvarsym(sym).vartype.def).symtable;
 | |
|                           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 : tstoredsym;
 | |
|         prdef : pprocdeflist;
 | |
|       begin
 | |
|         if cs_browser in aktmoduleswitches 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).restype.def.deftype=recorddef) then
 | |
|                       writesymtable(trecorddef(ttypesym(hp).restype.def).symtable);
 | |
|                     if (ttypesym(hp).restype.def.deftype=objectdef) then
 | |
|                       writesymtable(tobjectdef(ttypesym(hp).restype.def).symtable);
 | |
|                   end;
 | |
|                 procsym :
 | |
|                     Tprocsym(hp).foreach_procdef_static({$IFDEF FPCPROCVAR}@{$ENDIF}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 aktmoduleswitches 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.
 | |
| {
 | |
|   $Log$
 | |
|   Revision 1.16  2002-09-07 15:25:00  peter
 | |
|     * old logs removed and tabs fixed
 | |
| 
 | |
|   Revision 1.15  2002/08/20 10:31:26  daniel
 | |
|    * Tcallnode.det_resulttype rewritten
 | |
| 
 | |
|   Revision 1.14  2002/07/23 09:51:22  daniel
 | |
|   * Tried to make Tprocsym.defs protected. I didn't succeed but the cleanups
 | |
|     are worth comitting.
 | |
| 
 | |
|   Revision 1.13  2002/05/18 13:34:05  peter
 | |
|     * readded missing revisions
 | |
| 
 | |
|   Revision 1.12  2002/05/16 19:46:35  carl
 | |
|   + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
 | |
|   + try to fix temp allocation (still in ifdef)
 | |
|   + generic constructor calls
 | |
|   + start of tassembler / tmodulebase class cleanup
 | |
| 
 | |
| }
 | 
