| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740 | {    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,cclasses;    const       InputFileBufSize=32*1024;       linebufincrease=512;    type       tlongintarr = array[0..1000000] of longint;       plongintarr = ^tlongintarr;       tinputfile = class         path,name : pstring;       { path and filename }         next      : tinputfile;    { next file for reading }         is_macro,         endoffile,                 { still bytes left to read }         closed       : boolean;    { is the file closed }         buf          : pchar;      { 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    : plongintarr;  { line buffer to retrieve lines }         maxlinebuf : longint;         ref_index  : longint;      { to handle the browser refs }         ref_next   : tinputfile;         constructor create(const fn:string);         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: string): 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;       tdosinputfile = class(tinputfile)       protected         function fileopen(const filename: string): 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            : file;       { current file handle }       end;       tinputfilemanager = class          files : tinputfile;          last_ref_index : longint;          cacheindex : longint;          cacheinputfile : tinputfile;          constructor create;          destructor destroy;override;          procedure register_file(f : tinputfile);          procedure inverse_register_indexes;          function  get_file(l:longint) : tinputfile;          function  get_file_name(l :longint):string;          function  get_file_path(l :longint):string;       end;{****************************************************************************                                TModuleBase ****************************************************************************}     type        tmodulestate = (ms_unknown,          ms_registered,          ms_load,ms_compile,          ms_second_load,ms_second_compile,          ms_compiled        );     const        ModuleStateStr : array[TModuleState] of string[20] = (          'Unknown',          'Registered',          'Load','Compile',          'Second_Load','Second_Compile',          'Compiled'        );     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 }          paramfn,                  { original filename }          path,                     { path where the module is find/created }          outputpath,               { path where the .s / .o / exe are created }          modulename,               { name of the module in uppercase }          realmodulename,           { name of the module in the orignal case }          objfilename,              { fullname of the objectfile }          newfilename,              { fullname of the assemblerfile }          ppufilename,              { fullname of the ppufile }          staticlibfilename,        { fullname of the static libraryfile }          sharedlibfilename,        { fullname of the shared libraryfile }          mapfilename,              { fullname of the mapfile }          exefilename,              { fullname of the exefile }          mainsource   : pstring;   { name of the main sourcefile }          constructor create(const s:string);          destructor destroy;override;          procedure setfilename(const fn:string;allowoutput:boolean);          function get_asmfilename : string;       end;implementationuses{$IFDEF USE_SYSUTILS}  SysUtils,  GlobType,{$ELSE USE_SYSUTILS}  dos,{$ENDIF USE_SYSUTILS}{$ifdef heaptrc}  fmodule,  ppheap,{$endif heaptrc}  globals,systems  ;{****************************************************************************                                  TINPUTFILE ****************************************************************************}    constructor tinputfile.create(const fn:string);{$IFDEF USE_SYSUTILS}{$ELSE USE_SYSUTILS}      var        p:dirstr;        n:namestr;        e:extstr;{$ENDIF USE_SYSUTILS}      begin{$IFDEF USE_SYSUTILS}        name:=stringdup(SplitFileName(fn));        path:=stringdup(SplitPath(fn));{$ELSE USE_SYSUTILS}        FSplit(fn,p,n,e);        name:=stringdup(n+e);        path:=stringdup(p);{$ENDIF USE_SYSUTILS}        next:=nil;        filetime:=-1;      { file info }        is_macro:=false;        endoffile:=false;        closed:=true;        buf:=nil;        bufstart:=0;        bufsize:=0;        maxbufsize:=InputFileBufSize;      { save fields }        saveinputpointer:=nil;        saveline_no:=0;        savelastlinepos:=0;      { indexing refs }        ref_next:=nil;        ref_index:=0;      { line buffer }        linebuf:=nil;        maxlinebuf:=0;      end;    destructor tinputfile.destroy;      begin        if not closed then         close;        stringdispose(path);        stringdispose(name);      { free memory }        if assigned(linebuf) then         freemem(linebuf,maxlinebuf shl 2);      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^,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;        Getmem(buf,MaxBufsize);        bufstart:=0;        bufsize:=0;        open:=true;      end;    procedure tinputfile.close;      begin        if is_macro then         begin           if assigned(buf) then            begin              Freemem(buf,maxbufsize);              buf:=nil;            end;           closed:=true;           exit;         end;        if not closed then         begin           fileclose;           closed:=true;         end;        if assigned(buf) then          begin             Freemem(buf,maxbufsize);             buf:=nil;          end;        bufstart:=0;      end;    procedure tinputfile.tempclose;      begin        if is_macro then         exit;        if not closed then         begin           fileclose;           if assigned(buf) then            begin              Freemem(buf,maxbufsize);              buf:=nil;            end;           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 }        Getmem(buf,maxbufsize);      { restore state }        fileseek(BufStart);        bufsize:=0;        readbuf;        tempopen:=true;      end;    procedure tinputfile.setmacro(p:pchar;len:longint);      begin      { create new buffer }        getmem(buf,len+1);        move(p^,buf^,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);      var        oldlinebuf  : plongintarr;      begin        if line<1 then         exit;        while (line>=maxlinebuf) do         begin           oldlinebuf:=linebuf;         { create new linebuf and move old info }           getmem(linebuf,(maxlinebuf+linebufincrease) shl 2);           if assigned(oldlinebuf) then            begin              move(oldlinebuf^,linebuf^,maxlinebuf shl 2);              freemem(oldlinebuf,maxlinebuf shl 2);            end;           fillchar(linebuf^[maxlinebuf],linebufincrease shl 2,0);           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;                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: string): boolean;      var        ofm : byte;      begin        { Check if file exists, this will also check if it is          a real file and not a directory }        if not fileexists(filename) then          begin            result:=false;            exit;          end;        { Open file }        ofm:=filemode;        filemode:=0;        Assign(f,filename);        {$I-}         reset(f,1);        {$I+}        filemode:=ofm;        fileopen:=(ioresult=0);      end;    function tdosinputfile.fileseek(pos: longint): boolean;      begin        {$I-}         seek(f,Pos);        {$I+}        fileseek:=(ioresult=0);      end;    function tdosinputfile.fileread(var databuf; maxsize: longint): longint;      var        w : longint;      begin        blockread(f,databuf,maxsize,w);        fileread:=w;      end;    function tdosinputfile.fileeof: boolean;      begin        fileeof:=eof(f);      end;    function tdosinputfile.fileclose: boolean;      begin        {$I-}         system.close(f);        {$I+}        fileclose:=(ioresult=0);      end;    procedure tdosinputfile.filegettime;      begin        filetime:=getnamedfiletime(path^+name^);      end;{****************************************************************************                                Tinputfilemanager ****************************************************************************}    constructor tinputfilemanager.create;      begin         files:=nil;         last_ref_index:=0;         cacheindex:=0;         cacheinputfile:=nil;      end;    destructor tinputfilemanager.destroy;      var         hp : tinputfile;      begin         hp:=files;         while assigned(hp) do          begin            files:=files.ref_next;            hp.free;            hp:=files;          end;         last_ref_index:=0;      end;    procedure tinputfilemanager.register_file(f : tinputfile);      begin         { don't register macro's }         if f.is_macro then          exit;         inc(last_ref_index);         f.ref_next:=files;         f.ref_index:=last_ref_index;         files:=f;         { update cache }         cacheindex:=last_ref_index;         cacheinputfile:=f;{$ifdef heaptrc}         ppheap_register_file(f.name^,current_module.unit_index*100000+f.ref_index);{$endif heaptrc}      end;   { this procedure is necessary after loading the     sources files from a PPU file  PM }   procedure tinputfilemanager.inverse_register_indexes;     var        f : tinputfile;     begin        f:=files;        while assigned(f) do          begin             f.ref_index:=last_ref_index-f.ref_index+1;             f:=f.ref_next;          end;        { reset cache }        cacheindex:=0;        cacheinputfile:=nil;     end;   function tinputfilemanager.get_file(l :longint) : tinputfile;     var        ff : tinputfile;     begin       { check cache }       if (l=cacheindex) and assigned(cacheinputfile) then        begin          get_file:=cacheinputfile;          exit;        end;       ff:=files;       while assigned(ff) and (ff.ref_index<>l) do         ff:=ff.ref_next;       get_file:=ff;     end;   function tinputfilemanager.get_file_name(l :longint):string;     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):string;     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:string;allowoutput:boolean);      var        p : dirstr;        n : NameStr;        e : ExtStr;        prefix,        suffix,        extension : NameStr;      begin         stringdispose(objfilename);         stringdispose(newfilename);         stringdispose(ppufilename);         stringdispose(staticlibfilename);         stringdispose(sharedlibfilename);         stringdispose(mapfilename);         stringdispose(exefilename);         stringdispose(outputpath);         stringdispose(path);         { Create names }         paramfn := stringdup(fn);         paramallowoutput := allowoutput;{$IFDEF USE_SYSUTILS}         p := SplitPath(fn);         n := SplitName(fn);         e := SplitExtension(fn);{$ELSE USE_SYSUTILS}         fsplit(fn,p,n,e);{$ENDIF USE_SYSUTILS}         n:=FixFileName(n);         { set path }         path:=stringdup(FixPath(p,false));         { obj,asm,ppu names }         p:=path^;         if AllowOutput then          begin            if (OutputUnitDir<>'') then             p:=OutputUnitDir            else             if (OutputExeDir<>'') then              p:=OutputExeDir;          end;         outputpath:=stringdup(p);         newfilename := stringdup(n);         objfilename:=stringdup(p+n+target_info.objext);         ppufilename:=stringdup(p+n+target_info.unitext);         { lib and exe could be loaded with a file specified with -o }         prefix := target_info.sharedlibprefix;         suffix := '';         extension := target_info.sharedlibext;         if AllowOutput and (compile_level=1) then         begin           if OutputFile <> '' then n:=OutputFile;           if Assigned(OutputPrefix) then prefix := OutputPrefix^;           if Assigned(OutputSuffix) then suffix := OutputSuffix^;           if OutputExtension <> '' then extension := OutputExtension;         end;         staticlibfilename:=stringdup(p+target_info.staticlibprefix+n+target_info.staticlibext);         { output dir of exe can be specified separatly }         if AllowOutput and (OutputExeDir<>'') then          p:=OutputExeDir         else          p:=path^;         sharedlibfilename:=stringdup(p+prefix+n+suffix+extension);         exefilename:=stringdup(p+n+target_info.exeext);         mapfilename:=stringdup(p+n+'.map');      end;    constructor tmodulebase.create(const s:string);      begin        modulename:=stringdup(Upper(s));        realmodulename:=stringdup(s);        mainsource:=nil;        ppufilename:=nil;        objfilename:=nil;        newfilename:=nil;        staticlibfilename:=nil;        sharedlibfilename:=nil;        exefilename:=nil;        mapfilename:=nil;        outputpath:=nil;        path:=nil;        { status }        state:=ms_registered;        { unit index }        inc(global_unit_count);        unit_index:=global_unit_count;        { sources }        sourcefiles:=TInputFileManager.Create;      end;    function tmodulebase.get_asmfilename : string;     begin         get_asmfilename:=outputpath^+newfilename^+target_info.asmext;     end;    destructor tmodulebase.destroy;      begin        if assigned(sourcefiles) then         sourcefiles.free;        sourcefiles:=nil;        stringdispose(objfilename);        stringdispose(newfilename);        stringdispose(ppufilename);        stringdispose(staticlibfilename);        stringdispose(sharedlibfilename);        stringdispose(exefilename);        stringdispose(mapfilename);        stringdispose(outputpath);        stringdispose(path);        stringdispose(modulename);        stringdispose(realmodulename);        stringdispose(mainsource);        inherited destroy;      end;end.
 |