123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577 |
- {
- 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,5)='$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.
|