files.pas 41 KB

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