mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-10-31 18:51:53 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			578 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			578 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
| {
 | |
|     This program is part of the Free Pascal run time library.
 | |
|     Copyright (c) 1999-2000 by Peter Vreman
 | |
|     member of the Free Pascal development team
 | |
| 
 | |
|     See the file COPYING.FPC, included in this distribution,
 | |
|     for details about the copyright.
 | |
| 
 | |
|     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.
 | |
| 
 | |
|  **********************************************************************}
 | |
| 
 | |
| { Program to create a depend makefile for a program with multiple units }
 | |
| 
 | |
| program ppdep;
 | |
| uses Dos;
 | |
| 
 | |
| {.$define debug}
 | |
| 
 | |
| const
 | |
| {$ifdef unix}
 | |
|   exeext='';
 | |
| {$else}
 | |
|   exeext='.EXE';
 | |
| {$endif}
 | |
| 
 | |
| type
 | |
|   PUses=^TUses;
 | |
|   TUses=record
 | |
|     Name : string[32];
 | |
|     Next : PUses;
 | |
|   end;
 | |
|   PUnit=^TUnit;
 | |
|   TUnit=record
 | |
|     UsesList : PUses;
 | |
|     PasFn,
 | |
|     Name     : string[32];
 | |
|     IsUnit   : boolean;
 | |
|     Next     : PUnit;
 | |
|   end;
 | |
|   PDefine=^TDefine;
 | |
|   TDefine = Record
 | |
|     Name : String[32];
 | |
|     Next : PDefine;
 | |
|     end;
 | |
| 
 | |
| 
 | |
| var
 | |
|   UnitList         : PUnit;
 | |
|   Define           : PDefine;
 | |
|   ParaFile         : string;
 | |
|   Verbose          : boolean;
 | |
|   AddCall          : byte;
 | |
|   CallLine,
 | |
|   OutFile          : String;
 | |
|   UnitExt          : String;
 | |
| 
 | |
| {****************************************************************************
 | |
|                            Handy Routines
 | |
| ****************************************************************************}
 | |
| 
 | |
| function UCase(Const Hstr:string):string;
 | |
| var
 | |
|   i : longint;
 | |
| begin
 | |
|   for i:=1to Length(Hstr) do
 | |
|    UCase[i]:=Upcase(Hstr[i]);
 | |
|   UCase[0]:=chr(Length(Hstr));
 | |
| end;
 | |
| 
 | |
| 
 | |
| function FixFn(const s:string):string;
 | |
| var
 | |
|   i      : longint;
 | |
|   NoPath : boolean;
 | |
| begin
 | |
|   NoPath:=true;
 | |
|   for i:=length(s) downto 1 do
 | |
|    begin
 | |
|      case s[i] of
 | |
|  {$ifdef unix}
 | |
|   '/','\' : begin
 | |
|               FixFn[i]:='/';
 | |
|               NoPath:=false; {Skip lowercasing path: 'X11'<>'x11' }
 | |
|             end;
 | |
|  'A'..'Z' : if NoPath then
 | |
|              FixFn[i]:=char(byte(s[i])+32)
 | |
|             else
 | |
|              FixFn[i]:=s[i];
 | |
|  {$else}
 | |
|       '/' : FixFn[i]:='\';
 | |
|  'A'..'Z' : FixFn[i]:=char(byte(s[i])+32); { everything lowercase }
 | |
|  {$endif}
 | |
|      else
 | |
|       FixFn[i]:=s[i];
 | |
|      end;
 | |
|    end;
 | |
|   FixFn[0]:=Chr(Length(s));
 | |
| end;
 | |
| 
 | |
| 
 | |
| {****************************************************************************
 | |
|                              Main Program
 | |
| ****************************************************************************}
 | |
| 
 | |
| Function SearchPas(const fn:string):string;
 | |
| var
 | |
|   Dir : SearchRec;
 | |
| begin
 | |
|   FindFirst(FixFn(fn+'.PP'),$20,Dir);
 | |
|   if Doserror=0 then
 | |
|    SearchPas:=FixFn(fn+'.PP')
 | |
|   else
 | |
|    SearchPas:=FixFn(fn+'.PAS')
 | |
| end;
 | |
| 
 | |
| 
 | |
| Function UnitDone(const fn:string):boolean;
 | |
