finput.pas 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771
  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. { Check if file exists, this will also check if it is
  390. a real file and not a directory }
  391. if not fileexists(filename) then
  392. begin
  393. result:=false;
  394. exit;
  395. end;
  396. { Open file }
  397. ofm:=filemode;
  398. filemode:=0;
  399. Assign(f,filename);
  400. {$I-}
  401. reset(f,1);
  402. {$I+}
  403. filemode:=ofm;
  404. fileopen:=(ioresult=0);
  405. end;
  406. function tdosinputfile.fileseek(pos: longint): boolean;
  407. begin
  408. {$I-}
  409. seek(f,Pos);
  410. {$I+}
  411. fileseek:=(ioresult=0);
  412. end;
  413. function tdosinputfile.fileread(var databuf; maxsize: longint): longint;
  414. var
  415. w : longint;
  416. begin
  417. blockread(f,databuf,maxsize,w);
  418. fileread:=w;
  419. end;
  420. function tdosinputfile.fileeof: boolean;
  421. begin
  422. fileeof:=eof(f);
  423. end;
  424. function tdosinputfile.fileclose: boolean;
  425. begin
  426. {$I-}
  427. system.close(f);
  428. {$I+}
  429. fileclose:=(ioresult=0);
  430. end;
  431. procedure tdosinputfile.filegettime;
  432. begin
  433. filetime:=getnamedfiletime(path^+name^);
  434. end;
  435. {****************************************************************************
  436. Tinputfilemanager
  437. ****************************************************************************}
  438. constructor tinputfilemanager.create;
  439. begin
  440. files:=nil;
  441. last_ref_index:=0;
  442. cacheindex:=0;
  443. cacheinputfile:=nil;
  444. end;
  445. destructor tinputfilemanager.destroy;
  446. var
  447. hp : tinputfile;
  448. begin
  449. hp:=files;
  450. while assigned(hp) do
  451. begin
  452. files:=files.ref_next;
  453. hp.free;
  454. hp:=files;
  455. end;
  456. last_ref_index:=0;
  457. end;
  458. procedure tinputfilemanager.register_file(f : tinputfile);
  459. begin
  460. { don't register macro's }
  461. if f.is_macro then
  462. exit;
  463. inc(last_ref_index);
  464. f.ref_next:=files;
  465. f.ref_index:=last_ref_index;
  466. files:=f;
  467. { update cache }
  468. cacheindex:=last_ref_index;
  469. cacheinputfile:=f;
  470. {$ifdef heaptrc}
  471. ppheap_register_file(f.name^,current_module.unit_index*100000+f.ref_index);
  472. {$endif heaptrc}
  473. end;
  474. { this procedure is necessary after loading the
  475. sources files from a PPU file PM }
  476. procedure tinputfilemanager.inverse_register_indexes;
  477. var
  478. f : tinputfile;
  479. begin
  480. f:=files;
  481. while assigned(f) do
  482. begin
  483. f.ref_index:=last_ref_index-f.ref_index+1;
  484. f:=f.ref_next;
  485. end;
  486. { reset cache }
  487. cacheindex:=0;
  488. cacheinputfile:=nil;
  489. end;
  490. function tinputfilemanager.get_file(l :longint) : tinputfile;
  491. var
  492. ff : tinputfile;
  493. begin
  494. { check cache }
  495. if (l=cacheindex) and assigned(cacheinputfile) then
  496. begin
  497. get_file:=cacheinputfile;
  498. exit;
  499. end;
  500. ff:=files;
  501. while assigned(ff) and (ff.ref_index<>l) do
  502. ff:=ff.ref_next;
  503. get_file:=ff;
  504. end;
  505. function tinputfilemanager.get_file_name(l :longint):string;
  506. var
  507. hp : tinputfile;
  508. begin
  509. hp:=get_file(l);
  510. if assigned(hp) then
  511. get_file_name:=hp.name^
  512. else
  513. get_file_name:='';
  514. end;
  515. function tinputfilemanager.get_file_path(l :longint):string;
  516. var
  517. hp : tinputfile;
  518. begin
  519. hp:=get_file(l);
  520. if assigned(hp) then
  521. get_file_path:=hp.path^
  522. else
  523. get_file_path:='';
  524. end;
  525. {****************************************************************************
  526. TModuleBase
  527. ****************************************************************************}
  528. procedure tmodulebase.setfilename(const fn:string;allowoutput:boolean);
  529. var
  530. p : dirstr;
  531. n : NameStr;
  532. e : ExtStr;
  533. begin
  534. stringdispose(objfilename);
  535. stringdispose(newfilename);
  536. stringdispose(ppufilename);
  537. stringdispose(staticlibfilename);
  538. stringdispose(sharedlibfilename);
  539. stringdispose(mapfilename);
  540. stringdispose(exefilename);
  541. stringdispose(outputpath);
  542. stringdispose(path);
  543. { Create names }
  544. fsplit(fn,p,n,e);
  545. n:=FixFileName(n);
  546. { set path }
  547. path:=stringdup(FixPath(p,false));
  548. { obj,asm,ppu names }
  549. p:=path^;
  550. if AllowOutput then
  551. begin
  552. if (OutputUnitDir<>'') then
  553. p:=OutputUnitDir
  554. else
  555. if (OutputExeDir<>'') then
  556. p:=OutputExeDir;
  557. end;
  558. outputpath:=stringdup(p);
  559. newfilename := stringdup(n);
  560. objfilename:=stringdup(p+n+target_info.objext);
  561. ppufilename:=stringdup(p+n+target_info.unitext);
  562. { lib and exe could be loaded with a file specified with -o }
  563. if AllowOutput and (OutputFile<>'') and (compile_level=1) then
  564. n:=OutputFile;
  565. staticlibfilename:=stringdup(p+target_info.staticlibprefix+n+target_info.staticlibext);
  566. { output dir of exe can be specified separatly }
  567. if AllowOutput and (OutputExeDir<>'') then
  568. p:=OutputExeDir
  569. else
  570. p:=path^;
  571. if target_info.system in [system_i386_WIN32,system_i386_wdosx] then
  572. sharedlibfilename:=stringdup(p+n+target_info.sharedlibext)
  573. else
  574. sharedlibfilename:=stringdup(p+target_info.sharedlibprefix+n+target_info.sharedlibext);
  575. exefilename:=stringdup(p+n+target_info.exeext);
  576. mapfilename:=stringdup(p+n+'.map');
  577. end;
  578. constructor tmodulebase.create(const s:string);
  579. begin
  580. modulename:=stringdup(Upper(s));
  581. realmodulename:=stringdup(s);
  582. mainsource:=nil;
  583. ppufilename:=nil;
  584. objfilename:=nil;
  585. newfilename:=nil;
  586. staticlibfilename:=nil;
  587. sharedlibfilename:=nil;
  588. exefilename:=nil;
  589. mapfilename:=nil;
  590. outputpath:=nil;
  591. path:=nil;
  592. { status }
  593. state:=ms_registered;
  594. { unit index }
  595. inc(global_unit_count);
  596. unit_index:=global_unit_count;
  597. { sources }
  598. sourcefiles:=TInputFileManager.Create;
  599. end;
  600. function tmodulebase.get_asmfilename : string;
  601. begin
  602. get_asmfilename:=outputpath^+newfilename^+target_info.asmext;
  603. end;
  604. destructor tmodulebase.destroy;
  605. begin
  606. if assigned(sourcefiles) then
  607. sourcefiles.free;
  608. sourcefiles:=nil;
  609. stringdispose(objfilename);
  610. stringdispose(newfilename);
  611. stringdispose(ppufilename);
  612. stringdispose(staticlibfilename);
  613. stringdispose(sharedlibfilename);
  614. stringdispose(exefilename);
  615. stringdispose(mapfilename);
  616. stringdispose(outputpath);
  617. stringdispose(path);
  618. stringdispose(modulename);
  619. stringdispose(realmodulename);
  620. stringdispose(mainsource);
  621. inherited destroy;
  622. end;
  623. end.
  624. {
  625. $Log$
  626. Revision 1.23 2003-12-27 22:27:24 peter
  627. * check with fileexists() before opening a file
  628. Revision 1.22 2003/04/28 16:18:16 peter
  629. * sharedlib is placed in exe outputdir
  630. Revision 1.21 2002/12/29 14:57:50 peter
  631. * unit loading changed to first register units and load them
  632. afterwards. This is needed to support uses xxx in yyy correctly
  633. * unit dependency check fixed
  634. Revision 1.20 2002/11/15 01:58:46 peter
  635. * merged changes from 1.0.7 up to 04-11
  636. - -V option for generating bug report tracing
  637. - more tracing for option parsing
  638. - errors for cdecl and high()
  639. - win32 import stabs
  640. - win32 records<=8 are returned in eax:edx (turned off by default)
  641. - heaptrc update
  642. - more info for temp management in .s file with EXTDEBUG
  643. Revision 1.19 2002/10/20 14:49:31 peter
  644. * store original source time in ppu so it can be compared instead of
  645. comparing with the ppu time
  646. Revision 1.18 2002/08/11 13:24:11 peter
  647. * saving of asmsymbols in ppu supported
  648. * asmsymbollist global is removed and moved into a new class
  649. tasmlibrarydata that will hold the info of a .a file which
  650. corresponds with a single module. Added librarydata to tmodule
  651. to keep the library info stored for the module. In the future the
  652. objectfiles will also be stored to the tasmlibrarydata class
  653. * all getlabel/newasmsymbol and friends are moved to the new class
  654. Revision 1.17 2002/07/26 21:15:37 florian
  655. * rewrote the system handling
  656. Revision 1.16 2002/07/01 18:46:22 peter
  657. * internal linker
  658. * reorganized aasm layer
  659. Revision 1.15 2002/05/18 13:34:07 peter
  660. * readded missing revisions
  661. Revision 1.14 2002/05/16 19:46:36 carl
  662. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  663. + try to fix temp allocation (still in ifdef)
  664. + generic constructor calls
  665. + start of tassembler / tmodulebase class cleanup
  666. Revision 1.13 2002/05/14 19:34:41 peter
  667. * removed old logs and updated copyright year
  668. Revision 1.12 2002/04/04 18:34:00 carl
  669. + added wdosx support (patch from Pavel)
  670. }