finput.pas 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl
  4. This unit implements an extended file management
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit finput;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. cutils,cclasses;
  23. const
  24. InputFileBufSize=32*1024;
  25. linebufincrease=512;
  26. type
  27. tlongintarr = array[0..1000000] of longint;
  28. plongintarr = ^tlongintarr;
  29. tinputfile = class
  30. path,name : pstring; { path and filename }
  31. next : tinputfile; { next file for reading }
  32. is_macro,
  33. endoffile, { still bytes left to read }
  34. closed : boolean; { is the file closed }
  35. buf : pchar; { buffer }
  36. bufstart, { buffer start position in the file }
  37. bufsize, { amount of bytes in the buffer }
  38. maxbufsize : longint; { size in memory for the buffer }
  39. saveinputpointer : pchar; { save fields for scanner variables }
  40. savelastlinepos,
  41. saveline_no : longint;
  42. linebuf : plongintarr; { line buffer to retrieve lines }
  43. maxlinebuf : longint;
  44. ref_index : longint; { to handle the browser refs }
  45. ref_next : tinputfile;
  46. constructor create(const fn:string);
  47. destructor destroy;override;
  48. procedure setpos(l:longint);
  49. procedure seekbuf(fpos:longint);
  50. procedure readbuf;
  51. function open:boolean;
  52. procedure close;
  53. procedure tempclose;
  54. function tempopen:boolean;
  55. procedure setmacro(p:pchar;len:longint);
  56. procedure setline(line,linepos:longint);
  57. function getlinestr(l:longint):string;
  58. function getfiletime:longint;
  59. protected
  60. filetime : longint;
  61. function fileopen(const filename: string): boolean; virtual; abstract;
  62. function fileseek(pos: longint): boolean; virtual; abstract;
  63. function fileread(var databuf; maxsize: longint): longint; virtual; abstract;
  64. function fileeof: boolean; virtual; abstract;
  65. function fileclose: boolean; virtual; abstract;
  66. procedure filegettime; virtual; abstract;
  67. end;
  68. tdosinputfile = class(tinputfile)
  69. protected
  70. function fileopen(const filename: string): boolean; override;
  71. function fileseek(pos: longint): boolean; override;
  72. function fileread(var databuf; maxsize: longint): longint; override;
  73. function fileeof: boolean; override;
  74. function fileclose: boolean; override;
  75. procedure filegettime; override;
  76. private
  77. f : file; { current file handle }
  78. end;
  79. tinputfilemanager = class
  80. files : tinputfile;
  81. last_ref_index : longint;
  82. cacheindex : longint;
  83. cacheinputfile : tinputfile;
  84. constructor create;
  85. destructor destroy;override;
  86. procedure register_file(f : tinputfile);
  87. procedure inverse_register_indexes;
  88. function get_file(l:longint) : tinputfile;
  89. function get_file_name(l :longint):string;
  90. function get_file_path(l :longint):string;
  91. end;
  92. {****************************************************************************
  93. TModuleBase
  94. ****************************************************************************}
  95. type
  96. tmodulestate = (ms_unknown,
  97. ms_registered,
  98. ms_load,ms_compile,
  99. ms_second_load,ms_second_compile,
  100. ms_compiled
  101. );
  102. const
  103. ModuleStateStr : array[TModuleState] of string[20] = (
  104. 'Unknown',
  105. 'Registered',
  106. 'Load','Compile',
  107. 'Second_Load','Second_Compile',
  108. 'Compiled'
  109. );
  110. type
  111. tmodulebase = class(TLinkedListItem)
  112. { index }
  113. unit_index : longint; { global counter for browser }
  114. { status }
  115. state : tmodulestate;
  116. { sources }
  117. sourcefiles : tinputfilemanager;
  118. { paths and filenames }
  119. path, { path where the module is find/created }
  120. outputpath, { path where the .s / .o / exe are created }
  121. modulename, { name of the module in uppercase }
  122. realmodulename, { name of the module in the orignal case }
  123. objfilename, { fullname of the objectfile }
  124. newfilename, { fullname of the assemblerfile }
  125. ppufilename, { fullname of the ppufile }
  126. staticlibfilename, { fullname of the static libraryfile }
  127. sharedlibfilename, { fullname of the shared libraryfile }
  128. mapfilename, { fullname of the mapfile }
  129. exefilename, { fullname of the exefile }
  130. mainsource : pstring; { name of the main sourcefile }
  131. constructor create(const s:string);
  132. destructor destroy;override;
  133. procedure setfilename(const fn:string;allowoutput:boolean);
  134. function get_asmfilename : string;
  135. end;
  136. implementation
  137. uses
  138. {$ifdef Delphi}
  139. dmisc,
  140. {$else Delphi}
  141. dos,
  142. {$endif Delphi}
  143. {$ifdef heaptrc}
  144. fmodule,
  145. ppheap,
  146. {$endif heaptrc}
  147. globals,systems
  148. ;
  149. {****************************************************************************
  150. TINPUTFILE
  151. ****************************************************************************}
  152. constructor tinputfile.create(const fn:string);
  153. var
  154. p:dirstr;
  155. n:namestr;
  156. e:extstr;
  157. begin
  158. FSplit(fn,p,n,e);
  159. name:=stringdup(n+e);
  160. path:=stringdup(p);
  161. next:=nil;
  162. filetime:=-1;
  163. { file info }
  164. is_macro:=false;
  165. endoffile:=false;
  166. closed:=true;
  167. buf:=nil;
  168. bufstart:=0;
  169. bufsize:=0;
  170. maxbufsize:=InputFileBufSize;
  171. { save fields }
  172. saveinputpointer:=nil;
  173. saveline_no:=0;
  174. savelastlinepos:=0;
  175. { indexing refs }
  176. ref_next:=nil;
  177. ref_index:=0;
  178. { line buffer }
  179. linebuf:=nil;
  180. maxlinebuf:=0;
  181. end;
  182. destructor tinputfile.destroy;
  183. begin
  184. if not closed then
  185. close;
  186. stringdispose(path);
  187. stringdispose(name);
  188. { free memory }
  189. if assigned(linebuf) then
  190. freemem(linebuf,maxlinebuf shl 2);
  191. end;
  192. procedure tinputfile.setpos(l:longint);
  193. begin
  194. bufstart:=l;
  195. end;
  196. procedure tinputfile.seekbuf(fpos:longint);
  197. begin
  198. if closed then
  199. exit;
  200. fileseek(fpos);
  201. bufstart:=fpos;
  202. bufsize:=0;
  203. end;
  204. procedure tinputfile.readbuf;
  205. begin
  206. if is_macro then
  207. endoffile:=true;
  208. if closed then
  209. exit;
  210. inc(bufstart,bufsize);
  211. bufsize:=fileread(buf^,maxbufsize-1);
  212. buf[bufsize]:=#0;
  213. endoffile:=fileeof;
  214. end;
  215. function tinputfile.open:boolean;
  216. begin
  217. open:=false;
  218. if not closed then
  219. Close;
  220. if not fileopen(path^+name^) then
  221. exit;
  222. { file }
  223. endoffile:=false;
  224. closed:=false;
  225. Getmem(buf,MaxBufsize);
  226. bufstart:=0;
  227. bufsize:=0;
  228. open:=true;
  229. end;
  230. procedure tinputfile.close;
  231. begin
  232. if is_macro then
  233. begin
  234. if assigned(buf) then
  235. begin
  236. Freemem(buf,maxbufsize);
  237. buf:=nil;
  238. end;
  239. closed:=true;
  240. exit;
  241. end;
  242. if not closed then
  243. begin
  244. fileclose;
  245. closed:=true;
  246. end;
  247. if assigned(buf) then
  248. begin
  249. Freemem(buf,maxbufsize);
  250. buf:=nil;
  251. end;
  252. bufstart:=0;
  253. end;
  254. procedure tinputfile.tempclose;
  255. begin
  256. if is_macro then
  257. exit;
  258. if not closed then
  259. begin
  260. fileclose;
  261. if assigned(buf) then
  262. begin
  263. Freemem(buf,maxbufsize);
  264. buf:=nil;
  265. end;
  266. closed:=true;
  267. end;
  268. end;
  269. function tinputfile.tempopen:boolean;
  270. begin
  271. tempopen:=false;
  272. if is_macro then
  273. begin
  274. { seek buffer postion to bufstart }
  275. if bufstart>0 then
  276. begin
  277. move(buf[bufstart],buf[0],bufsize-bufstart+1);
  278. bufstart:=0;
  279. end;
  280. tempopen:=true;
  281. exit;
  282. end;
  283. if not closed then
  284. exit;
  285. if not fileopen(path^+name^) then
  286. exit;
  287. closed:=false;
  288. { get new mem }
  289. Getmem(buf,maxbufsize);
  290. { restore state }
  291. fileseek(BufStart);
  292. bufsize:=0;
  293. readbuf;
  294. tempopen:=true;
  295. end;
  296. procedure tinputfile.setmacro(p:pchar;len:longint);
  297. begin
  298. { create new buffer }
  299. getmem(buf,len+1);
  300. move(p^,buf^,len);
  301. buf[len]:=#0;
  302. { reset }
  303. bufstart:=0;
  304. bufsize:=len;
  305. maxbufsize:=len+1;
  306. is_macro:=true;
  307. endoffile:=true;
  308. closed:=true;
  309. end;
  310. procedure tinputfile.setline(line,linepos:longint);
  311. var
  312. oldlinebuf : plongintarr;
  313. begin
  314. if line<1 then
  315. exit;
  316. while (line>=maxlinebuf) do
  317. begin
  318. oldlinebuf:=linebuf;
  319. { create new linebuf and move old info }
  320. getmem(linebuf,(maxlinebuf+linebufincrease) shl 2);
  321. if assigned(oldlinebuf) then
  322. begin
  323. move(oldlinebuf^,linebuf^,maxlinebuf shl 2);
  324. freemem(oldlinebuf,maxlinebuf shl 2);
  325. end;
  326. fillchar(linebuf^[maxlinebuf],linebufincrease shl 2,0);
  327. inc(maxlinebuf,linebufincrease);
  328. end;
  329. linebuf^[line]:=linepos;
  330. end;
  331. function tinputfile.getlinestr(l:longint):string;
  332. var
  333. c : char;
  334. i,
  335. fpos : longint;
  336. p : pchar;
  337. begin
  338. getlinestr:='';
  339. if l<maxlinebuf then
  340. begin
  341. fpos:=linebuf^[l];
  342. { fpos is set negativ if the line was already written }
  343. { but we still know the correct value }
  344. if fpos<0 then
  345. fpos:=-fpos+1;
  346. if closed then
  347. open;
  348. { in current buf ? }
  349. if (fpos<bufstart) or (fpos>bufstart+bufsize) then
  350. begin
  351. seekbuf(fpos);
  352. readbuf;
  353. end;
  354. { the begin is in the buf now simply read until #13,#10 }
  355. i:=0;
  356. p:=@buf[fpos-bufstart];
  357. repeat
  358. c:=p^;
  359. if c=#0 then
  360. begin
  361. if endoffile then
  362. break;
  363. readbuf;
  364. p:=buf;
  365. c:=p^;
  366. end;
  367. if c in [#10,#13] then
  368. break;
  369. inc(i);
  370. getlinestr[i]:=c;
  371. inc(longint(p));
  372. until (i=255);
  373. getlinestr[0]:=chr(i);
  374. end;
  375. end;
  376. function tinputfile.getfiletime:longint;
  377. begin
  378. if filetime=-1 then
  379. filegettime;
  380. getfiletime:=filetime;
  381. end;
  382. {****************************************************************************
  383. TDOSINPUTFILE
  384. ****************************************************************************}
  385. function tdosinputfile.fileopen(const filename: string): boolean;
  386. var
  387. ofm : byte;
  388. begin
  389. ofm:=filemode;
  390. filemode:=0;
  391. Assign(f,filename);
  392. {$I-}
  393. reset(f,1);
  394. {$I+}
  395. filemode:=ofm;
  396. fileopen:=(ioresult=0);
  397. end;
  398. function tdosinputfile.fileseek(pos: longint): boolean;
  399. begin
  400. {$I-}
  401. seek(f,Pos);
  402. {$I+}
  403. fileseek:=(ioresult=0);
  404. end;
  405. function tdosinputfile.fileread(var databuf; maxsize: longint): longint;
  406. var
  407. w : longint;
  408. begin
  409. blockread(f,databuf,maxsize,w);
  410. fileread:=w;
  411. end;
  412. function tdosinputfile.fileeof: boolean;
  413. begin
  414. fileeof:=eof(f);
  415. end;
  416. function tdosinputfile.fileclose: boolean;
  417. begin
  418. {$I-}
  419. system.close(f);
  420. {$I+}
  421. fileclose:=(ioresult=0);
  422. end;
  423. procedure tdosinputfile.filegettime;
  424. begin
  425. filetime:=getnamedfiletime(path^+name^);
  426. end;
  427. {****************************************************************************
  428. Tinputfilemanager
  429. ****************************************************************************}
  430. constructor tinputfilemanager.create;
  431. begin
  432. files:=nil;
  433. last_ref_index:=0;
  434. cacheindex:=0;
  435. cacheinputfile:=nil;
  436. end;
  437. destructor tinputfilemanager.destroy;
  438. var
  439. hp : tinputfile;
  440. begin
  441. hp:=files;
  442. while assigned(hp) do
  443. begin
  444. files:=files.ref_next;
  445. hp.free;
  446. hp:=files;
  447. end;
  448. last_ref_index:=0;
  449. end;
  450. procedure tinputfilemanager.register_file(f : tinputfile);
  451. begin
  452. { don't register macro's }
  453. if f.is_macro then
  454. exit;
  455. inc(last_ref_index);
  456. f.ref_next:=files;
  457. f.ref_index:=last_ref_index;
  458. files:=f;
  459. { update cache }
  460. cacheindex:=last_ref_index;
  461. cacheinputfile:=f;
  462. {$ifdef heaptrc}
  463. ppheap_register_file(f.name^,current_module.unit_index*100000+f.ref_index);
  464. {$endif heaptrc}
  465. end;
  466. { this procedure is necessary after loading the
  467. sources files from a PPU file PM }
  468. procedure tinputfilemanager.inverse_register_indexes;
  469. var
  470. f : tinputfile;
  471. begin
  472. f:=files;
  473. while assigned(f) do
  474. begin
  475. f.ref_index:=last_ref_index-f.ref_index+1;
  476. f:=f.ref_next;
  477. end;
  478. { reset cache }
  479. cacheindex:=0;
  480. cacheinputfile:=nil;
  481. end;
  482. function tinputfilemanager.get_file(l :longint) : tinputfile;
  483. var
  484. ff : tinputfile;
  485. begin
  486. { check cache }
  487. if (l=cacheindex) and assigned(cacheinputfile) then
  488. begin
  489. get_file:=cacheinputfile;
  490. exit;
  491. end;
  492. ff:=files;
  493. while assigned(ff) and (ff.ref_index<>l) do
  494. ff:=ff.ref_next;
  495. get_file:=ff;
  496. end;
  497. function tinputfilemanager.get_file_name(l :longint):string;
  498. var
  499. hp : tinputfile;
  500. begin
  501. hp:=get_file(l);
  502. if assigned(hp) then
  503. get_file_name:=hp.name^
  504. else
  505. get_file_name:='';
  506. end;
  507. function tinputfilemanager.get_file_path(l :longint):string;
  508. var
  509. hp : tinputfile;
  510. begin
  511. hp:=get_file(l);
  512. if assigned(hp) then
  513. get_file_path:=hp.path^
  514. else
  515. get_file_path:='';
  516. end;
  517. {****************************************************************************
  518. TModuleBase
  519. ****************************************************************************}
  520. procedure tmodulebase.setfilename(const fn:string;allowoutput:boolean);
  521. var
  522. p : dirstr;
  523. n : NameStr;
  524. e : ExtStr;
  525. begin
  526. stringdispose(objfilename);
  527. stringdispose(newfilename);
  528. stringdispose(ppufilename);
  529. stringdispose(staticlibfilename);
  530. stringdispose(sharedlibfilename);
  531. stringdispose(mapfilename);
  532. stringdispose(exefilename);
  533. stringdispose(outputpath);
  534. stringdispose(path);
  535. { Create names }
  536. fsplit(fn,p,n,e);
  537. n:=FixFileName(n);
  538. { set path }
  539. path:=stringdup(FixPath(p,false));
  540. { obj,asm,ppu names }
  541. p:=path^;
  542. if AllowOutput then
  543. begin
  544. if (OutputUnitDir<>'') then
  545. p:=OutputUnitDir
  546. else
  547. if (OutputExeDir<>'') then
  548. p:=OutputExeDir;
  549. end;
  550. outputpath:=stringdup(p);
  551. newfilename := stringdup(n);
  552. objfilename:=stringdup(p+n+target_info.objext);
  553. ppufilename:=stringdup(p+n+target_info.unitext);
  554. { lib and exe could be loaded with a file specified with -o }
  555. if AllowOutput and (OutputFile<>'') and (compile_level=1) then
  556. n:=OutputFile;
  557. staticlibfilename:=stringdup(p+target_info.staticlibprefix+n+target_info.staticlibext);
  558. { output dir of exe can be specified separatly }
  559. if AllowOutput and (OutputExeDir<>'') then
  560. p:=OutputExeDir
  561. else
  562. p:=path^;
  563. if target_info.system in [system_i386_WIN32,system_i386_wdosx] then
  564. sharedlibfilename:=stringdup(p+n+target_info.sharedlibext)
  565. else
  566. sharedlibfilename:=stringdup(p+target_info.sharedlibprefix+n+target_info.sharedlibext);
  567. exefilename:=stringdup(p+n+target_info.exeext);
  568. mapfilename:=stringdup(p+n+'.map');
  569. end;
  570. constructor tmodulebase.create(const s:string);
  571. begin
  572. modulename:=stringdup(Upper(s));
  573. realmodulename:=stringdup(s);
  574. mainsource:=nil;
  575. ppufilename:=nil;
  576. objfilename:=nil;
  577. newfilename:=nil;
  578. staticlibfilename:=nil;
  579. sharedlibfilename:=nil;
  580. exefilename:=nil;
  581. mapfilename:=nil;
  582. outputpath:=nil;
  583. path:=nil;
  584. { status }
  585. state:=ms_registered;
  586. { unit index }
  587. inc(global_unit_count);
  588. unit_index:=global_unit_count;
  589. { sources }
  590. sourcefiles:=TInputFileManager.Create;
  591. end;
  592. function tmodulebase.get_asmfilename : string;
  593. begin
  594. get_asmfilename:=outputpath^+newfilename^+target_info.asmext;
  595. end;
  596. destructor tmodulebase.destroy;
  597. begin
  598. if assigned(sourcefiles) then
  599. sourcefiles.free;
  600. sourcefiles:=nil;
  601. stringdispose(objfilename);
  602. stringdispose(newfilename);
  603. stringdispose(ppufilename);
  604. stringdispose(staticlibfilename);
  605. stringdispose(sharedlibfilename);
  606. stringdispose(exefilename);
  607. stringdispose(mapfilename);
  608. stringdispose(outputpath);
  609. stringdispose(path);
  610. stringdispose(modulename);
  611. stringdispose(realmodulename);
  612. stringdispose(mainsource);
  613. inherited destroy;
  614. end;
  615. end.
  616. {
  617. $Log$
  618. Revision 1.22 2003-04-28 16:18:16 peter
  619. * sharedlib is placed in exe outputdir
  620. Revision 1.21 2002/12/29 14:57:50 peter
  621. * unit loading changed to first register units and load them
  622. afterwards. This is needed to support uses xxx in yyy correctly
  623. * unit dependency check fixed
  624. Revision 1.20 2002/11/15 01:58:46 peter
  625. * merged changes from 1.0.7 up to 04-11
  626. - -V option for generating bug report tracing
  627. - more tracing for option parsing
  628. - errors for cdecl and high()
  629. - win32 import stabs
  630. - win32 records<=8 are returned in eax:edx (turned off by default)
  631. - heaptrc update
  632. - more info for temp management in .s file with EXTDEBUG
  633. Revision 1.19 2002/10/20 14:49:31 peter
  634. * store original source time in ppu so it can be compared instead of
  635. comparing with the ppu time
  636. Revision 1.18 2002/08/11 13:24:11 peter
  637. * saving of asmsymbols in ppu supported
  638. * asmsymbollist global is removed and moved into a new class
  639. tasmlibrarydata that will hold the info of a .a file which
  640. corresponds with a single module. Added librarydata to tmodule
  641. to keep the library info stored for the module. In the future the
  642. objectfiles will also be stored to the tasmlibrarydata class
  643. * all getlabel/newasmsymbol and friends are moved to the new class
  644. Revision 1.17 2002/07/26 21:15:37 florian
  645. * rewrote the system handling
  646. Revision 1.16 2002/07/01 18:46:22 peter
  647. * internal linker
  648. * reorganized aasm layer
  649. Revision 1.15 2002/05/18 13:34:07 peter
  650. * readded missing revisions
  651. Revision 1.14 2002/05/16 19:46:36 carl
  652. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  653. + try to fix temp allocation (still in ifdef)
  654. + generic constructor calls
  655. + start of tassembler / tmodulebase class cleanup
  656. Revision 1.13 2002/05/14 19:34:41 peter
  657. * removed old logs and updated copyright year
  658. Revision 1.12 2002/04/04 18:34:00 carl
  659. + added wdosx support (patch from Pavel)
  660. }