| var
 | |
|   hp : PUnit;
 | |
| begin
 | |
|   hp:=UnitList;
 | |
|   while not (hp=nil) do
 | |
|    begin
 | |
|      if hp^.Name=fn then
 | |
|       begin
 | |
|         UnitDone:=true;
 | |
|         exit;
 | |
|       end;
 | |
|      hp:=hp^.Next;
 | |
|    end;
 | |
|   UnitDone:=false;
 | |
| end;
 | |
| 
 | |
| 
 | |
| Function CheckDefine(const s:string):boolean;
 | |
| var
 | |
|   ss : string[32];
 | |
|   P : PDefine;
 | |
| begin
 | |
|   ss:=ucase(s);
 | |
|   P:=Define;
 | |
|   while (p<>Nil) do
 | |
|    begin
 | |
|      if ss=p^.name then
 | |
|       begin
 | |
|         CheckDefine:=true;
 | |
|         exit;
 | |
|       end;
 | |
|      P:=P^.Next;
 | |
|    end;
 | |
|   CheckDefine:=false;
 | |
| end;
 | |
| 
 | |
| Procedure AddDefine(Const S : String);
 | |
| Var
 | |
|   P : PDefine;
 | |
| begin
 | |
|   New(P);
 | |
|   P^.Name:=Ucase(S);
 | |
|   P^.Next:=Define;
 | |
|   Define:=P;
 | |
| end;
 | |
| 
 | |
| 
 | |
| procedure RemoveSep(var fn:string);
 | |
| var
 | |
|   i : longint;
 | |
| begin
 | |
|   i:=0;
 | |
