finput.pas 20 KB

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