ppdep.pp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591
  1. {
  2. $Id$
  3. This program is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2000 by Peter Vreman
  5. member of the Free Pascal development team
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. { Program to create a depend makefile for a program with multiple units }
  13. program ppdep;
  14. uses Dos;
  15. {.$define debug}
  16. const
  17. {$ifdef unix}
  18. exeext='';
  19. {$else}
  20. exeext='.EXE';
  21. {$endif}
  22. type
  23. PUses=^TUses;
  24. TUses=record
  25. Name : string[32];
  26. Next : PUses;
  27. end;
  28. PUnit=^TUnit;
  29. TUnit=record
  30. UsesList : PUses;
  31. PasFn,
  32. Name : string[32];
  33. IsUnit : boolean;
  34. Next : PUnit;
  35. end;
  36. PDefine=^TDefine;
  37. TDefine = Record
  38. Name : String[32];
  39. Next : PDefine;
  40. end;
  41. var
  42. UnitList : PUnit;
  43. Define : PDefine;
  44. ParaFile : string;
  45. Verbose : boolean;
  46. AddCall : byte;
  47. CallLine,
  48. OutFile : String;
  49. UnitExt : String;
  50. {****************************************************************************
  51. Handy Routines
  52. ****************************************************************************}
  53. function UCase(Const Hstr:string):string;
  54. var
  55. i : longint;
  56. begin
  57. for i:=1to Length(Hstr) do
  58. UCase[i]:=Upcase(Hstr[i]);
  59. UCase[0]:=chr(Length(Hstr));
  60. end;
  61. function FixFn(const s:string):string;
  62. var
  63. i : longint;
  64. NoPath : boolean;
  65. begin
  66. NoPath:=true;
  67. for i:=length(s) downto 1 do
  68. begin
  69. case s[i] of
  70. {$ifdef unix}
  71. '/','\' : begin
  72. FixFn[i]:='/';
  73. NoPath:=false; {Skip lowercasing path: 'X11'<>'x11' }
  74. end;
  75. 'A'..'Z' : if NoPath then
  76. FixFn[i]:=char(byte(s[i])+32)
  77. else
  78. FixFn[i]:=s[i];
  79. {$else}
  80. '/' : FixFn[i]:='\';
  81. 'A'..'Z' : FixFn[i]:=char(byte(s[i])+32); { everything lowercase }
  82. {$endif}
  83. else
  84. FixFn[i]:=s[i];
  85. end;
  86. end;
  87. FixFn[0]:=Chr(Length(s));
  88. end;
  89. {****************************************************************************
  90. Main Program
  91. ****************************************************************************}
  92. Function SearchPas(const fn:string):string;
  93. var
  94. Dir : SearchRec;
  95. begin
  96. FindFirst(FixFn(fn+'.PP'),$20,Dir);
  97. if Doserror=0 then
  98. SearchPas:=FixFn(fn+'.PP')
  99. else
  100. SearchPas:=FixFn(fn+'.PAS')
  101. end;
  102. Function UnitDone(const fn:string):boolean;
  103. var
  104. hp : PUnit;
  105. begin
  106. hp:=UnitList;
  107. while not (hp=nil) do
  108. begin
  109. if hp^.Name=fn then
  110. begin
  111. UnitDone:=true;
  112. exit;
  113. end;
  114. hp:=hp^.Next;
  115. end;
  116. UnitDone:=false;
  117. end;
  118. Function CheckDefine(const s:string):boolean;
  119. var
  120. ss : string[32];
  121. P : PDefine;
  122. begin
  123. ss:=ucase(s);
  124. P:=Define;
  125. while (p<>Nil) do
  126. begin
  127. if ss=p^.name then
  128. begin
  129. CheckDefine:=true;
  130. exit;
  131. end;
  132. P:=P^.Next;
  133. end;
  134. CheckDefine:=false;
  135. end;
  136. Procedure AddDefine(Const S : String);
  137. Var
  138. P : PDefine;
  139. begin
  140. New(P);
  141. P^.Name:=Ucase(S);
  142. P^.Next:=Define;
  143. Define:=P;
  144. end;
  145. procedure RemoveSep(var fn:string);
  146. var
  147. i : longint;
  148. begin
  149. i:=0;
  150. while (i<length(fn)) and (fn[i+1] in [',',' ',#9]) do
  151. inc(i);
  152. Delete(fn,1,i);
  153. end;
  154. function GetName(var fn:string):string;
  155. var
  156. i : longint;
  157. begin
  158. i:=0;
  159. while (i<length(fn)) and (fn[i+1] in ['A'..'Z','0'..'9','_','-']) do
  160. inc(i);
  161. GetName:=Copy(fn,1,i);
  162. Delete(fn,1,i);
  163. end;
  164. procedure ListDepend(const fn:string);
  165. {$ifndef FPC}
  166. procedure readln(var t:text;var s:string);
  167. var
  168. c : char;
  169. i : longint;
  170. begin
  171. c:=#0;
  172. i:=0;
  173. while (not eof(t)) and (c<>#10) do
  174. begin
  175. read(t,c);
  176. if c<>#10 then
  177. begin
  178. inc(i);
  179. s[i]:=c;
  180. end;
  181. end;
  182. if (i>0) and (s[i]=#13) then
  183. dec(i);
  184. s[0]:=chr(i);
  185. end;
  186. {$endif}
  187. const
  188. MaxLevel=200;
  189. var
  190. f : text;
  191. hs : ^string;
  192. curruses,lastuses : PUses;
  193. currunit,lastunit : PUnit;
  194. i,j : longint;
  195. UsesDone,
  196. OldComment,
  197. Done,Comment,
  198. InImplementation : boolean;
  199. Skip : array[0..MaxLevel] of boolean;
  200. Level : byte;
  201. begin
  202. if UnitDone(fn) then
  203. exit;
  204. new(hs);
  205. new(currunit);
  206. currunit^.next:=nil;
  207. currunit^.Name:=fn;
  208. currunit^.IsUnit:=true;
  209. currunit^.PasFn:=SearchPas(fn);
  210. currunit^.useslist:=nil;
  211. assign(f,currunit^.PasFn);
  212. {$I-}
  213. reset(f);
  214. {$I+}
  215. if ioresult=0 then
  216. begin
  217. if verbose then
  218. Writeln('Processing ',currunit^.PasFn);
  219. {Add to Linked List}
  220. if unitlist=nil then
  221. unitlist:=currunit
  222. else
  223. begin
  224. lastunit:=UnitList;
  225. while not (lastunit^.Next=nil) do
  226. lastunit:=lastunit^.next;
  227. lastunit^.next:=currunit;
  228. end;
  229. {Parse file}
  230. InImplementation:=false;
  231. done:=false;
  232. usesdone:=true;
  233. Comment:=false;
  234. OldComment:=false;
  235. FillChar(skip,sizeof(Skip),0);
  236. hs^:='';
  237. Level:=0;
  238. while (not done) and (not Eof(f)) do
  239. begin
  240. repeat
  241. if hs^='' then
  242. begin
  243. ReadLn(f,hs^);
  244. hs^:=UCase(hs^);
  245. end;
  246. RemoveSep(hs^);
  247. until (hs^<>'') or Eof(f);
  248. if Comment then
  249. begin
  250. i:=pos('}',hs^);
  251. if (i>0) then
  252. begin
  253. j:=pos('{',hs^);
  254. if (j>0) and (j<i) then
  255. begin
  256. Comment:=true;
  257. Delete(hs^,1,j-1);
  258. end
  259. else
  260. begin
  261. Comment:=false;
  262. Delete(hs^,1,i-1);
  263. end;
  264. end
  265. else
  266. hs^:='';
  267. end;
  268. if (pos('(*',hs^)>0) or OldComment then
  269. begin
  270. i:=pos('*)',hs^);
  271. if (i>0) then
  272. begin
  273. OldComment:=false;
  274. Delete(hs^,1,i+1);
  275. end
  276. else
  277. begin
  278. OldComment:=true;
  279. hs^:='';
  280. end;
  281. end;
  282. if (hs^<>'') then
  283. begin
  284. case hs^[1] of
  285. '}' : begin
  286. Comment:=false;
  287. hs^:='';
  288. end;
  289. '{' : begin
  290. if (Copy(hs^,2,6)='$IFDEF') then
  291. begin
  292. Delete(hs^,1,7);
  293. RemoveSep(hs^);
  294. inc(Level);
  295. if Level>=MaxLevel then
  296. begin
  297. Writeln('Too many IF(N)DEFs');
  298. Halt(1);
  299. end;
  300. skip[level]:=skip[level-1] or (not CheckDefine(GetName(hs^)));
  301. hs^:='';
  302. end
  303. else
  304. if (Copy(hs^,2,7)='$IFNDEF') then
  305. begin
  306. Delete(hs^,1,7);
  307. RemoveSep(hs^);
  308. inc(Level);
  309. if Level>=MaxLevel then
  310. begin
  311. Writeln('Too many IF(N)DEFs');
  312. Halt(1);
  313. end;
  314. skip[level]:=skip[level-1] or (CheckDefine(GetName(hs^)));
  315. hs^:='';
  316. end
  317. else
  318. if (Copy(hs^,2,6)='$ELSE') then
  319. begin
  320. skip[level]:=skip[level-1] or (not skip[level]);
  321. hs^:='';
  322. end
  323. else
  324. if (Copy(hs^,2,6)='$ENDIF') then
  325. begin
  326. skip[level]:=false;
  327. if Level=0 then
  328. begin
  329. Writeln('Too many ENDIFs');
  330. Halt(1);
  331. end;
  332. dec(level);
  333. hs^:='';
  334. end
  335. else
  336. if (Copy(hs^,2,6)='$IFOPT') then
  337. begin
  338. inc(Level);
  339. if Level>=MaxLevel then
  340. begin
  341. Writeln('Too many IF(N)DEFs');
  342. Halt(1);
  343. end;
  344. skip[level]:=true;
  345. hs^:='';
  346. end
  347. else
  348. begin
  349. i:=pos('}',hs^);
  350. if i>0 then
  351. begin
  352. Delete(hs^,1,i);
  353. Comment:=false;
  354. end
  355. else
  356. Comment:=true;
  357. end;
  358. end;
  359. ';' : begin
  360. UsesDone:=true;
  361. Done:=(UsesDone and InImplementation);
  362. hs^:='';
  363. end;
  364. else
  365. begin
  366. if skip[level] then
  367. hs^:=''
  368. else
  369. begin
  370. if (not UsesDone) then
  371. begin
  372. new(curruses);
  373. curruses^.Name:=GetName(hs^);
  374. curruses^.next:=nil;
  375. if currunit^.useslist=nil then
  376. currunit^.useslist:=curruses
  377. else
  378. begin
  379. lastuses:=currunit^.useslist;
  380. while not (lastuses^.Next=nil) do
  381. lastuses:=lastuses^.next;
  382. lastuses^.next:=curruses;
  383. end;
  384. {$ifndef debug}
  385. ListDepend(curruses^.Name);
  386. {$endif}
  387. RemoveSep(hs^);
  388. end
  389. else
  390. begin
  391. if (Copy(hs^,1,4)='USES') and ((length(hs^)=4) or (hs^[5] in [' ',#9])) then
  392. begin
  393. Delete(hs^,1,4);
  394. UsesDone:=false;
  395. end
  396. else
  397. begin
  398. if (hs^='IMPLEMENTATION') then
  399. InImplementation:=true
  400. else
  401. if (Copy(hs^,1,7)='PROGRAM') then
  402. begin
  403. currunit^.IsUnit:=false;
  404. InImplementation:=true; {there can be only 1 uses}
  405. end
  406. else
  407. if InImplementation and ((copy(hs^,1,5)='CONST') or
  408. (copy(hs^,1,3)='VAR') or (copy(hs^,1,5)='BEGIN')) then
  409. done:=true;
  410. hs^:='';
  411. end;
  412. end;
  413. end;
  414. end;
  415. end;
  416. end;
  417. end;
  418. Close(f);
  419. end
  420. else
  421. dispose(currunit);
  422. dispose(hs);
  423. end;
  424. procedure ShowDepend;
  425. var
  426. currunit : PUnit;
  427. curruses : PUses;
  428. t : text;
  429. P : PDefine;
  430. First : boolean;
  431. begin
  432. if CallLine='' then
  433. begin
  434. CallLine:='ppc386 ';
  435. P:=Define;
  436. While P<>Nil do
  437. begin
  438. CallLine:=CallLine+' -d'+P^.Name;
  439. P:=P^.Next;
  440. end;
  441. end;
  442. assign(t,OutFile);
  443. rewrite(t);
  444. currunit:=UnitList;
  445. First:=true;
  446. while not (currunit=nil) do
  447. begin
  448. if currunit^.IsUnit then
  449. Write(t,FixFn(currunit^.Name+'.'+unitext)+': '+currunit^.PasFn)
  450. else
  451. Write(t,FixFn(currunit^.Name+exeext)+': '+currunit^.PasFn);
  452. curruses:=currunit^.useslist;
  453. while not (curruses=nil) do
  454. begin
  455. {$ifndef debug}
  456. if UnitDone(curruses^.name) then
  457. {$endif}
  458. begin
  459. writeln(t,' \');
  460. write(t,#9+FixFn(curruses^.name+'.'+unitext));
  461. end;
  462. curruses:=curruses^.next;
  463. end;
  464. writeln(t,'');
  465. If (AddCall=2) or (First and (AddCall=1)) then
  466. writeln(t,#9,CallLine,' ',currunit^.PasFn);
  467. writeln(t,'');
  468. currunit:=currunit^.next;
  469. First:=false;
  470. end;
  471. close(t);
  472. end;
  473. procedure getpara;
  474. var
  475. ch : char;
  476. para : string[128];
  477. i : word;
  478. procedure helpscreen;
  479. begin
  480. writeln('ppdep [Options] <File>');
  481. Writeln;
  482. Writeln('Options can be: -D<define> Define a symbol');
  483. Writeln(' -oFile Write output to file');
  484. WRiteln(' (default stdout)');
  485. Writeln(' -eext Set unit extension to ext');
  486. Writeln(' (default ppu)');
  487. Writeln(' -V Be more verbose');
  488. Writeln(' -? or -H This HelpScreen');
  489. Writeln(' -A[call] Add compiler calls to makefile (all files)');
  490. Writeln(' -F[call] Add compiler calls to makefile (only top file)');
  491. halt(1);
  492. end;
  493. begin
  494. Define:=Nil;
  495. Outfile:='';
  496. AddCall:=0;
  497. Verbose:=False;
  498. {$IFDEF Unix}
  499. UnitExt:='ppu';
  500. {$ELSE}
  501. UnitExt:='PPU';
  502. {$endif}
  503. for i:=1 to paramcount do
  504. begin
  505. para:=Paramstr(i);
  506. if (para[1]='-') then
  507. begin
  508. ch:=Upcase(para[2]);
  509. delete(para,1,2);
  510. case ch of
  511. 'A' : begin
  512. AddCall:=2;
  513. CallLine:=Para;
  514. end;
  515. 'F' : begin
  516. AddCall:=1;
  517. CallLine:=Para;
  518. end;
  519. 'D' : AddDefine(para);
  520. 'O' : OutFile:=Para;
  521. 'E' : UnitExt:=Para;
  522. 'V' : verbose:=true;
  523. '?','H' : helpscreen;
  524. end;
  525. end
  526. else
  527. begin
  528. ParaFile:=Para;
  529. if Pos('.',ParaFile)>0 then
  530. Delete(Parafile,Pos('.',ParaFile),255);
  531. end;
  532. end;
  533. if (ParaFile='') then
  534. HelpScreen;
  535. end;
  536. begin
  537. GetPara;
  538. ListDepend(ParaFile);
  539. ShowDepend;
  540. end.
  541. {
  542. $Log$
  543. Revision 1.4 2002-09-07 15:40:30 peter
  544. * old logs removed and tabs fixed
  545. Revision 1.3 2002/06/01 18:39:14 marco
  546. * Renamefest
  547. Revision 1.2 2002/02/27 16:32:50 carl
  548. * ifdef linux -> ifdef unix
  549. }