finput.pas 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757
  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. if target_info.system in [system_i386_WIN32,system_i386_wdosx] then
  559. sharedlibfilename:=stringdup(p+n+target_info.sharedlibext)
  560. else
  561. sharedlibfilename:=stringdup(p+target_info.sharedlibprefix+n+target_info.sharedlibext);
  562. { output dir of exe can be specified separatly }
  563. if AllowOutput and (OutputExeDir<>'') then
  564. p:=OutputExeDir
  565. else
  566. p:=path^;
  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.21 2002-12-29 14:57:50 peter
  619. * unit loading changed to first register units and load them
  620. afterwards. This is needed to support uses xxx in yyy correctly
  621. * unit dependency check fixed
  622. Revision 1.20 2002/11/15 01:58:46 peter
  623. * merged changes from 1.0.7 up to 04-11
  624. - -V option for generating bug report tracing
  625. - more tracing for option parsing
  626. - errors for cdecl and high()
  627. - win32 import stabs
  628. - win32 records<=8 are returned in eax:edx (turned off by default)
  629. - heaptrc update
  630. - more info for temp management in .s file with EXTDEBUG
  631. Revision 1.19 2002/10/20 14:49:31 peter
  632. * store original source time in ppu so it can be compared instead of
  633. comparing with the ppu time
  634. Revision 1.18 2002/08/11 13:24:11 peter
  635. * saving of asmsymbols in ppu supported
  636. * asmsymbollist global is removed and moved into a new class
  637. tasmlibrarydata that will hold the info of a .a file which
  638. corresponds with a single module. Added librarydata to tmodule
  639. to keep the library info stored for the module. In the future the
  640. objectfiles will also be stored to the tasmlibrarydata class
  641. * all getlabel/newasmsymbol and friends are moved to the new class
  642. Revision 1.17 2002/07/26 21:15:37 florian
  643. * rewrote the system handling
  644. Revision 1.16 2002/07/01 18:46:22 peter
  645. * internal linker
  646. * reorganized aasm layer
  647. Revision 1.15 2002/05/18 13:34:07 peter
  648. * readded missing revisions
  649. Revision 1.14 2002/05/16 19:46:36 carl
  650. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  651. + try to fix temp allocation (still in ifdef)
  652. + generic constructor calls
  653. + start of tassembler / tmodulebase class cleanup
  654. Revision 1.13 2002/05/14 19:34:41 peter
  655. * removed old logs and updated copyright year
  656. Revision 1.12 2002/04/04 18:34:00 carl
  657. + added wdosx support (patch from Pavel)
  658. }