123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702 |
- {
- Copyright (c) 1998-2002 by Florian Klaempfl
- This unit implements an extended file management
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- ****************************************************************************
- }
- unit finput;
- {$i fpcdefs.inc}
- interface
- uses
- cutils,globtype,cclasses,cstreams;
- const
- InputFileBufSize=32*1024+1;
- linebufincrease=512;
- type
- tlongintarr = array of longint;
- tinputfile = class
- path,name : TPathStr; { path and filename }
- inc_path : TPathStr; { path if file was included with $I directive }
- next : tinputfile; { next file for reading }
- buf : TAnsiCharDynArray; { buffer }
- bufstart, { buffer start position in the file }
- bufsize, { amount of bytes in the buffer }
- maxbufsize : longint; { size in memory for the buffer }
- saveinputpointer : pchar; { save fields for scanner variables }
- savelastlinepos,
- saveline_no : longint;
- linebuf : tlongintarr; { line buffer to retrieve lines }
- maxlinebuf : longint;
- ref_index : longint;
- is_macro,
- endoffile, { still bytes left to read }
- closed : boolean; { is the file closed }
- { this file represents an internally generated macro. Enables
- certain escape sequences }
- internally_generated_macro: boolean;
- constructor create(const fn:TPathStr);
- destructor destroy;override;
- procedure setpos(l:longint);
- procedure seekbuf(fpos:longint);
- procedure readbuf;
- function open:boolean;
- procedure close;
- procedure tempclose;
- function tempopen:boolean;
- procedure setmacro(p:pchar;len:longint);
- procedure setline(line,linepos:longint);
- function getlinestr(l:longint):string;
- function getfiletime:longint;
- protected
- filetime : longint;
- function fileopen(const filename: TPathStr): boolean; virtual; abstract;
- function fileseek(pos: longint): boolean; virtual; abstract;
- function fileread(var databuf; maxsize: longint): longint; virtual; abstract;
- function fileeof: boolean; virtual; abstract;
- function fileclose: boolean; virtual; abstract;
- procedure filegettime; virtual; abstract;
- end;
- ptinputfile = ^tinputfile;
- tdosinputfile = class(tinputfile)
- protected
- function fileopen(const filename: TPathStr): boolean; override;
- function fileseek(pos: longint): boolean; override;
- function fileread(var databuf; maxsize: longint): longint; override;
- function fileeof: boolean; override;
- function fileclose: boolean; override;
- procedure filegettime; override;
- private
- f : TCCustomFileStream; { current file handle }
- end;
- tinputfilemanager = class
- files : ptinputfile;
- nfiles,afiles : sizeint;
- constructor create;
- destructor destroy;override;
- procedure register_file(f : tinputfile);
- function get_file(l:longint) : tinputfile;
- function get_file_name(l :longint):TPathStr;
- function get_file_path(l :longint):TPathStr;
- end;
- {****************************************************************************
- TModuleBase
- ****************************************************************************}
- type
- tmodulestate = (ms_unknown,
- ms_registered,
- ms_load,
- ms_compile,
- ms_compiling_waitintf,
- ms_compiling_waitimpl,
- ms_compiling_waitfinish,
- ms_compiling_wait,
- ms_compiled,
- ms_processed,
- ms_moduleerror
- );
- tmodulestates = set of tmodulestate;
- const
- ModuleStateStr : array[TModuleState] of string[32] = (
- 'Unknown',
- 'Registered',
- 'Load',
- 'Compile',
- 'Compiling_Waiting_interface',
- 'Compiling_Waiting_implementation',
- 'Compiling_Waiting_finish',
- 'Compiling_Waiting',
- 'Compiled',
- 'Processed',
- 'Error'
- );
- type
- tmodulebase = class(TLinkedListItem)
- { index }
- unit_index : longint; { global counter for browser }
- { status }
- state : tmodulestate;
- { sources }
- sourcefiles : tinputfilemanager;
- { paths and filenames }
- paramallowoutput : boolean; { original allowoutput parameter }
- modulename, { name of the module in uppercase }
- realmodulename: pshortstring; { name of the module in the orignal case }
- paramfn, { original filename }
- mainsource, { name of the main sourcefile }
- objfilename, { fullname of the objectfile }
- asmfilename, { fullname of the assemblerfile }
- ppufilename, { fullname of the ppufile }
- {$ifdef DEBUG_NODE_XML}
- ppxfilename, { fullname of the intermediate node XML file }
- {$endif DEBUG_NODE_XML}
- importlibfilename, { fullname of the import libraryfile }
- staticlibfilename, { fullname of the static libraryfile }
- sharedlibfilename, { fullname of the shared libraryfile }
- exportfilename, { fullname of the export file }
- mapfilename, { fullname of the mapfile }
- exefilename, { fullname of the exefile }
- dbgfilename, { fullname of the debug info file }
- path, { path where the module is find/created }
- outputpath : TPathStr; { path where the .s / .o / exe are created }
- {$ifdef DEBUG_NODE_XML}
- ppxfilefail: Boolean; { If the ppxfile could not be accessed, flag it }
- {$endif DEBUG_NODE_XML}
- is_initial : boolean; { is this the initial module, i.e. the one specified on the command-line ?}
- constructor create(const s:string);
- destructor destroy;override;
- procedure setfilename(const fn:TPathStr;allowoutput:boolean);
- end;
- Function GetNamedFileTime (Const F : TPathStr) : Longint;
- implementation
- uses
- SysUtils,
- Comphook,
- {$ifndef GENERIC_CPU}
- {$ifdef heaptrc}
- fmodule,
- ppheap,
- {$endif heaptrc}
- {$endif not GENERIC_CPU}
- cfileutl,
- Globals,Systems
- ;
- {****************************************************************************
- Utils
- ****************************************************************************}
- Function GetNamedFileTime (Const F : TPathStr) : Longint;
- begin
- GetNamedFileTime:=do_getnamedfiletime(F);
- end;
- {****************************************************************************
- TINPUTFILE
- ****************************************************************************}
- constructor tinputfile.create(const fn:TPathStr);
- begin
- name:=ExtractFileName(fn);
- path:=ExtractFilePath(fn);
- inc_path:='';
- next:=nil;
- filetime:=-1;
- buf:=nil;
- bufstart:=0;
- bufsize:=0;
- maxbufsize:=InputFileBufSize;
- { save fields }
- saveinputpointer:=nil;
- saveline_no:=0;
- savelastlinepos:=0;
- { indexing refs }
- ref_index:=0;
- { line buffer }
- linebuf:=nil;
- maxlinebuf:=0;
- { file info }
- is_macro:=false;
- endoffile:=false;
- closed:=true;
- internally_generated_macro:=false;
- end;
- destructor tinputfile.destroy;
- begin
- if not closed then
- close;
- linebuf:=Nil;
- end;
- procedure tinputfile.setpos(l:longint);
- begin
- bufstart:=l;
- end;
- procedure tinputfile.seekbuf(fpos:longint);
- begin
- if closed then
- exit;
- fileseek(fpos);
- bufstart:=fpos;
- bufsize:=0;
- end;
- procedure tinputfile.readbuf;
- begin
- if is_macro then
- endoffile:=true;
- if closed then
- exit;
- inc(bufstart,bufsize);
- bufsize:=fileread(buf[0],maxbufsize-1);
- buf[bufsize]:=#0;
- endoffile:=fileeof;
- end;
- function tinputfile.open:boolean;
- begin
- open:=false;
- if not closed then
- Close;
- if not fileopen(path+name) then
- exit;
- { file }
- endoffile:=false;
- closed:=false;
- SetLength(buf,MaxBufsize);
- buf[0]:=#0;
- bufstart:=0;
- bufsize:=0;
- open:=true;
- end;
- procedure tinputfile.close;
- begin
- if is_macro then
- begin
- buf:=nil;
- name:='';
- path:='';
- closed:=true;
- exit;
- end;
- if not closed then
- begin
- fileclose;
- closed:=true;
- end;
- if assigned(buf) then
- buf:=nil;
- bufstart:=0;
- end;
- procedure tinputfile.tempclose;
- begin
- if is_macro then
- exit;
- if not closed then
- begin
- fileclose;
- buf:=nil;
- closed:=true;
- end;
- end;
- function tinputfile.tempopen:boolean;
- begin
- tempopen:=false;
- if is_macro then
- begin
- { seek buffer postion to bufstart }
- if bufstart>0 then
- begin
- move(buf[bufstart],buf[0],bufsize-bufstart+1);
- bufstart:=0;
- end;
- tempopen:=true;
- exit;
- end;
- if not closed then
- exit;
- if not fileopen(path+name) then
- exit;
- closed:=false;
- { get new mem }
- SetLength(buf,maxbufsize);
- { restore state }
- fileseek(BufStart);
- bufsize:=0;
- readbuf;
- tempopen:=true;
- end;
- procedure tinputfile.setmacro(p:pchar;len:longint);
- begin
- { create new buffer }
- SetLength(buf,len+1);
- if len>0 then
- move(p^,buf[0],len);
- buf[len]:=#0;
- { reset }
- bufstart:=0;
- bufsize:=len;
- maxbufsize:=len+1;
- is_macro:=true;
- endoffile:=true;
- closed:=true;
- end;
- procedure tinputfile.setline(line,linepos:longint);
- begin
- if line<1 then
- exit;
- while (line>=maxlinebuf) do
- begin
- { create new linebuf and move old info }
- SetLength(linebuf,(maxlinebuf+linebufincrease));
- inc(maxlinebuf,linebufincrease);
- end;
- linebuf[line]:=linepos;
- end;
- function tinputfile.getlinestr(l:longint):string;
- var
- c : char;
- i,
- fpos : longint;
- p : pchar;
- begin
- getlinestr:='';
- if l<maxlinebuf then
- begin
- fpos:=linebuf[l];
- { fpos is set negativ if the line was already written }
- { but we still know the correct value }
- if fpos<0 then
- fpos:=-fpos+1;
- if closed then
- open;
- { in current buf ? }
- if (fpos<bufstart) or (fpos>bufstart+bufsize) then
- begin
- seekbuf(fpos);
- readbuf;
- end;
- { the begin is in the buf now simply read until #13,#10 }
- i:=0;
- p:=@buf[fpos-bufstart];
- repeat
- c:=p^;
- if c=#0 then
- begin
- if endoffile then
- break;
- readbuf;
- p:=@buf[0];
- c:=p^;
- end;
- if c in [#10,#13] then
- break;
- inc(i);
- getlinestr[i]:=c;
- inc(p);
- until (i=255);
- getlinestr[0]:=chr(i);
- end;
- end;
- function tinputfile.getfiletime:longint;
- begin
- if filetime=-1 then
- filegettime;
- getfiletime:=filetime;
- end;
- {****************************************************************************
- TDOSINPUTFILE
- ****************************************************************************}
- function tdosinputfile.fileopen(const filename: TPathStr): boolean;
- begin
- { Check if file exists, this will also check if it is
- a real file and not a directory }
- if not fileexists(filename,false) then
- begin
- result:=false;
- exit;
- end;
- { Open file }
- fileopen:=false;
- try
- f:=CFileStreamClass.Create(filename,fmOpenRead);
- fileopen:=CStreamError=0;
- except
- end;
- end;
- function tdosinputfile.fileseek(pos: longint): boolean;
- begin
- fileseek:=false;
- try
- f.position:=Pos;
- fileseek:=true;
- except
- end;
- end;
- function tdosinputfile.fileread(var databuf; maxsize: longint): longint;
- begin
- fileread:=f.Read(databuf,maxsize);
- end;
- function tdosinputfile.fileeof: boolean;
- begin
- fileeof:=f.eof();
- end;
- function tdosinputfile.fileclose: boolean;
- begin
- fileclose:=false;
- try
- f.Free;
- fileclose:=true;
- except
- end;
- end;
- procedure tdosinputfile.filegettime;
- begin
- filetime:=getnamedfiletime(path+name);
- end;
- {****************************************************************************
- Tinputfilemanager
- ****************************************************************************}
- constructor tinputfilemanager.create;
- begin
- end;
- destructor tinputfilemanager.destroy;
- var
- ifile : SizeInt;
- begin
- for ifile:=0 to nfiles-1 do
- files[ifile].free;
- FreeMem(files);
- end;
- procedure tinputfilemanager.register_file(f : tinputfile);
- begin
- { don't register macro's }
- if f.is_macro then
- exit;
- if nfiles=afiles then
- begin
- afiles:=afiles+4+SizeUint(afiles) div 4+SizeUint(afiles) div 8;
- ReallocMem(files,afiles*sizeof(files[0]));
- end;
- f.ref_index:=1+nfiles;
- files[nfiles]:=f;
- inc(nfiles);
- {$ifndef GENERIC_CPU}
- {$ifdef heaptrc}
- ppheap_register_file(f.path+f.name,current_module.unit_index*100000+f.ref_index);
- {$endif heaptrc}
- {$endif not GENERIC_CPU}
- end;
- function tinputfilemanager.get_file(l :longint) : tinputfile;
- begin
- if not ((l>=1) and (l<=nfiles)) then
- exit(nil);
- result:=files[l-1];
- end;
- function tinputfilemanager.get_file_name(l :longint):TPathStr;
- var
- hp : tinputfile;
- begin
- hp:=get_file(l);
- if assigned(hp) then
- get_file_name:=hp.name
- else
- get_file_name:='';
- end;
- function tinputfilemanager.get_file_path(l :longint):TPathStr;
- var
- hp : tinputfile;
- begin
- hp:=get_file(l);
- if assigned(hp) then
- get_file_path:=hp.path
- else
- get_file_path:='';
- end;
- {****************************************************************************
- TModuleBase
- ****************************************************************************}
- procedure tmodulebase.setfilename(const fn:TPathStr;allowoutput:boolean);
- var
- p, n,
- prefix,
- suffix : TPathStr;
- begin
- { Create names }
- paramfn := fn;
- paramallowoutput := allowoutput;
- p := FixPath(ExtractFilePath(fn),false);
- n := FixFileName(ChangeFileExt(ExtractFileName(fn),''));
- { set path }
- path:=p;
- { obj,asm,ppu names }
- if AllowOutput then
- begin
- if (OutputUnitDir<>'') then
- p:=OutputUnitDir
- else
- if (OutputExeDir<>'') then
- p:=OutputExeDir;
- end;
- outputpath:=p;
- asmfilename:=p+n+target_info.asmext;
- objfilename:=p+n+target_info.objext;
- ppufilename:=p+n+target_info.unitext;
- {$ifdef DEBUG_NODE_XML}
- ppxfilename:=p+n+'-node-dump.xml';
- {$endif DEBUG_NODE_XML}
- importlibfilename:=p+target_info.importlibprefix+n+target_info.importlibext;
- staticlibfilename:=p+target_info.staticlibprefix+n+target_info.staticlibext;
- exportfilename:=p+'exp'+n+target_info.objext;
- { output dir of exe can be specified separatly }
- if AllowOutput and (OutputExeDir<>'') then
- p:=OutputExeDir
- else
- p:=path;
- { lib and exe could be loaded with a file specified with -o }
- if AllowOutput and is_initial and
- (OutputFileName<>'')then
- begin
- exefilename:=p+OutputFileName;
- sharedlibfilename:=p+OutputFileName;
- n:=ChangeFileExt(OutputFileName,''); { for mapfilename and dbgfilename }
- end
- else
- begin
- exefilename:=p+n+target_info.exeext;
- if Assigned(OutputPrefix) then
- prefix := OutputPrefix^
- else
- prefix := target_info.sharedlibprefix;
- if Assigned(OutputSuffix) then
- suffix := OutputSuffix^
- else
- suffix := '';
- sharedlibfilename:=p+prefix+n+suffix+target_info.sharedlibext;
- end;
- mapfilename:=p+n+'.map';
- dbgfilename:=p+n+'.dbg';
- end;
- constructor tmodulebase.create(const s:string);
- begin
- modulename:=stringdup(Upper(s));
- realmodulename:=stringdup(s);
- mainsource:='';
- ppufilename:='';
- {$ifdef DEBUG_NODE_XML}
- ppxfilename:='';
- {$endif DEBUG_NODE_XML}
- objfilename:='';
- asmfilename:='';
- importlibfilename:='';
- staticlibfilename:='';
- sharedlibfilename:='';
- exefilename:='';
- dbgfilename:='';
- mapfilename:='';
- outputpath:='';
- paramfn:='';
- path:='';
- {$ifdef DEBUG_NODE_XML}
- { Setting ppxfilefail to true will stop it from being written to if it
- was never initialised, which happens if a module doesn't need
- recompiling. }
- ppxfilefail := True;
- {$endif DEBUG_NODE_XML}
- { status }
- state:=ms_registered;
- { unit index }
- inc(global_unit_count);
- unit_index:=global_unit_count;
- { sources }
- sourcefiles:=TInputFileManager.Create;
- end;
- destructor tmodulebase.destroy;
- begin
- if assigned(sourcefiles) then
- sourcefiles.free;
- sourcefiles:=nil;
- stringdispose(modulename);
- stringdispose(realmodulename);
- inherited destroy;
- end;
- end.
|