|   while (i<length(fn)) and (fn[i+1] in [',',' ',#9]) do
 | |
|    inc(i);
 | |
|   Delete(fn,1,i);
 | |
| end;
 | |
| 
 | |
| 
 | |
| function GetName(var fn:string):string;
 | |
| var
 | |
|   i : longint;
 | |
| begin
 | |
|   i:=0;
 | |
|   while (i<length(fn)) and (fn[i+1] in ['A'..'Z','0'..'9','_','-']) do
 | |
|    inc(i);
 | |
|   GetName:=Copy(fn,1,i);
 | |
|   Delete(fn,1,i);
 | |
| end;
 | |
| 
 | |
| 
 | |
| procedure ListDepend(const fn:string);
 | |
| 
 | |
| {$ifndef FPC}
 | |
|   procedure readln(var t:text;var s:string);
 | |
|   var
 | |
|     c : char;
 | |
|     i : longint;
 | |
|   begin
 | |
|     c:=#0;
 | |
|     i:=0;
 | |
|     while (not eof(t)) and (c<>#10) do
 | |
|      begin
 | |
|        read(t,c);
 | |
|        if c<>#10 then
 | |
|         begin
 | |
|           inc(i);
 | |
|           s[i]:=c;
 | |
|         end;
 | |
|      end;
 | |
|     if (i>0) and (s[i]=#13) then
 | |
|      dec(i);
 | |
|     s[0]:=chr(i);
 | |
|   end;
 | |
| {$endif}
 | |
| 
 | |
| const
 | |
|   MaxLevel=200;
 | |
| var
 | |
|   f  : text;
 | |
|   hs : ^string;
 | |
|   curruses,lastuses : PUses;
 | |
|   currunit,lastunit : PUnit;
 | |
|   i,j : longint;
 | |
|   UsesDone,
 | |
|   OldComment,
 | |
|   Done,Comment,
 | |
|   InImplementation : boolean;
 | |
|   Skip : array[0..MaxLevel] of boolean;
 | |
|   Level : byte;
 | |
| begin
 | |
|   if UnitDone(fn) then
 | |
|    exit;
 | |
|   new(hs);
 | |
|   new(currunit);
 | |
|   currunit^.next:=nil;
 | |
|   currunit^.Name:=fn;
 | |
|   currunit^.IsUnit:=true;
 | |
|   currunit^.PasFn:=SearchPas(fn);
 | |
|   currunit^.useslist:=nil;
 | |
|   assign(f,currunit^.PasFn);
 | |
|   {$I-}
 | |
|    reset(f);
 | |
|   {$I+}
 | |
|   if ioresult=0 then
 | |
|    begin
 | |
|      if verbose then
 | |
|       Writeln('Processing ',currunit^.PasFn);
 | |
|    {Add to Linked List}
 | |
|      if unitlist=nil then
 | |
|       unitlist:=currunit
 | |
|      else
 | |
|       begin
 | |
|         lastunit:=UnitList;
 | |
|         while not (lastunit^.Next=nil) do
 | |
|          lastunit:=lastunit^.next;
 | |
|         lastunit^.next:=currunit;
 | |
|       end;
 | |
|    {Parse file}
 | |
|      InImplementation:=false;
 | |
|      done:=false;
 | |
|      usesdone:=true;
 | |
|      Comment:=false;
 | |
|      OldComment:=false;
 | |
|      FillChar(skip,sizeof(Skip),0);
 | |
|      hs^:='';
 | |
|      Level:=0;
 | |
|      while (not done) and (not Eof(f)) do
 | |
|       begin
 | |
|         repeat
 | |
|           if hs^='' then
 | |
|            begin
 | |
|              ReadLn(f,hs^);
 | |
|              hs^:=UCase(hs^);
 | |
|            end;
 | |
|           RemoveSep(hs^);
 | |
|         until (hs^<>'') or Eof(f);
 | |
|         if Comment then
 | |
|          begin
 | |
|            i:=pos('}',hs^);
 | |
|            if (i>0) then
 | |
|             begin
 | |
|               j:=pos('{',hs^);
 | |
|               if (j>0) and (j<i) then
 | |
|                begin
 | |
|                  Comment:=true;
 | |
|                  Delete(hs^,1,j-1);
 | |
|                end
 | |
|               else
 | |
|                begin
 | |
|                  Comment:=false;
 | |
|                  Delete(hs^,1,i-1);
 | |
|                end;
 | |
|             end
 | |
|            else
 | |
|             hs^:='';
 | |
|          end;
 | |
|         if (pos('(*',hs^)>0) or OldComment then
 | |
|          begin
 | |
|            i:=pos('*)',hs^);
 | |
|            if (i>0) then
 | |
|             begin
 | |
|               OldComment:=false;
 | |
|               Delete(hs^,1,i+1);
 | |
|             end
 | |
|            else
 | |
|             begin
 | |
|               OldComment:=true;
 | |
|               hs^:='';
 | |
|             end;
 | |
|          end;
 | |
|         if (hs^<>'') then
 | |
|          begin
 | |
|            case hs^[1] of
 | |
|             '}' : begin
 | |
|                     Comment:=false;
 | |
|                     hs^:='';
 | |
|                   end;
 | |
|             '{' : begin
 | |
|                     if (Copy(hs^,2,6)='$IFDEF') then
 | |
|                      begin
 | |
|                        Delete(hs^,1,7);
 | |
|                        RemoveSep(hs^);
 | |
|                        inc(Level);
 | |
|                        if Level>=MaxLevel then
 | |
|                         begin
 | |
|                           Writeln('Too many IF(N)DEFs');
 | |
|                           Halt(1);
 | |
|                         end;
 | |
|                        skip[level]:=skip[level-1] or (not CheckDefine(GetName(hs^)));
 | |
|                        hs^:='';
 | |
|                      end
 | |
|                     else
 | |
|                      if (Copy(hs^,2,7)='$IFNDEF') then
 | |
|                       begin
 | |
|                         Delete(hs^,1,7);
 | |
|                         RemoveSep(hs^);
 | |
|                         inc(Level);
 | |
|                         if Level>=MaxLevel then
 | |
|                          begin
 | |
|                            Writeln('Too many IF(N)DEFs');
 | |
|                            Halt(1);
 | |
|                          end;
 | |
|                         skip[level]:=skip[level-1] or (CheckDefine(GetName(hs^)));
 | |
|                         hs^:='';
 | |
|                       end
 | |
|                     else
 | |
|                      if (Copy(hs^,2,6)='$ELSE') then
 | |
|                       begin
 | |
|                         skip[level]:=skip[level-1] or (not skip[level]);
 | |
|                         hs^:='';
 | |
|                       end
 | |
|                     else
 | |
|                      if (Copy(hs^,2,6)='$ENDIF') then
 | |
|                       begin
 | |
|                         skip[level]:=false;
 | |
|                         if Level=0 then
 | |
|                          begin
 | |
|                            Writeln('Too many ENDIFs');
 | |
|                            Halt(1);
 | |
|                          end;
 | |
|                         dec(level);
 | |
|                         hs^:='';
 | |
|                       end
 | |
|                     else
 | |
|                      if (Copy(hs^,2,6)='$IFOPT') then
 | |
|                       begin
 | |
|                         inc(Level);
 | |
|                         if Level>=MaxLevel then
 | |
|                          begin
 | |
|                            Writeln('Too many IF(N)DEFs');
 | |
|                            Halt(1);
 | |
|                          end;
 | |
|                         skip[level]:=true;
 | |
|                         hs^:='';
 | |
|                       end
 | |
|                     else
 | |
|                      begin
 | |
|                        i:=pos('}',hs^);
 | |
|                        if i>0 then
 | |
|                         begin
 | |
|                           Delete(hs^,1,i);
 | |
|                           Comment:=false;
 | |
|                         end
 | |
|                        else
 | |
|                         Comment:=true;
 | |
|                      end;
 | |
|                   end;
 | |
|             ';' : begin
 | |
|                     UsesDone:=true;
 | |
|                     Done:=(UsesDone and InImplementation);
 | |
|                     hs^:='';
 | |
|                   end;
 | |
|            else
 | |
|             begin
 | |
|               if skip[level] then
 | |
|                hs^:=''
 | |
|               else
 | |
|                begin
 | |
|                  if (not UsesDone) then
 | |
|                   begin
 | |
|                     new(curruses);
 | |
|                     curruses^.Name:=GetName(hs^);
 | |
|                     curruses^.next:=nil;
 | |
|                     if currunit^.useslist=nil then
 | |
|                      currunit^.useslist:=curruses
 | |
|                     else
 | |
|                      begin
 | |
|                        lastuses:=currunit^.useslist;
 | |
|                        while not (lastuses^.Next=nil) do
 | |
|                         lastuses:=lastuses^.next;
 | |
|                        lastuses^.next:=curruses;
 | |
|                      end;
 | |
|    {$ifndef debug}
 | |
|                     ListDepend(curruses^.Name);
 | |
|    {$endif}
 | |
|                     RemoveSep(hs^);
 | |
|                   end
 | |
|                  else
 | |
|                   begin
 | |
|                     if (Copy(hs^,1,4)='USES') and ((length(hs^)=4) or (hs^[5] in [' ',#9])) then
 | |
|                      begin
 | |
|                        Delete(hs^,1,4);
 | |
|                        UsesDone:=false;
 | |
|                      end
 | |
|                     else
 | |
|                      begin
 | |
|                        if (hs^='IMPLEMENTATION') then
 | |
|                         InImplementation:=true
 | |
|                        else
 | |
|                         if (Copy(hs^,1,7)='PROGRAM') then
 | |
|                          begin
 | |
|                            currunit^.IsUnit:=false;
 | |
|                            InImplementation:=true; {there can be only 1 uses}
 | |
|                          end
 | |
|                        else
 | |
|                          if InImplementation and ((copy(hs^,1,5)='CONST') or
 | |
|                             (copy(hs^,1,3)='VAR') or (copy(hs^,1,5)='BEGIN')) then
 | |
|                           done:=true;
 | |
|                        hs^:='';
 | |
|                      end;
 | |
|                   end;
 | |
|                end;
 | |
|             end;
 | |
|            end;
 | |
|          end;
 | |
|       end;
 | |
|      Close(f);
 | |
|    end
 | |
|   else
 | |
|    dispose(currunit);
 | |
|   dispose(hs);
 | |
| end;
 | |
| 
 | |
| 
 | |
| procedure ShowDepend;
 | |
| var
 | |
|   currunit : PUnit;
 | |
|   curruses : PUses;
 | |
|   t        : text;
 | |
|   P        : PDefine;
 | |
|   First    : boolean;
 | |
| begin
 | |
|   if CallLine='' then
 | |
|    begin
 | |
|      CallLine:='ppc386 ';
 | |
|      P:=Define;
 | |
|      While P<>Nil do
 | |
|       begin
 | |
|         CallLine:=CallLine+' -d'+P^.Name;
 | |
|         P:=P^.Next;
 | |
|       end;
 | |
|    end;
 | |
|   assign(t,OutFile);
 | |
|   rewrite(t);
 | |
|   currunit:=UnitList;
 | |
|   First:=true;
 | |
|   while not (currunit=nil) do
 | |
|    begin
 | |
|      if currunit^.IsUnit then
 | |
|       Write(t,FixFn(currunit^.Name+'.'+unitext)+': '+currunit^.PasFn)
 | |
|      else
 | |
|       Write(t,FixFn(currunit^.Name+exeext)+': '+currunit^.PasFn);
 | |
|      curruses:=currunit^.useslist;
 | |
|      while not (curruses=nil) do
 | |
|       begin
 | |
| {$ifndef debug}
 | |
|         if UnitDone(curruses^.name) then
 | |
| {$endif}
 | |
|          begin
 | |
|            writeln(t,' \');
 | |
|            write(t,#9+FixFn(curruses^.name+'.'+unitext));
 | |
|          end;
 | |
|         curruses:=curruses^.next;
 | |
|       end;
 | |
|      writeln(t,'');
 | |
|      If (AddCall=2) or (First and (AddCall=1)) then
 | |
|       writeln(t,#9,CallLine,' ',currunit^.PasFn);
 | |
|      writeln(t,'');
 | |
|      currunit:=currunit^.next;
 | |
|      First:=false;
 | |
|    end;
 | |
|   close(t);
 | |
| end;
 | |
| 
 | |
| 
 | |
| procedure getpara;
 | |
| var
 | |
|   ch   : char;
 | |
|   para : string[128];
 | |
|   i    : word;
 | |
| 
 | |
|   procedure helpscreen;
 | |
|   begin
 | |
|     writeln('ppdep [Options] <File>');
 | |
|     Writeln;
 | |
|     Writeln('Options can be: -D<define>   Define a symbol');
 | |
|     Writeln('                -oFile       Write output to file');
 | |
|     WRiteln('                             (default stdout)');
 | |
|     Writeln('                -eext        Set unit extension to ext');
 | |
|     Writeln('                             (default ppu)');
 | |
|     Writeln('                -V           Be more verbose');
 | |
|     Writeln('          -? or -H           This HelpScreen');
 | |
|     Writeln('                -A[call]     Add compiler calls to makefile (all files)');
 | |
|     Writeln('                -F[call]     Add compiler calls to makefile (only top file)');
 | |
|     halt(1);
 | |
|   end;
 | |
| 
 | |
| begin
 | |
|   Define:=Nil;
 | |
|   Outfile:='';
 | |
|   AddCall:=0;
 | |
|   Verbose:=False;
 | |
| {$IFDEF Unix}
 | |
|   UnitExt:='ppu';
 | |
| {$ELSE}
 | |
|   UnitExt:='PPU';
 | |
| {$endif}
 | |
|   for i:=1 to paramcount do
 | |
|    begin
 | |
|      para:=Paramstr(i);
 | |
|      if (para[1]='-') then
 | |
|       begin
 | |
|         ch:=Upcase(para[2]);
 | |
|         delete(para,1,2);
 | |
|         case ch of
 | |
|          'A' : begin
 | |
|                  AddCall:=2;
 | |
|                  CallLine:=Para;
 | |
|                end;
 | |
|          'F' : begin
 | |
|                  AddCall:=1;
 | |
|                  CallLine:=Para;
 | |
|                end;
 | |
|          'D' : AddDefine(para);
 | |
|          'O' : OutFile:=Para;
 | |
|          'E' : UnitExt:=Para;
 | |
|          'V' : verbose:=true;
 | |
|      '?','H' : helpscreen;
 | |
|         end;
 | |
|      end
 | |
|     else
 | |
|      begin
 | |
|        ParaFile:=Para;
 | |
|        if Pos('.',ParaFile)>0 then
 | |
|         Delete(Parafile,Pos('.',ParaFile),255);
 | |
|      end;
 | |
|     end;
 | |
|   if (ParaFile='') then
 | |
|    HelpScreen;
 | |
| end;
 | |
| 
 | |
| 
 | |
| begin
 | |
|   GetPara;
 | |
|   ListDepend(ParaFile);
 | |
|   ShowDepend;
 | |
| end.
 | 
