files.pas 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Florian Klaempfl
  4. This unit implements an extended file management and the first loading
  5. and searching of the modules (ppufiles)
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. ****************************************************************************
  18. }
  19. unit files;
  20. {$ifdef TP}
  21. {$V+}
  22. {$endif}
  23. {$ifdef TP}
  24. {$define SHORTASMPREFIX}
  25. {$endif}
  26. {$ifdef go32v1}
  27. {$define SHORTASMPREFIX}
  28. {$endif}
  29. {$ifdef go32v2}
  30. {$define SHORTASMPREFIX}
  31. {$endif}
  32. {$ifdef OS2}
  33. { Allthough OS/2 supports long filenames I play it safe and
  34. use 8.3 filenames, because this allows the compiler to run
  35. on a FAT partition. (DM) }
  36. {$define SHORTASMPREFIX}
  37. {$endif}
  38. interface
  39. uses
  40. globtype,
  41. cobjects,globals,ppu;
  42. const
  43. {$ifdef FPC}
  44. maxunits = 1024;
  45. InputFileBufSize=32*1024;
  46. linebufincrease=512;
  47. {$else}
  48. maxunits = 128;
  49. InputFileBufSize=1024;
  50. linebufincrease=64;
  51. {$endif}
  52. type
  53. trecompile_reason = (rr_unknown,rr_noppu,rr_sourcenewer,
  54. rr_build,rr_libolder,rr_objolder,rr_asmolder,rr_crcchanged);
  55. {$ifdef FPC}
  56. tlongintarr = array[0..1000000] of longint;
  57. {$else}
  58. tlongintarr = array[0..16000] of longint;
  59. {$endif}
  60. plongintarr = ^tlongintarr;
  61. pinputfile = ^tinputfile;
  62. tinputfile = object
  63. path,name : pstring; { path and filename }
  64. next : pinputfile; { next file for reading }
  65. f : file; { current file handle }
  66. is_macro,
  67. endoffile, { still bytes left to read }
  68. closed : boolean; { is the file closed }
  69. buf : pchar; { buffer }
  70. bufstart, { buffer start position in the file }
  71. bufsize, { amount of bytes in the buffer }
  72. maxbufsize : longint; { size in memory for the buffer }
  73. saveinputpointer : pchar; { save fields for scanner variables }
  74. savelastlinepos,
  75. saveline_no : longint;
  76. linebuf : plongintarr; { line buffer to retrieve lines }
  77. maxlinebuf : longint;
  78. ref_count : longint; { to handle the browser refs }
  79. ref_index : longint;
  80. ref_next : pinputfile;
  81. constructor init(const fn:string);
  82. destructor done;
  83. procedure setpos(l:longint);
  84. procedure seekbuf(fpos:longint);
  85. procedure readbuf;
  86. function open:boolean;
  87. procedure close;
  88. procedure tempclose;
  89. function tempopen:boolean;
  90. procedure setmacro(p:pchar;len:longint);
  91. procedure setline(line,linepos:longint);
  92. function getlinestr(l:longint):string;
  93. end;
  94. pfilemanager = ^tfilemanager;
  95. tfilemanager = object
  96. files : pinputfile;
  97. last_ref_index : longint;
  98. cacheindex : longint;
  99. cacheinputfile : pinputfile;
  100. constructor init;
  101. destructor done;
  102. procedure register_file(f : pinputfile);
  103. procedure inverse_register_indexes;
  104. function get_file(l:longint) : pinputfile;
  105. function get_file_name(l :longint):string;
  106. function get_file_path(l :longint):string;
  107. end;
  108. plinkcontaineritem=^tlinkcontaineritem;
  109. tlinkcontaineritem=object(tcontaineritem)
  110. data : pstring;
  111. needlink : longint;
  112. constructor init(const s:string;m:longint);
  113. destructor done;virtual;
  114. end;
  115. plinkcontainer=^tlinkcontainer;
  116. tlinkcontainer=object(tcontainer)
  117. constructor Init;
  118. procedure insert(const s : string;m:longint);
  119. function get(var m:longint) : string;
  120. function getusemask(mask:longint) : string;
  121. function find(const s:string):boolean;
  122. end;
  123. {$ifndef NEWMAP}
  124. tunitmap = array[0..maxunits-1] of pointer;
  125. punitmap = ^tunitmap;
  126. pmodule = ^tmodule;
  127. {$else NEWMAP}
  128. pmodule = ^tmodule;
  129. tunitmap = array[0..maxunits-1] of pmodule;
  130. punitmap = ^tunitmap;
  131. {$endif NEWMAP}
  132. tmodule = object(tlinkedlist_item)
  133. ppufile : pppufile; { the PPU file }
  134. crc,
  135. interface_crc,
  136. flags : longint; { the PPU flags }
  137. compiled, { unit is already compiled }
  138. do_reload, { force reloading of the unit }
  139. do_assemble, { only assemble the object, don't recompile }
  140. do_compile, { need to compile the sources }
  141. sources_avail, { if all sources are reachable }
  142. is_unit,
  143. in_compile, { is it being compiled ?? }
  144. in_second_compile, { is this unit being compiled for the 2nd time? }
  145. in_second_load, { is this unit PPU loaded a 2nd time? }
  146. in_implementation, { processing the implementation part? }
  147. in_global : boolean; { allow global settings }
  148. recompile_reason : trecompile_reason; { the reason why the unit should be recompiled }
  149. islibrary : boolean; { if it is a library (win32 dll) }
  150. map : punitmap; { mapping of all used units }
  151. unitcount : word; { local unit counter }
  152. unit_index : word; { global counter for browser }
  153. globalsymtable, { pointer to the local/static symtable of this unit }
  154. localsymtable : pointer; { pointer to the psymtable of this unit }
  155. scanner : pointer; { scanner object used }
  156. loaded_from : pmodule;
  157. uses_imports : boolean; { Set if the module imports from DLL's.}
  158. imports : plinkedlist;
  159. _exports : plinkedlist;
  160. sourcefiles : pfilemanager;
  161. resourcefiles : tstringcontainer;
  162. linkunitofiles,
  163. linkunitstaticlibs,
  164. linkunitsharedlibs,
  165. linkotherofiles, { objects,libs loaded from the source }
  166. linkothersharedlibs, { using $L or $LINKLIB or import lib (for linux) }
  167. linkotherstaticlibs : tlinkcontainer;
  168. used_units : tlinkedlist;
  169. dependent_units : tlinkedlist;
  170. localunitsearchpath, { local searchpaths }
  171. localobjectsearchpath,
  172. localincludesearchpath,
  173. locallibrarysearchpath : TSearchPathList;
  174. path, { path where the module is find/created }
  175. outputpath, { path where the .s / .o / exe are created }
  176. modulename, { name of the module in uppercase }
  177. objfilename, { fullname of the objectfile }
  178. asmfilename, { fullname of the assemblerfile }
  179. ppufilename, { fullname of the ppufile }
  180. staticlibfilename, { fullname of the static libraryfile }
  181. sharedlibfilename, { fullname of the shared libraryfile }
  182. exefilename, { fullname of the exefile }
  183. asmprefix, { prefix for the smartlink asmfiles }
  184. mainsource : pstring; { name of the main sourcefile }
  185. {$ifdef Test_Double_checksum}
  186. crc_array : pointer;
  187. crc_size : longint;
  188. crc_array2 : pointer;
  189. crc_size2 : longint;
  190. {$endif def Test_Double_checksum}
  191. constructor init(const s:string;_is_unit:boolean);
  192. destructor done;virtual;
  193. procedure reset;
  194. procedure setfilename(const fn:string;allowoutput:boolean);
  195. function openppu:boolean;
  196. function search_unit(const n : string;onlysource:boolean):boolean;
  197. end;
  198. pused_unit = ^tused_unit;
  199. tused_unit = object(tlinkedlist_item)
  200. unitid : word;
  201. name : pstring;
  202. checksum,
  203. interface_checksum : longint;
  204. loaded : boolean;
  205. in_uses,
  206. in_interface,
  207. is_stab_written : boolean;
  208. u : pmodule;
  209. constructor init(_u : pmodule;intface:boolean);
  210. constructor init_to_load(const n:string;c,intfc:longint;intface:boolean);
  211. destructor done;virtual;
  212. end;
  213. pdependent_unit = ^tdependent_unit;
  214. tdependent_unit = object(tlinkedlist_item)
  215. u : pmodule;
  216. constructor init(_u : pmodule);
  217. end;
  218. var
  219. main_module : pmodule; { Main module of the program }
  220. current_module : pmodule; { Current module which is compiled or loaded }
  221. compiled_module : pmodule; { Current module which is compiled }
  222. current_ppu : pppufile; { Current ppufile which is read }
  223. global_unit_count : word;
  224. usedunits : tlinkedlist; { Used units for this program }
  225. loaded_units : tlinkedlist; { All loaded units }
  226. SmartLinkOFiles : TStringContainer; { List of .o files which are generated,
  227. used to delete them after linking }
  228. function get_source_file(moduleindex,fileindex : word) : pinputfile;
  229. implementation
  230. uses
  231. {$ifdef Delphi}
  232. dmisc,
  233. {$else Delphi}
  234. dos,
  235. {$endif Delphi}
  236. verbose,systems,
  237. symtable,scanner;
  238. {****************************************************************************
  239. TINPUTFILE
  240. ****************************************************************************}
  241. constructor tinputfile.init(const fn:string);
  242. var
  243. p:dirstr;
  244. n:namestr;
  245. e:extstr;
  246. begin
  247. FSplit(fn,p,n,e);
  248. name:=stringdup(n+e);
  249. path:=stringdup(p);
  250. next:=nil;
  251. { file info }
  252. is_macro:=false;
  253. endoffile:=false;
  254. closed:=true;
  255. buf:=nil;
  256. bufstart:=0;
  257. bufsize:=0;
  258. maxbufsize:=InputFileBufSize;
  259. { save fields }
  260. saveinputpointer:=nil;
  261. saveline_no:=0;
  262. savelastlinepos:=0;
  263. { indexing refs }
  264. ref_next:=nil;
  265. ref_count:=0;
  266. ref_index:=0;
  267. { line buffer }
  268. linebuf:=nil;
  269. maxlinebuf:=0;
  270. end;
  271. destructor tinputfile.done;
  272. begin
  273. if not closed then
  274. close;
  275. stringdispose(path);
  276. stringdispose(name);
  277. { free memory }
  278. if assigned(linebuf) then
  279. freemem(linebuf,maxlinebuf shl 2);
  280. end;
  281. procedure tinputfile.setpos(l:longint);
  282. begin
  283. bufstart:=l;
  284. end;
  285. procedure tinputfile.seekbuf(fpos:longint);
  286. begin
  287. if closed then
  288. exit;
  289. seek(f,fpos);
  290. bufstart:=fpos;
  291. bufsize:=0;
  292. end;
  293. procedure tinputfile.readbuf;
  294. {$ifdef TP}
  295. var
  296. w : word;
  297. {$endif}
  298. begin
  299. if is_macro then
  300. endoffile:=true;
  301. if closed then
  302. exit;
  303. inc(bufstart,bufsize);
  304. {$ifdef VER70}
  305. blockread(f,buf^,maxbufsize-1,w);
  306. bufsize:=w;
  307. {$else}
  308. blockread(f,buf^,maxbufsize-1,bufsize);
  309. {$endif}
  310. buf[bufsize]:=#0;
  311. endoffile:=eof(f);
  312. end;
  313. function tinputfile.open:boolean;
  314. var
  315. ofm : byte;
  316. begin
  317. open:=false;
  318. if not closed then
  319. Close;
  320. ofm:=filemode;
  321. filemode:=0;
  322. Assign(f,path^+name^);
  323. {$I-}
  324. reset(f,1);
  325. {$I+}
  326. filemode:=ofm;
  327. if ioresult<>0 then
  328. exit;
  329. { file }
  330. endoffile:=false;
  331. closed:=false;
  332. Getmem(buf,MaxBufsize);
  333. bufstart:=0;
  334. bufsize:=0;
  335. open:=true;
  336. end;
  337. procedure tinputfile.close;
  338. begin
  339. if is_macro then
  340. begin
  341. if assigned(buf) then
  342. Freemem(buf,maxbufsize);
  343. buf:=nil;
  344. {is_macro:=false;
  345. still needed for dispose in scanner PM }
  346. closed:=true;
  347. exit;
  348. end;
  349. if not closed then
  350. begin
  351. {$I-}
  352. system.close(f);
  353. {$I+}
  354. if ioresult<>0 then;
  355. closed:=true;
  356. end;
  357. if assigned(buf) then
  358. begin
  359. Freemem(buf,maxbufsize);
  360. buf:=nil;
  361. end;
  362. bufstart:=0;
  363. end;
  364. procedure tinputfile.tempclose;
  365. begin
  366. if is_macro then
  367. exit;
  368. if not closed then
  369. begin
  370. {$I-}
  371. system.close(f);
  372. {$I+}
  373. if ioresult<>0 then;
  374. Freemem(buf,maxbufsize);
  375. buf:=nil;
  376. closed:=true;
  377. end;
  378. end;
  379. function tinputfile.tempopen:boolean;
  380. var
  381. ofm : byte;
  382. begin
  383. tempopen:=false;
  384. if is_macro then
  385. begin
  386. { seek buffer postion to bufstart }
  387. if bufstart>0 then
  388. begin
  389. move(buf[bufstart],buf[0],bufsize-bufstart+1);
  390. bufstart:=0;
  391. end;
  392. tempopen:=true;
  393. exit;
  394. end;
  395. if not closed then
  396. exit;
  397. ofm:=filemode;
  398. filemode:=0;
  399. Assign(f,path^+name^);
  400. {$I-}
  401. reset(f,1);
  402. {$I+}
  403. filemode:=ofm;
  404. if ioresult<>0 then
  405. exit;
  406. closed:=false;
  407. { get new mem }
  408. Getmem(buf,maxbufsize);
  409. { restore state }
  410. seek(f,BufStart);
  411. bufsize:=0;
  412. readbuf;
  413. tempopen:=true;
  414. end;
  415. procedure tinputfile.setmacro(p:pchar;len:longint);
  416. begin
  417. { create new buffer }
  418. getmem(buf,len+1);
  419. move(p^,buf^,len);
  420. buf[len]:=#0;
  421. { reset }
  422. bufstart:=0;
  423. bufsize:=len;
  424. maxbufsize:=len+1;
  425. is_macro:=true;
  426. endoffile:=true;
  427. closed:=true;
  428. end;
  429. procedure tinputfile.setline(line,linepos:longint);
  430. var
  431. oldlinebuf : plongintarr;
  432. begin
  433. if line<1 then
  434. exit;
  435. while (line>=maxlinebuf) do
  436. begin
  437. oldlinebuf:=linebuf;
  438. { create new linebuf and move old info }
  439. getmem(linebuf,(maxlinebuf+linebufincrease) shl 2);
  440. if assigned(oldlinebuf) then
  441. begin
  442. move(oldlinebuf^,linebuf^,maxlinebuf shl 2);
  443. freemem(oldlinebuf,maxlinebuf shl 2);
  444. end;
  445. fillchar(linebuf^[maxlinebuf],linebufincrease shl 2,0);
  446. inc(maxlinebuf,linebufincrease);
  447. end;
  448. linebuf^[line]:=linepos;
  449. end;
  450. function tinputfile.getlinestr(l:longint):string;
  451. var
  452. c : char;
  453. i,
  454. fpos : longint;
  455. p : pchar;
  456. begin
  457. getlinestr:='';
  458. if l<maxlinebuf then
  459. begin
  460. fpos:=linebuf^[l];
  461. { fpos is set negativ if the line was already written }
  462. { but we still know the correct value }
  463. if fpos<0 then
  464. fpos:=-fpos+1;
  465. if closed then
  466. open;
  467. { in current buf ? }
  468. if (fpos<bufstart) or (fpos>bufstart+bufsize) then
  469. begin
  470. seekbuf(fpos);
  471. readbuf;
  472. end;
  473. { the begin is in the buf now simply read until #13,#10 }
  474. i:=0;
  475. p:=@buf[fpos-bufstart];
  476. repeat
  477. c:=p^;
  478. if c=#0 then
  479. begin
  480. if endoffile then
  481. break;
  482. readbuf;
  483. p:=buf;
  484. c:=p^;
  485. end;
  486. if c in [#10,#13] then
  487. break;
  488. inc(i);
  489. getlinestr[i]:=c;
  490. inc(longint(p));
  491. until (i=255);
  492. {$ifndef TP}
  493. {$ifopt H+}
  494. setlength(getlinestr,i);
  495. {$else}
  496. getlinestr[0]:=chr(i);
  497. {$endif}
  498. {$else}
  499. getlinestr[0]:=chr(i);
  500. {$endif}
  501. end;
  502. end;
  503. {****************************************************************************
  504. TFILEMANAGER
  505. ****************************************************************************}
  506. constructor tfilemanager.init;
  507. begin
  508. files:=nil;
  509. last_ref_index:=0;
  510. cacheindex:=0;
  511. cacheinputfile:=nil;
  512. end;
  513. destructor tfilemanager.done;
  514. var
  515. hp : pinputfile;
  516. begin
  517. hp:=files;
  518. while assigned(hp) do
  519. begin
  520. files:=files^.ref_next;
  521. dispose(hp,done);
  522. hp:=files;
  523. end;
  524. last_ref_index:=0;
  525. end;
  526. procedure tfilemanager.register_file(f : pinputfile);
  527. begin
  528. { don't register macro's }
  529. if f^.is_macro then
  530. exit;
  531. inc(last_ref_index);
  532. f^.ref_next:=files;
  533. f^.ref_index:=last_ref_index;
  534. files:=f;
  535. { update cache }
  536. cacheindex:=last_ref_index;
  537. cacheinputfile:=f;
  538. {$ifdef FPC}
  539. {$ifdef heaptrc}
  540. writeln(stderr,f^.name^,' index ',current_module^.unit_index*100000+f^.ref_index);
  541. {$endif heaptrc}
  542. {$endif FPC}
  543. end;
  544. { this procedure is necessary after loading the
  545. sources files from a PPU file PM }
  546. procedure tfilemanager.inverse_register_indexes;
  547. var
  548. f : pinputfile;
  549. begin
  550. f:=files;
  551. while assigned(f) do
  552. begin
  553. f^.ref_index:=last_ref_index-f^.ref_index+1;
  554. f:=f^.ref_next;
  555. end;
  556. { reset cache }
  557. cacheindex:=0;
  558. cacheinputfile:=nil;
  559. end;
  560. function tfilemanager.get_file(l :longint) : pinputfile;
  561. var
  562. ff : pinputfile;
  563. begin
  564. { check cache }
  565. if (l=cacheindex) and assigned(cacheinputfile) then
  566. begin
  567. get_file:=cacheinputfile;
  568. exit;
  569. end;
  570. ff:=files;
  571. while assigned(ff) and (ff^.ref_index<>l) do
  572. ff:=ff^.ref_next;
  573. get_file:=ff;
  574. end;
  575. function tfilemanager.get_file_name(l :longint):string;
  576. var
  577. hp : pinputfile;
  578. begin
  579. hp:=get_file(l);
  580. if assigned(hp) then
  581. get_file_name:=hp^.name^
  582. else
  583. get_file_name:='';
  584. end;
  585. function tfilemanager.get_file_path(l :longint):string;
  586. var
  587. hp : pinputfile;
  588. begin
  589. hp:=get_file(l);
  590. if assigned(hp) then
  591. get_file_path:=hp^.path^
  592. else
  593. get_file_path:='';
  594. end;
  595. function get_source_file(moduleindex,fileindex : word) : pinputfile;
  596. var
  597. hp : pmodule;
  598. f : pinputfile;
  599. begin
  600. hp:=pmodule(loaded_units.first);
  601. while assigned(hp) and (hp^.unit_index<>moduleindex) do
  602. hp:=pmodule(hp^.next);
  603. get_source_file:=nil;
  604. if not assigned(hp) then
  605. exit;
  606. f:=pinputfile(hp^.sourcefiles^.files);
  607. while assigned(f) do
  608. begin
  609. if f^.ref_index=fileindex then
  610. begin
  611. get_source_file:=f;
  612. exit;
  613. end;
  614. f:=pinputfile(f^.ref_next);
  615. end;
  616. end;
  617. {****************************************************************************
  618. TLinkContainerItem
  619. ****************************************************************************}
  620. constructor TLinkContainerItem.Init(const s:string;m:longint);
  621. begin
  622. inherited Init;
  623. data:=stringdup(s);
  624. needlink:=m;
  625. end;
  626. destructor TLinkContainerItem.Done;
  627. begin
  628. stringdispose(data);
  629. end;
  630. {****************************************************************************
  631. TLinkContainer
  632. ****************************************************************************}
  633. constructor TLinkContainer.Init;
  634. begin
  635. inherited init;
  636. end;
  637. procedure TLinkContainer.insert(const s : string;m:longint);
  638. var
  639. newnode : plinkcontaineritem;
  640. begin
  641. {if find(s) then
  642. exit; }
  643. new(newnode,init(s,m));
  644. inherited insert(newnode);
  645. end;
  646. function TLinkContainer.get(var m:longint) : string;
  647. var
  648. p : plinkcontaineritem;
  649. begin
  650. p:=plinkcontaineritem(inherited get);
  651. if p=nil then
  652. begin
  653. get:='';
  654. m:=0;
  655. exit;
  656. end;
  657. get:=p^.data^;
  658. m:=p^.needlink;
  659. dispose(p,done);
  660. end;
  661. function TLinkContainer.getusemask(mask:longint) : string;
  662. var
  663. p : plinkcontaineritem;
  664. found : boolean;
  665. begin
  666. found:=false;
  667. repeat
  668. p:=plinkcontaineritem(inherited get);
  669. if p=nil then
  670. begin
  671. getusemask:='';
  672. exit;
  673. end;
  674. getusemask:=p^.data^;
  675. found:=(p^.needlink and mask)<>0;
  676. dispose(p,done);
  677. until found;
  678. end;
  679. function TLinkContainer.find(const s:string):boolean;
  680. var
  681. newnode : plinkcontaineritem;
  682. begin
  683. find:=false;
  684. newnode:=plinkcontaineritem(root);
  685. while assigned(newnode) do
  686. begin
  687. if newnode^.data^=s then
  688. begin
  689. find:=true;
  690. exit;
  691. end;
  692. newnode:=plinkcontaineritem(newnode^.next);
  693. end;
  694. end;
  695. {****************************************************************************
  696. TMODULE
  697. ****************************************************************************}
  698. procedure tmodule.setfilename(const fn:string;allowoutput:boolean);
  699. var
  700. p : dirstr;
  701. n : NameStr;
  702. e : ExtStr;
  703. begin
  704. stringdispose(objfilename);
  705. stringdispose(asmfilename);
  706. stringdispose(ppufilename);
  707. stringdispose(staticlibfilename);
  708. stringdispose(sharedlibfilename);
  709. stringdispose(exefilename);
  710. stringdispose(outputpath);
  711. stringdispose(path);
  712. { Create names }
  713. fsplit(fn,p,n,e);
  714. n:=FixFileName(n);
  715. { set path }
  716. path:=stringdup(FixPath(p,false));
  717. { obj,asm,ppu names }
  718. p:=path^;
  719. if AllowOutput then
  720. begin
  721. if (OutputUnitDir<>'') then
  722. p:=OutputUnitDir
  723. else
  724. if (OutputExeDir<>'') then
  725. p:=OutputExeDir;
  726. end;
  727. outputpath:=stringdup(p);
  728. objfilename:=stringdup(p+n+target_info.objext);
  729. asmfilename:=stringdup(p+n+target_info.asmext);
  730. ppufilename:=stringdup(p+n+target_info.unitext);
  731. { lib and exe could be loaded with a file specified with -o }
  732. if AllowOutput and (OutputFile<>'') then
  733. n:=OutputFile;
  734. staticlibfilename:=stringdup(p+target_os.libprefix+n+target_os.staticlibext);
  735. if target_info.target=target_i386_WIN32 then
  736. sharedlibfilename:=stringdup(p+n+target_os.sharedlibext)
  737. else
  738. sharedlibfilename:=stringdup(p+target_os.libprefix+n+target_os.sharedlibext);
  739. { output dir of exe can be specified separatly }
  740. if AllowOutput and (OutputExeDir<>'') then
  741. p:=OutputExeDir
  742. else
  743. p:=path^;
  744. exefilename:=stringdup(p+n+target_info.exeext);
  745. end;
  746. function tmodule.openppu:boolean;
  747. var
  748. objfiletime,
  749. ppufiletime,
  750. asmfiletime : longint;
  751. begin
  752. openppu:=false;
  753. Message1(unit_t_ppu_loading,ppufilename^);
  754. { Get ppufile time (also check if the file exists) }
  755. ppufiletime:=getnamedfiletime(ppufilename^);
  756. if ppufiletime=-1 then
  757. exit;
  758. { Open the ppufile }
  759. Message1(unit_u_ppu_name,ppufilename^);
  760. ppufile:=new(pppufile,init(ppufilename^));
  761. ppufile^.change_endian:=source_os.endian<>target_os.endian;
  762. if not ppufile^.open then
  763. begin
  764. dispose(ppufile,done);
  765. Message(unit_u_ppu_file_too_short);
  766. exit;
  767. end;
  768. { check for a valid PPU file }
  769. if not ppufile^.CheckPPUId then
  770. begin
  771. dispose(ppufile,done);
  772. Message(unit_u_ppu_invalid_header);
  773. exit;
  774. end;
  775. { check for allowed PPU versions }
  776. if not (ppufile^.GetPPUVersion = CurrentPPUVersion) then
  777. begin
  778. dispose(ppufile,done);
  779. Message1(unit_u_ppu_invalid_version,tostr(ppufile^.GetPPUVersion));
  780. exit;
  781. end;
  782. { check the target processor }
  783. if ttargetcpu(ppufile^.header.cpu)<>target_cpu then
  784. begin
  785. dispose(ppufile,done);
  786. Message(unit_u_ppu_invalid_processor);
  787. exit;
  788. end;
  789. { check target }
  790. if ttarget(ppufile^.header.target)<>target_info.target then
  791. begin
  792. dispose(ppufile,done);
  793. Message(unit_u_ppu_invalid_target);
  794. exit;
  795. end;
  796. { Load values to be access easier }
  797. flags:=ppufile^.header.flags;
  798. crc:=ppufile^.header.checksum;
  799. interface_crc:=ppufile^.header.interface_checksum;
  800. { Show Debug info }
  801. Message1(unit_u_ppu_time,filetimestring(ppufiletime));
  802. Message1(unit_u_ppu_flags,tostr(flags));
  803. Message1(unit_u_ppu_crc,tostr(ppufile^.header.checksum));
  804. Message1(unit_u_ppu_crc,tostr(ppufile^.header.interface_checksum)+' (intfc)');
  805. { check the object and assembler file to see if we need only to
  806. assemble, only if it's not in a library }
  807. do_compile:=false;
  808. if (flags and uf_in_library)=0 then
  809. begin
  810. if (flags and uf_smart_linked)<>0 then
  811. begin
  812. objfiletime:=getnamedfiletime(staticlibfilename^);
  813. Message2(unit_u_check_time,staticlibfilename^,filetimestring(objfiletime));
  814. if (ppufiletime<0) or (objfiletime<0) or (ppufiletime>objfiletime) then
  815. begin
  816. recompile_reason:=rr_libolder;
  817. Message(unit_u_recompile_staticlib_is_older);
  818. do_compile:=true;
  819. exit;
  820. end;
  821. end;
  822. if (flags and uf_static_linked)<>0 then
  823. begin
  824. { the objectfile should be newer than the ppu file }
  825. objfiletime:=getnamedfiletime(objfilename^);
  826. Message2(unit_u_check_time,objfilename^,filetimestring(objfiletime));
  827. if (ppufiletime<0) or (objfiletime<0) or (ppufiletime>objfiletime) then
  828. begin
  829. { check if assembler file is older than ppu file }
  830. asmfileTime:=GetNamedFileTime(asmfilename^);
  831. Message2(unit_u_check_time,asmfilename^,filetimestring(asmfiletime));
  832. if (asmfiletime<0) or (ppufiletime>asmfiletime) then
  833. begin
  834. Message(unit_u_recompile_obj_and_asm_older);
  835. recompile_reason:=rr_objolder;
  836. do_compile:=true;
  837. exit;
  838. end
  839. else
  840. begin
  841. Message(unit_u_recompile_obj_older_than_asm);
  842. if not(cs_asm_extern in aktglobalswitches) then
  843. begin
  844. do_compile:=true;
  845. recompile_reason:=rr_asmolder;
  846. exit;
  847. end;
  848. end;
  849. end;
  850. end;
  851. end;
  852. openppu:=true;
  853. end;
  854. function tmodule.search_unit(const n : string;onlysource:boolean):boolean;
  855. var
  856. singlepathstring,
  857. filename : string;
  858. Function UnitExists(const ext:string):boolean;
  859. begin
  860. Message1(unit_t_unitsearch,Singlepathstring+filename+ext);
  861. UnitExists:=FileExists(Singlepathstring+FileName+ext);
  862. end;
  863. Function SearchPath(const s:string):boolean;
  864. var
  865. found : boolean;
  866. ext : string[8];
  867. begin
  868. Found:=false;
  869. singlepathstring:=FixPath(s,false);
  870. if not onlysource then
  871. begin
  872. {$ifdef CHECKPPL}
  873. { Check for PPL file }
  874. if not Found then
  875. begin
  876. Found:=UnitExists(target_info.unitlibext);
  877. if Found then
  878. Begin
  879. SetFileName(SinglePathString+FileName,false);
  880. Found:=OpenPPU;
  881. End;
  882. end;
  883. {$endif CHECKPPL}
  884. { Check for PPU file }
  885. if not Found then
  886. begin
  887. Found:=UnitExists(target_info.unitext);
  888. if Found then
  889. Begin
  890. SetFileName(SinglePathString+FileName,false);
  891. Found:=OpenPPU;
  892. End;
  893. end;
  894. end;
  895. { Check for Sources }
  896. if not Found then
  897. begin
  898. ppufile:=nil;
  899. do_compile:=true;
  900. recompile_reason:=rr_noppu;
  901. {Check for .pp file}
  902. Found:=UnitExists(target_os.sourceext);
  903. if Found then
  904. Ext:=target_os.sourceext
  905. else
  906. begin
  907. {Check for .pas}
  908. Found:=UnitExists(target_os.pasext);
  909. if Found then
  910. Ext:=target_os.pasext;
  911. end;
  912. stringdispose(mainsource);
  913. if Found then
  914. begin
  915. sources_avail:=true;
  916. {Load Filenames when found}
  917. mainsource:=StringDup(SinglePathString+FileName+Ext);
  918. SetFileName(SinglePathString+FileName,false);
  919. end
  920. else
  921. sources_avail:=false;
  922. end;
  923. SearchPath:=Found;
  924. end;
  925. Function SearchPathList(list:TSearchPathList):boolean;
  926. var
  927. hp : PStringQueueItem;
  928. found : boolean;
  929. begin
  930. found:=false;
  931. hp:=list.First;
  932. while assigned(hp) do
  933. begin
  934. found:=SearchPath(hp^.data^);
  935. if found then
  936. break;
  937. hp:=hp^.next;
  938. end;
  939. SearchPathList:=found;
  940. end;
  941. var
  942. fnd : boolean;
  943. begin
  944. filename:=FixFileName(n);
  945. { try to find unit
  946. 1. cwd
  947. 2. local unit path
  948. 3. global unit path }
  949. fnd:=SearchPath('.');
  950. if (not fnd) then
  951. fnd:=SearchPathList(current_module^.LocalUnitSearchPath);
  952. if (not fnd) then
  953. fnd:=SearchPathList(UnitSearchPath);
  954. { try to find a file with the first 8 chars of the modulename, like
  955. dos }
  956. if (not fnd) and (length(filename)>8) then
  957. begin
  958. filename:=copy(filename,1,8);
  959. fnd:=SearchPath('.');
  960. if (not fnd) then
  961. fnd:=SearchPathList(current_module^.LocalUnitSearchPath);
  962. if not fnd then
  963. fnd:=SearchPathList(UnitSearchPath);
  964. end;
  965. search_unit:=fnd;
  966. end;
  967. procedure tmodule.reset;
  968. var
  969. pm : pdependent_unit;
  970. begin
  971. if assigned(scanner) then
  972. pscannerfile(scanner)^.invalid:=true;
  973. if assigned(globalsymtable) then
  974. begin
  975. dispose(punitsymtable(globalsymtable),done);
  976. globalsymtable:=nil;
  977. end;
  978. if assigned(localsymtable) then
  979. begin
  980. dispose(punitsymtable(localsymtable),done);
  981. localsymtable:=nil;
  982. end;
  983. if assigned(map) then
  984. begin
  985. dispose(map);
  986. map:=nil;
  987. end;
  988. if assigned(ppufile) then
  989. begin
  990. dispose(ppufile,done);
  991. ppufile:=nil;
  992. end;
  993. sourcefiles^.done;
  994. sourcefiles^.init;
  995. imports^.done;
  996. imports^.init;
  997. _exports^.done;
  998. _exports^.init;
  999. used_units.done;
  1000. used_units.init;
  1001. { all units that depend on this one must be recompiled ! }
  1002. pm:=pdependent_unit(dependent_units.first);
  1003. while assigned(pm) do
  1004. begin
  1005. if pm^.u^.in_second_compile then
  1006. Comment(v_debug,'No reload already in second compile: '+pm^.u^.modulename^)
  1007. else
  1008. begin
  1009. pm^.u^.do_reload:=true;
  1010. Comment(v_debug,'Reloading '+pm^.u^.modulename^+' needed because '+modulename^+' is reloaded');
  1011. end;
  1012. pm:=pdependent_unit(pm^.next);
  1013. end;
  1014. dependent_units.done;
  1015. dependent_units.init;
  1016. resourcefiles.done;
  1017. resourcefiles.init;
  1018. linkunitofiles.done;
  1019. linkunitofiles.init;
  1020. linkunitstaticlibs.done;
  1021. linkunitstaticlibs.init;
  1022. linkunitsharedlibs.done;
  1023. linkunitsharedlibs.init;
  1024. linkotherofiles.done;
  1025. linkotherofiles.init;
  1026. linkotherstaticlibs.done;
  1027. linkotherstaticlibs.init;
  1028. linkothersharedlibs.done;
  1029. linkothersharedlibs.init;
  1030. uses_imports:=false;
  1031. do_assemble:=false;
  1032. do_compile:=false;
  1033. { sources_avail:=true;
  1034. should not be changed PM }
  1035. compiled:=false;
  1036. in_implementation:=false;
  1037. in_global:=true;
  1038. {loaded_from:=nil;
  1039. should not be changed PFV }
  1040. flags:=0;
  1041. crc:=0;
  1042. interface_crc:=0;
  1043. unitcount:=1;
  1044. recompile_reason:=rr_unknown;
  1045. end;
  1046. constructor tmodule.init(const s:string;_is_unit:boolean);
  1047. var
  1048. p : dirstr;
  1049. n : namestr;
  1050. e : extstr;
  1051. begin
  1052. FSplit(s,p,n,e);
  1053. { Programs have the name program to don't conflict with dup id's }
  1054. if _is_unit then
  1055. {$ifdef UNITALIASES}
  1056. modulename:=stringdup(GetUnitAlias(Upper(n)))
  1057. {$else}
  1058. modulename:=stringdup(Upper(n))
  1059. {$endif}
  1060. else
  1061. modulename:=stringdup('PROGRAM');
  1062. mainsource:=stringdup(s);
  1063. ppufilename:=nil;
  1064. objfilename:=nil;
  1065. asmfilename:=nil;
  1066. staticlibfilename:=nil;
  1067. sharedlibfilename:=nil;
  1068. exefilename:=nil;
  1069. { Dos has the famous 8.3 limit :( }
  1070. {$ifdef SHORTASMPREFIX}
  1071. asmprefix:=stringdup(FixFileName('as'));
  1072. {$else}
  1073. asmprefix:=stringdup(FixFileName(n));
  1074. {$endif}
  1075. outputpath:=nil;
  1076. path:=nil;
  1077. setfilename(p+n,true);
  1078. localunitsearchpath.init;
  1079. localobjectsearchpath.init;
  1080. localincludesearchpath.init;
  1081. locallibrarysearchpath.init;
  1082. used_units.init;
  1083. dependent_units.init;
  1084. new(sourcefiles,init);
  1085. resourcefiles.init;
  1086. linkunitofiles.init;
  1087. linkunitstaticlibs.init;
  1088. linkunitsharedlibs.init;
  1089. linkotherofiles.init;
  1090. linkotherstaticlibs.init;
  1091. linkothersharedlibs.init;
  1092. ppufile:=nil;
  1093. scanner:=nil;
  1094. map:=nil;
  1095. globalsymtable:=nil;
  1096. localsymtable:=nil;
  1097. loaded_from:=nil;
  1098. flags:=0;
  1099. crc:=0;
  1100. interface_crc:=0;
  1101. do_reload:=false;
  1102. unitcount:=1;
  1103. inc(global_unit_count);
  1104. unit_index:=global_unit_count;
  1105. do_assemble:=false;
  1106. do_compile:=false;
  1107. sources_avail:=true;
  1108. compiled:=false;
  1109. recompile_reason:=rr_unknown;
  1110. in_second_load:=false;
  1111. in_compile:=false;
  1112. in_second_compile:=false;
  1113. in_implementation:=false;
  1114. in_global:=true;
  1115. is_unit:=_is_unit;
  1116. islibrary:=false;
  1117. uses_imports:=false;
  1118. imports:=new(plinkedlist,init);
  1119. _exports:=new(plinkedlist,init);
  1120. { search the PPU file if it is an unit }
  1121. if is_unit then
  1122. search_unit(modulename^,false);
  1123. end;
  1124. destructor tmodule.done;
  1125. {$ifdef MEMDEBUG}
  1126. var
  1127. d : tmemdebug;
  1128. {$endif}
  1129. begin
  1130. if assigned(map) then
  1131. dispose(map);
  1132. if assigned(ppufile) then
  1133. dispose(ppufile,done);
  1134. ppufile:=nil;
  1135. if assigned(imports) then
  1136. dispose(imports,done);
  1137. imports:=nil;
  1138. if assigned(_exports) then
  1139. dispose(_exports,done);
  1140. _exports:=nil;
  1141. if assigned(scanner) then
  1142. pscannerfile(scanner)^.invalid:=true;
  1143. if assigned(sourcefiles) then
  1144. dispose(sourcefiles,done);
  1145. sourcefiles:=nil;
  1146. used_units.done;
  1147. dependent_units.done;
  1148. resourcefiles.done;
  1149. linkunitofiles.done;
  1150. linkunitstaticlibs.done;
  1151. linkunitsharedlibs.done;
  1152. linkotherofiles.done;
  1153. linkotherstaticlibs.done;
  1154. linkothersharedlibs.done;
  1155. stringdispose(objfilename);
  1156. stringdispose(asmfilename);
  1157. stringdispose(ppufilename);
  1158. stringdispose(staticlibfilename);
  1159. stringdispose(sharedlibfilename);
  1160. stringdispose(exefilename);
  1161. stringdispose(outputpath);
  1162. stringdispose(path);
  1163. stringdispose(modulename);
  1164. stringdispose(mainsource);
  1165. stringdispose(asmprefix);
  1166. localunitsearchpath.done;
  1167. localobjectsearchpath.done;
  1168. localincludesearchpath.done;
  1169. locallibrarysearchpath.done;
  1170. {$ifdef MEMDEBUG}
  1171. d.init('symtable');
  1172. {$endif}
  1173. if assigned(globalsymtable) then
  1174. dispose(punitsymtable(globalsymtable),done);
  1175. globalsymtable:=nil;
  1176. if assigned(localsymtable) then
  1177. dispose(punitsymtable(localsymtable),done);
  1178. localsymtable:=nil;
  1179. {$ifdef MEMDEBUG}
  1180. d.done;
  1181. {$endif}
  1182. inherited done;
  1183. end;
  1184. {****************************************************************************
  1185. TUSED_UNIT
  1186. ****************************************************************************}
  1187. constructor tused_unit.init(_u : pmodule;intface:boolean);
  1188. begin
  1189. u:=_u;
  1190. in_interface:=intface;
  1191. in_uses:=false;
  1192. is_stab_written:=false;
  1193. loaded:=true;
  1194. name:=stringdup(_u^.modulename^);
  1195. checksum:=_u^.crc;
  1196. interface_checksum:=_u^.interface_crc;
  1197. unitid:=0;
  1198. end;
  1199. constructor tused_unit.init_to_load(const n:string;c,intfc:longint;intface:boolean);
  1200. begin
  1201. u:=nil;
  1202. in_interface:=intface;
  1203. in_uses:=false;
  1204. is_stab_written:=false;
  1205. loaded:=false;
  1206. name:=stringdup(n);
  1207. checksum:=c;
  1208. interface_checksum:=intfc;
  1209. unitid:=0;
  1210. end;
  1211. destructor tused_unit.done;
  1212. begin
  1213. stringdispose(name);
  1214. inherited done;
  1215. end;
  1216. {****************************************************************************
  1217. TDENPENDENT_UNIT
  1218. ****************************************************************************}
  1219. constructor tdependent_unit.init(_u : pmodule);
  1220. begin
  1221. u:=_u;
  1222. end;
  1223. end.
  1224. {
  1225. $Log$
  1226. Revision 1.116 2000-02-24 18:41:38 peter
  1227. * removed warnings/notes
  1228. Revision 1.115 2000/02/10 16:00:23 peter
  1229. * dont' check for ppl files as they aren't used atm.
  1230. Revision 1.114 2000/02/09 13:22:52 peter
  1231. * log truncated
  1232. Revision 1.113 2000/01/11 09:52:06 peter
  1233. * fixed placing of .sl directories
  1234. * use -b again for base-file selection
  1235. * fixed group writing for linux with smartlinking
  1236. Revision 1.112 2000/01/07 01:14:27 peter
  1237. * updated copyright to 2000
  1238. Revision 1.111 1999/12/08 01:01:11 peter
  1239. * fixed circular unit reference checking. loaded_from was reset after
  1240. reseting a unit, so no loaded_from info was available anymore.
  1241. Revision 1.110 1999/11/16 23:39:04 peter
  1242. * use outputexedir for link.res location
  1243. Revision 1.109 1999/11/12 11:03:50 peter
  1244. * searchpaths changed to stringqueue object
  1245. Revision 1.108 1999/11/06 14:34:20 peter
  1246. * truncated log to 20 revs
  1247. Revision 1.107 1999/11/04 23:13:25 peter
  1248. * moved unit alias support into ifdef
  1249. Revision 1.106 1999/11/04 10:54:02 peter
  1250. + -Ua<oldname>=<newname> unit alias support
  1251. Revision 1.105 1999/10/28 13:14:00 pierre
  1252. * allow doubles in TLinkContainer needed for double libraries
  1253. Revision 1.104 1999/09/27 23:40:12 peter
  1254. * fixed macro within macro endless-loop
  1255. Revision 1.103 1999/09/16 08:00:50 pierre
  1256. + compiled_module to avoid wrong file info when load PPU files
  1257. Revision 1.102 1999/08/31 15:51:10 pierre
  1258. * in_second_compile cleaned up, in_compile and in_second_load added
  1259. Revision 1.101 1999/08/27 10:43:20 pierre
  1260. + interface CRC check with ifdef Test_double_checksum added
  1261. Revision 1.100 1999/08/24 13:14:01 peter
  1262. * MEMDEBUG to see the sizes of asmlist,asmsymbols,symtables
  1263. }