ppdep.pp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  1. {
  2. $Id$
  3. This program is part of the Free Pascal run time library.
  4. Copyright (c) 1997 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 linux}
  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 Linux}
  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');
  490. halt(1);
  491. end;
  492. begin
  493. Define:=Nil;
  494. Outfile:='';
  495. AddCall:=0;
  496. Verbose:=False;
  497. {$IFDEF LINUX}
  498. UnitExt:='ppu';
  499. {$ELSE}
  500. UnitExt:='PPU';
  501. {$endif}
  502. for i:=1 to paramcount do
  503. begin
  504. para:=Paramstr(i);
  505. if (para[1]='-') then
  506. begin
  507. ch:=Upcase(para[2]);
  508. delete(para,1,2);
  509. case ch of
  510. 'A' : begin
  511. AddCall:=2;
  512. CallLine:=Para;
  513. end;
  514. 'F' : begin
  515. AddCall:=1;
  516. CallLine:=Para;
  517. end;
  518. 'D' : AddDefine(para);
  519. 'O' : OutFile:=Para;
  520. 'E' : UnitExt:=Para;
  521. 'V' : verbose:=true;
  522. '?','H' : helpscreen;
  523. end;
  524. end
  525. else
  526. begin
  527. ParaFile:=Para;
  528. if Pos('.',ParaFile)>0 then
  529. Delete(Parafile,Pos('.',ParaFile),255);
  530. end;
  531. end;
  532. if (ParaFile='') then
  533. HelpScreen;
  534. end;
  535. begin
  536. GetPara;
  537. ListDepend(ParaFile);
  538. ShowDepend;
  539. end.
  540. {
  541. $Log$
  542. Revision 1.1 1999-05-12 16:11:39 peter
  543. * moved
  544. Revision 1.1 1999/05/03 18:03:15 peter
  545. * renamed mkdep -> ppdep
  546. * removed obsolete units
  547. * add .cod files
  548. Revision 1.7 1998/11/18 11:15:14 michael
  549. + Added support for different unit extensions
  550. Revision 1.6 1998/10/22 23:51:35 peter
  551. * better comment support
  552. Revision 1.5 1998/08/10 09:55:21 peter
  553. * fix for uses in rejected part
  554. Revision 1.4 1998/06/24 14:02:17 peter
  555. + (* *) support
  556. Revision 1.3 1998/06/23 14:01:18 peter
  557. + -F to add a line to only the first file
  558. Revision 1.2 1998/03/27 18:39:20 peter
  559. * fixed the preprocessor
  560. + -A<call> to add the <call> to all the entries
  561. Revision 1.1.1.1 1998/03/25 11:18:48 root
  562. * Restored version
  563. Revision 1.5 1998/03/15 15:39:23 peter
  564. * fixed $ELSE
  565. Revision 1.4 1998/03/10 12:53:24 peter
  566. * much better preprocessor
  567. + IFOPT skipping
  568. Revision 1.3 1998/03/02 13:45:34 peter
  569. * works better and exefile name is written when a program is parsed
  570. Revision 1.2 1998/02/24 13:55:07 michael
  571. + Added option to write to file. Default is to stdout
  572. + Added option to write/not write a compiler call
  573. + Nr of defines is now unlimited.
  574. * Fixed bug with uppercase filenames under linux.
  575. Revision 1.1 1998/02/23 23:16:48 peter
  576. + Initial implementation
  577. }