| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873 | {    Copyright (c) 1998-2002 by Peter Vreman    This unit handles the verbose 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 verbose;{$i fpcdefs.inc}interface    uses{$IFNDEF MACOS_USE_FAKE_SYSUTILS}      sysutils,{$ENDIF}      cutils,      globals,finput,      cmsgs;{$ifndef EXTERN_MSG}  {$i msgtxt.inc}{$endif}{$i msgidx.inc}    Const      { Levels }      V_None         = $0;      V_Fatal        = $1;      V_Error        = $2;      V_Normal       = $4; { doesn't show a text like Error: }      V_Warning      = $8;      V_Note         = $10;      V_Hint         = $20;      V_LineInfoMask = $fff;      { From here by default no line info }      V_Info         = $1000;      V_Status       = $2000;      V_Used         = $4000;      V_Tried        = $8000;      V_Conditional  = $10000;      V_Debug        = $20000;      V_Executable   = $40000;      V_LevelMask    = $fffffff;      V_All          = V_LevelMask;      V_Default      = V_Fatal + V_Error + V_Normal;      { Flags }      V_LineInfo     = $10000000;    var      msg : pmessage;    const      msgfilename : string = '';    procedure SetRedirectFile(const fn:string);    function  SetVerbosity(const s:string):boolean;    procedure PrepareReport;    function  CheckVerbosity(v:longint):boolean;    procedure SetCompileModule(p:tmodulebase);    procedure ShowStatus;    function  ErrorCount:longint;    procedure SetErrorFlags(const s:string);    procedure GenerateError;    procedure Internalerror(i:longint);    procedure Comment(l:longint;s:string);    function  MessagePchar(w:longint):pchar;    procedure Message(w:longint);    procedure Message1(w:longint;const s1:string);    procedure Message2(w:longint;const s1,s2:string);    procedure Message3(w:longint;const s1,s2,s3:string);    procedure Message4(w:longint;const s1,s2,s3,s4:string);    procedure MessagePos(const pos:tfileposinfo;w:longint);    procedure MessagePos1(const pos:tfileposinfo;w:longint;const s1:string);    procedure MessagePos2(const pos:tfileposinfo;w:longint;const s1,s2:string);    procedure MessagePos3(const pos:tfileposinfo;w:longint;const s1,s2,s3:string);    procedure MessagePos4(const pos:tfileposinfo;w:longint;const s1,s2,s3,s4:string);    { message calls with codegenerror support }    procedure cgmessage(t : longint);    procedure cgmessage1(t : longint;const s : string);    procedure cgmessage2(t : longint;const s1,s2 : string);    procedure cgmessage3(t : longint;const s1,s2,s3 : string);    procedure CGMessagePos(const pos:tfileposinfo;t:longint);    procedure CGMessagePos1(const pos:tfileposinfo;t:longint;const s1:string);    procedure CGMessagePos2(const pos:tfileposinfo;t:longint;const s1,s2:string);    procedure CGMessagePos3(const pos:tfileposinfo;t:longint;const s1,s2,s3:string);    procedure InitVerbose;    procedure DoneVerbose;implementation    uses      comphook;var  compiling_module : tmodulebase;{****************************************************************************                       Extra Handlers for default compiler****************************************************************************}    procedure DoneRedirectFile;      begin        if status.use_redir then         begin           close(status.redirfile);           status.use_redir:=false;         end;        if status.use_bugreport then         begin           close(status.reportbugfile);           status.use_bugreport:=false;         end;      end;    procedure SetRedirectFile(const fn:string);      begin        assign(status.redirfile,fn);        {$I-}         append(status.redirfile);         if ioresult <> 0 then          rewrite(status.redirfile);        {$I+}        status.use_redir:=(ioresult=0);      end;    procedure PrepareReport;      var        fn : string;      begin        if status.use_bugreport then         exit;        fn:='fpcdebug.txt';        assign(status.reportbugfile,fn);        {$I-}         append(status.reportbugfile);         if ioresult <> 0 then          rewrite(status.reportbugfile);        {$I+}        status.use_bugreport:=(ioresult=0);        if status.use_bugreport then         writeln(status.reportbugfile,'FPC bug report file');      end;    function CheckVerbosity(v:longint):boolean;      begin        CheckVerbosity:=status.use_bugreport or                        ((status.verbosity and (v and V_LevelMask))=(v and V_LevelMask));      end;    function SetVerbosity(const s:string):boolean;      var        m : Longint;        i : Integer;        inverse : boolean;        c : char;      begin        Setverbosity:=false;        val(s,m,i);        if (i=0) and (s<>'') then         status.verbosity:=m        else         begin           i:=1;           while i<=length(s) do             begin                c:=upcase(s[i]);                inverse:=false;                { on/off ? }                if (i<length(s)) then                 case s[i+1] of                  '-' : begin                          inc(i);                          inverse:=true;                        end;                  '+' : inc(i);                 end;                { handle switch }                case c of                { Special cases }                 'A' : status.verbosity:=V_All;                 '0' : status.verbosity:=V_Default;                 'P' : begin                         if inverse then                          paraprintnodetree:=0                         else                          paraprintnodetree:=1;                       end;                 'R' : begin                          if inverse then                            begin                               status.use_gccoutput:=false;                               status.use_stderr:=false;                            end                          else                            begin                               status.use_gccoutput:=true;                               status.use_stderr:=true;                            end;                       end;                 'Z' : begin                          if inverse then                            status.use_stderr:=false                          else                            status.use_stderr:=true;                       end;                { Normal cases - do an or }                 'E' : if inverse then                         status.verbosity:=status.verbosity and (not V_Error)                       else                         status.verbosity:=status.verbosity or V_Error;                 'I' : if inverse then                         status.verbosity:=status.verbosity and (not V_Info)                       else                         status.verbosity:=status.verbosity or V_Info;                 'W' : if inverse then                         status.verbosity:=status.verbosity and (not V_Warning)                       else                         status.verbosity:=status.verbosity or V_Warning;                 'N' : if inverse then                         status.verbosity:=status.verbosity and (not V_Note)                       else                         status.verbosity:=status.verbosity or V_Note;                 'H' : if inverse then                         status.verbosity:=status.verbosity and (not V_Hint)                       else                         status.verbosity:=status.verbosity or V_Hint;                 'L' : if inverse then                         status.verbosity:=status.verbosity and (not V_Status)                       else                         status.verbosity:=status.verbosity or V_Status;                 'U' : if inverse then                         status.verbosity:=status.verbosity and (not V_Used)                       else                         status.verbosity:=status.verbosity or V_Used;                 'T' : if inverse then                         status.verbosity:=status.verbosity and (not V_Tried)                       else                         status.verbosity:=status.verbosity or V_Tried;                 'C' : if inverse then                         status.verbosity:=status.verbosity and (not V_Conditional)                       else                         status.verbosity:=status.verbosity or V_Conditional;                 'D' : if inverse then                         status.verbosity:=status.verbosity and (not V_Debug)                       else                         status.verbosity:=status.verbosity or V_Debug;                 'X' : if inverse then                         status.verbosity:=status.verbosity and (not V_Executable)                       else                         status.verbosity:=status.verbosity or V_Executable;                 'V' : PrepareReport;                 end;                inc(i);             end;           end;        if status.verbosity=0 then         status.verbosity:=V_Default;        setverbosity:=true;      end;    procedure Loadprefixes;        function loadprefix(w:longint):string;        var          s : string;          idx : longint;        begin          s:=msg^.get(w,[]);          idx:=pos('_',s);          if idx>0 then           Loadprefix:=Copy(s,idx+1,255)          else           Loadprefix:=s;        end;      begin      { Load the prefixes }        fatalstr:=Loadprefix(general_i_fatal);        errorstr:=Loadprefix(general_i_error);        warningstr:=Loadprefix(general_i_warning);        notestr:=Loadprefix(general_i_note);        hintstr:=Loadprefix(general_i_hint);      end;    procedure LoadMsgFile(const fn:string);      begin        { reload the internal messages if not already loaded }{$ifndef EXTERN_MSG}        if not msg^.msgintern then         msg^.LoadIntern(@msgtxt,msgtxtsize);{$endif}        if not msg^.LoadExtern(fn) then         begin{$ifdef EXTERN_MSG}           writeln('Fatal: Cannot find error message file.');           halt(3);{$else}           msg^.LoadIntern(@msgtxt,msgtxtsize);{$endif}         end;        { reload the prefixes using the new messages }        Loadprefixes;      end;    procedure MaybeLoadMessageFile;      begin        { Load new message file }        if (msgfilename<>'')  then         begin           LoadMsgFile(msgfilename);           msgfilename:='';         end;      end;    procedure SetCompileModule(p:tmodulebase);      begin        compiling_module:=p;      end;      var        lastfileidx,        lastmoduleidx : longint;    Procedure UpdateStatus;      begin      { fix status }        status.currentline:=aktfilepos.line;        status.currentcolumn:=aktfilepos.column;        if assigned(compiling_module) and           assigned(compiling_module.sourcefiles) and           ((compiling_module.unit_index<>lastmoduleidx) or            (aktfilepos.fileindex<>lastfileidx)) then         begin           { update status record }           status.currentmodule:=compiling_module.modulename^;           status.currentsource:=compiling_module.sourcefiles.get_file_name(aktfilepos.fileindex);           status.currentsourcepath:=compiling_module.sourcefiles.get_file_path(aktfilepos.fileindex);           { update lastfileidx only if name known PM }           if status.currentsource<>'' then             lastfileidx:=aktfilepos.fileindex           else             lastfileidx:=0;           lastmoduleidx:=compiling_module.unit_index;         end;        if assigned(compiling_module) then          status.compiling_current:=(compiling_module.state in [ms_compile,ms_second_compile]);      end;    procedure ShowStatus;      begin        UpdateStatus;        if do_status() then          raise ECompilerAbort.Create;      end;    function ErrorCount:longint;      begin        ErrorCount:=status.errorcount;      end;    procedure SetErrorFlags(const s:string);      var        code : integer;        i,j,l : longint;      begin      { empty string means error count = 1 for backward compatibility (PFV) }        if s='' then         begin           status.maxerrorcount:=1;           exit;         end;        i:=0;        while (i<length(s)) do         begin           inc(i);           case s[i] of             '0'..'9' :                begin                  j:=i;                  while (j<=length(s)) and (s[j] in ['0'..'9']) do                   inc(j);                  val(copy(s,i,j-i),l,code);                  if code<>0 then                   l:=1;                  status.maxerrorcount:=l;                  i:=j;                end;              'w','W' :                status.errorwarning:=true;              'n','N' :                status.errornote:=true;              'h','H' :                status.errorhint:=true;           end;         end;      end;    procedure GenerateError;      begin        inc(status.errorcount);      end;    procedure internalerror(i : longint);      begin        UpdateStatus;        do_internalerror(i);        inc(status.errorcount);        raise ECompilerAbort.Create;      end;    procedure Comment(l:longint;s:string);      var        dostop : boolean;      begin        dostop:=((l and V_Fatal)<>0);        if ((l and V_Error)<>0) or           (status.errorwarning and ((l and V_Warning)<>0)) or           (status.errornote and ((l and V_Note)<>0)) or           (status.errorhint and ((l and V_Hint)<>0)) then         inc(status.errorcount);      { check verbosity level }        if not CheckVerbosity(l) then          exit;        if (l and V_LineInfoMask)<>0 then          l:=l or V_LineInfo;      { Create status info }        UpdateStatus;      { Fix replacements }        DefaultReplacements(s);      { show comment }        if do_comment(l,s) or dostop then          raise ECompilerAbort.Create;        if (status.errorcount>=status.maxerrorcount) and not status.skip_error then         begin           Message1(unit_f_errors_in_unit,tostr(status.errorcount));           status.skip_error:=true;           raise ECompilerAbort.Create;         end;      end;    Procedure Msg2Comment(s:string);      var        idx,i,v : longint;        dostop  : boolean;      begin      {Reset}        dostop:=false;        v:=0;      {Parse options}        idx:=pos('_',s);        if idx=0 then         v:=V_Normal        else         if (idx >= 1) And (idx <= 5) then          begin            for i:=1 to idx do             begin               case upcase(s[i]) of                'F' :                  begin                    v:=v or V_Fatal;                    inc(status.errorcount);                    dostop:=true;                  end;                'E' :                  begin                    v:=v or V_Error;                    inc(status.errorcount);                  end;                'O' :                  v:=v or V_Normal;                'W':                  begin                    v:=v or V_Warning;                    if status.errorwarning then                     inc(status.errorcount);                  end;                'N' :                  begin                    v:=v or V_Note;                    if status.errornote then                     inc(status.errorcount);                  end;                'H' :                  begin                    v:=v or V_Hint;                    if status.errorhint then                     inc(status.errorcount);                  end;                'I' :                  v:=v or V_Info;                'L' :                  v:=v or V_LineInfo;                'U' :                  v:=v or V_Used;                'T' :                  v:=v or V_Tried;                'C' :                  v:=v or V_Conditional;                'D' :                  v:=v or V_Debug;                'X' :                  v:=v or V_Executable;                'S' :                  dostop:=true;                '_' : ;               end;             end;          end;        Delete(s,1,idx);      { check verbosity level }        if not CheckVerbosity(v) then          exit;        if (v and V_LineInfoMask)<>0 then          v:=v or V_LineInfo;      { fix status }        UpdateStatus;      { Fix replacements }        DefaultReplacements(s);      { show comment }        if do_comment(v,s) or dostop then          raise ECompilerAbort.Create;        if (status.errorcount>=status.maxerrorcount) and not status.skip_error then         begin           Message1(unit_f_errors_in_unit,tostr(status.errorcount));           status.skip_error:=true;           raise ECompilerAbort.Create;         end;      end;    function  MessagePchar(w:longint):pchar;      begin        MaybeLoadMessageFile;        MessagePchar:=msg^.GetPchar(w)      end;    procedure Message(w:longint);      begin        MaybeLoadMessageFile;        Msg2Comment(msg^.Get(w,[]));      end;    procedure Message1(w:longint;const s1:string);{$ifdef ver1_0}      var        hs1 : string;{$endif ver1_0}      begin        MaybeLoadMessageFile;{$ifdef ver1_0}        { 1.0.x is broken, it uses concatcopy instead of shortstring          copy when passing array of shortstring. (PFV) }        hs1:=s1;        Msg2Comment(msg^.Get(w,[hs1]));{$else ver1_0}        Msg2Comment(msg^.Get(w,[s1]));{$endif ver1_0}      end;    procedure Message2(w:longint;const s1,s2:string);{$ifdef ver1_0}      var        hs1,hs2 : string;{$endif ver1_0}      begin        MaybeLoadMessageFile;{$ifdef ver1_0}        { 1.0.x is broken, it uses concatcopy instead of shortstring          copy when passing array of shortstring. (PFV) }        hs1:=s1;        hs2:=s2;        Msg2Comment(msg^.Get(w,[hs1,hs2]));{$else ver1_0}        Msg2Comment(msg^.Get(w,[s1,s2]));{$endif ver1_0}      end;    procedure Message3(w:longint;const s1,s2,s3:string);{$ifdef ver1_0}      var        hs1,hs2,hs3 : string;{$endif ver1_0}      begin        MaybeLoadMessageFile;{$ifdef ver1_0}        { 1.0.x is broken, it uses concatcopy instead of shortstring          copy when passing array of shortstring. (PFV) }        hs1:=s1;        hs2:=s2;        hs3:=s3;        Msg2Comment(msg^.Get(w,[hs1,hs2,hs3]));{$else ver1_0}        Msg2Comment(msg^.Get(w,[s1,s2,s3]));{$endif ver1_0}      end;    procedure Message4(w:longint;const s1,s2,s3,s4:string);{$ifdef ver1_0}      var        hs1,hs2,hs3,hs4 : string;{$endif ver1_0}      begin        MaybeLoadMessageFile;{$ifdef ver1_0}        { 1.0.x is broken, it uses concatcopy instead of shortstring          copy when passing array of shortstring. (PFV) }        hs1:=s1;        hs2:=s2;        hs3:=s3;        hs4:=s4;        Msg2Comment(msg^.Get(w,[hs1,hs2,hs3,hs4]));{$else ver1_0}        Msg2Comment(msg^.Get(w,[s1,s2,s3,s4]));{$endif ver1_0}      end;    procedure MessagePos(const pos:tfileposinfo;w:longint);      var        oldpos : tfileposinfo;      begin        oldpos:=aktfilepos;        aktfilepos:=pos;        MaybeLoadMessageFile;        Msg2Comment(msg^.Get(w,[]));        aktfilepos:=oldpos;      end;    procedure MessagePos1(const pos:tfileposinfo;w:longint;const s1:string);      var        oldpos : tfileposinfo;      begin        oldpos:=aktfilepos;        aktfilepos:=pos;        MaybeLoadMessageFile;        Msg2Comment(msg^.Get(w,[s1]));        aktfilepos:=oldpos;      end;    procedure MessagePos2(const pos:tfileposinfo;w:longint;const s1,s2:string);      var        oldpos : tfileposinfo;      begin        oldpos:=aktfilepos;        aktfilepos:=pos;        MaybeLoadMessageFile;        Msg2Comment(msg^.Get(w,[s1,s2]));        aktfilepos:=oldpos;      end;    procedure MessagePos3(const pos:tfileposinfo;w:longint;const s1,s2,s3:string);      var        oldpos : tfileposinfo;      begin        oldpos:=aktfilepos;        aktfilepos:=pos;        MaybeLoadMessageFile;        Msg2Comment(msg^.Get(w,[s1,s2,s3]));        aktfilepos:=oldpos;      end;    procedure MessagePos4(const pos:tfileposinfo;w:longint;const s1,s2,s3,s4:string);      var        oldpos : tfileposinfo;      begin        oldpos:=aktfilepos;        aktfilepos:=pos;        MaybeLoadMessageFile;        Msg2Comment(msg^.Get(w,[s1,s2,s3,s4]));        aktfilepos:=oldpos;      end;{*****************************************************************************            override the message calls to set codegenerror*****************************************************************************}    procedure cgmessage(t : longint);      var         olderrorcount : longint;      begin         if not(codegenerror) then           begin              olderrorcount:=Errorcount;              verbose.Message(t);              codegenerror:=olderrorcount<>Errorcount;           end;      end;    procedure cgmessage1(t : longint;const s : string);      var         olderrorcount : longint;      begin         if not(codegenerror) then           begin              olderrorcount:=Errorcount;              verbose.Message1(t,s);              codegenerror:=olderrorcount<>Errorcount;           end;      end;    procedure cgmessage2(t : longint;const s1,s2 : string);      var         olderrorcount : longint;      begin         if not(codegenerror) then           begin              olderrorcount:=Errorcount;              verbose.Message2(t,s1,s2);              codegenerror:=olderrorcount<>Errorcount;           end;      end;    procedure cgmessage3(t : longint;const s1,s2,s3 : string);      var         olderrorcount : longint;      begin         if not(codegenerror) then           begin              olderrorcount:=Errorcount;              verbose.Message3(t,s1,s2,s3);              codegenerror:=olderrorcount<>Errorcount;           end;      end;    procedure cgmessagepos(const pos:tfileposinfo;t : longint);      var         olderrorcount : longint;      begin         if not(codegenerror) then           begin              olderrorcount:=Errorcount;              verbose.MessagePos(pos,t);              codegenerror:=olderrorcount<>Errorcount;           end;      end;    procedure cgmessagepos1(const pos:tfileposinfo;t : longint;const s1 : string);      var         olderrorcount : longint;      begin         if not(codegenerror) then           begin              olderrorcount:=Errorcount;              verbose.MessagePos1(pos,t,s1);              codegenerror:=olderrorcount<>Errorcount;           end;      end;    procedure cgmessagepos2(const pos:tfileposinfo;t : longint;const s1,s2 : string);      var         olderrorcount : longint;      begin         if not(codegenerror) then           begin              olderrorcount:=Errorcount;              verbose.MessagePos2(pos,t,s1,s2);              codegenerror:=olderrorcount<>Errorcount;           end;      end;    procedure cgmessagepos3(const pos:tfileposinfo;t : longint;const s1,s2,s3 : string);      var         olderrorcount : longint;      begin         if not(codegenerror) then           begin              olderrorcount:=Errorcount;              verbose.MessagePos3(pos,t,s1,s2,s3);              codegenerror:=olderrorcount<>Errorcount;           end;      end;{*****************************************************************************                                Initialization*****************************************************************************}    procedure InitVerbose;      begin      { Init }        msg:=new(pmessage,Init(20,msgidxmax));        if msg=nil then         begin           writeln('Fatal: MsgIdx Wrong');           halt(3);         end;{$ifndef EXTERN_MSG}        msg^.LoadIntern(@msgtxt,msgtxtsize);{$else EXTERN_MSG}        LoadMsgFile(exepath+'errore.msg');{$endif EXTERN_MSG}        FillChar(Status,sizeof(TCompilerStatus),0);        status.verbosity:=V_Default;        Status.MaxErrorCount:=50;        Loadprefixes;        lastfileidx:=-1;        lastmoduleidx:=-1;        status.currentmodule:='';        status.currentsource:='';        status.currentsourcepath:='';        status.compiling_current:=false;        compiling_module:=nil;        { Register internalerrorproc for cutils/cclasses }        internalerrorproc:=@internalerror;      end;    procedure DoneVerbose;      begin        if assigned(msg) then         begin           dispose(msg,Done);           msg:=nil;         end;        DoneRedirectFile;      end;initializationfinalization  { Be sure to close the redirect files to flush all data }  DoneRedirectFile;end.
 |