finput.pas 20 KB

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