| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305 | {    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 USE_FAKE_SYSUTILS}      sysutils,{$ELSE}      fksysutl,{$ENDIF}      cutils,      globtype,finput,      cmsgs;{$ifndef EXTERN_MSG}  {$i msgtxt.inc}{$endif}{$i msgidx.inc}    var      msg : pmessage;    type      tmsgqueueevent = procedure(const s:TMsgStr;v,w:longint) of object;    const      msgfilename : string = '';    procedure SetRedirectFile(const fn:string);    function  SetVerbosity(const s:TCmdStr):boolean;    procedure PrepareReport;    function  CheckVerbosity(v:longint):boolean;    function  SetMessageVerbosity(v:longint;state:tmsgstate):boolean;    procedure RestoreLocalVerbosity(pstate : pmessagestaterecord);    procedure FreeLocalVerbosity(var fstate : pmessagestaterecord);    function ChangeMessageVerbosity(s: ansistring; var i: integer;state:tmsgstate): boolean;    procedure ShowStatus;    function  ErrorCount:longint;    procedure SetErrorFlags(const s:string);    procedure GenerateError;    procedure Internalerror(i:longint);noreturn;    procedure Comment(l:longint;s:ansistring);    function  MessageStr(w:longint):TMsgStr;    procedure Message(w:longint;onqueue:tmsgqueueevent=nil);    procedure Message1(w:longint;const s1:TMsgStr;onqueue:tmsgqueueevent=nil);    procedure Message2(w:longint;const s1,s2:TMsgStr;onqueue:tmsgqueueevent=nil);    procedure Message3(w:longint;const s1,s2,s3:TMsgStr;onqueue:tmsgqueueevent=nil);    procedure Message4(w:longint;const s1,s2,s3,s4:TMsgStr;onqueue:tmsgqueueevent=nil);    procedure MessagePos(const pos:tfileposinfo;w:longint;onqueue:tmsgqueueevent=nil);    procedure MessagePos1(const pos:tfileposinfo;w:longint;const s1:TMsgStr;onqueue:tmsgqueueevent=nil);    procedure MessagePos2(const pos:tfileposinfo;w:longint;const s1,s2:TMsgStr;onqueue:tmsgqueueevent=nil);    procedure MessagePos3(const pos:tfileposinfo;w:longint;const s1,s2,s3:TMsgStr;onqueue:tmsgqueueevent=nil);    procedure MessagePos4(const pos:tfileposinfo;w:longint;const s1,s2,s3,s4:TMsgStr;onqueue:tmsgqueueevent=nil);    { message calls with codegenerror support }    procedure cgmessage(t : longint);    procedure cgmessage1(t : longint;const s : TMsgStr);    procedure cgmessage2(t : longint;const s1,s2 : TMsgStr);    procedure cgmessage3(t : longint;const s1,s2,s3 : TMsgStr);    procedure CGMessagePos(const pos:tfileposinfo;t:longint);    procedure CGMessagePos1(const pos:tfileposinfo;t:longint;const s1:TMsgStr);    procedure CGMessagePos2(const pos:tfileposinfo;t:longint;const s1,s2:TMsgStr);    procedure CGMessagePos3(const pos:tfileposinfo;t:longint;const s1,s2,s3:TMsgStr);    procedure FlushOutput;    procedure InitVerbose;    procedure DoneVerbose;    const      printnodespacing = '   ';    var      { indention used when writing a node tree to the screen }      printnodeindention : string;     { Node dumping support functions }     procedure printnodeindent; inline;     procedure printnodeunindent; inline;{$ifdef DEBUG_NODE_XML}     function SanitiseXMLString(const S: ansistring): ansistring;     function WritePointer(const P: Pointer): ansistring;     function WriteConstPUInt(const P: TConstPtrUInt): ansistring;     function WriteGUID(const GUID: TGUID): ansistring;{$endif DEBUG_NODE_XML}implementation    uses      comphook,fmodule,constexp,globals,cfileutl,switches,cclasses;{****************************************************************************                       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        { close old redirection file because FileRedirection is handled in both passes }        if status.use_redir then          close(status.redirfile);        assign(status.redirfile,fn);      {$push}{$I-}        append(status.redirfile);        if ioresult <> 0 then          begin            assign(status.redirfile,fn);            rewrite(status.redirfile);          end;      {$pop}        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);        {$push}{$I-}         append(status.reportbugfile);         if ioresult <> 0 then          rewrite(status.reportbugfile);        {$pop}        status.use_bugreport:=(ioresult=0);        if status.use_bugreport then         writeln(status.reportbugfile,'FPC bug report file');      end;    procedure RestoreLocalVerbosity(pstate : pmessagestaterecord);      var        msgset : thashset;        msgfound : boolean;      begin        msg^.ResetStates;        msgset:=thashset.create(10,false,false);        while assigned(pstate) do          begin            msgfound:=false;            { only apply the newest message state }            if not assigned(msgset.findoradd(@pstate^.value,sizeof(pstate^.value),msgfound)) or                not msgfound then              SetMessageVerbosity(pstate^.value,pstate^.state);            pstate:=pstate^.next;          end;        msgset.free;      end;    procedure FreeLocalVerbosity(var fstate : pmessagestaterecord);    var pstate : pmessagestaterecord;      begin        pstate:=unaligned(fstate);        while assigned(pstate) do          begin            unaligned(fstate):=pstate^.next;            dispose(pstate);            pstate:=unaligned(fstate);          end;      end;    function ChangeMessageVerbosity(s: ansistring; var i : integer;state:tmsgstate): boolean;      var        tok  : ansistring;        msgnr, code : longint;      begin        { delete everything up to and including 'm' }        delete(s,1,i);        { the rest of the string must be message numbers }        inc(i,length(s)+1);        result:=false;        repeat          tok:=GetToken(s,',');          if (tok='') then            break;          val(tok, msgnr, code);          if (code<>0) then            exit;          if not msg^.valid(msgnr) then            exit          else            recordpendingmessagestate(msgnr, state);        until false;        result:=true;      end;    function SetMessageVerbosity(v:longint;state:tmsgstate):boolean;      begin        result:=msg^.setverbosity(v,state);      end;    function CheckVerbosity(v:longint):boolean;      begin        result:=do_checkverbosity(v);      end;    function SetVerbosity(const s:TCmdStr):boolean;      const        message_verbosity:array[boolean] of tmsgstate=(ms_off_global,ms_on_global);      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 }                 '0' : status.verbosity:=V_Default;                 'A' : status.verbosity:=V_All;                 'B' : begin                          if inverse then                            status.print_source_path:=false                          else                            status.print_source_path:=true;                       end;                 'M' : if not ChangeMessageVerbosity(s,i,message_verbosity[inverse]) then                         begin                           result:=false;                           exit                         end;                 'P' : begin                         if inverse then                          paraprintnodetree:=0                         else                          paraprintnodetree:=1;                       end;                 'Q' : begin                          if inverse then                            status.showmsgnrs:=false                          else                            status.showmsgnrs:=true;                       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;                 'V' : PrepareReport;                 'Z' : begin                          if inverse then                            status.use_stderr:=false                          else                            status.use_stderr:=true;                       end;                { Normal cases - do an or }                 '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;                 'E' : if inverse then                         status.verbosity:=status.verbosity and (not V_Error)                       else                         status.verbosity:=status.verbosity or V_Error;                 'H' : if inverse then                         status.verbosity:=status.verbosity and (not V_Hint)                       else                         status.verbosity:=status.verbosity or V_Hint;                 'I' : if inverse then                         status.verbosity:=status.verbosity and (not V_Info)                       else                         status.verbosity:=status.verbosity or V_Info;                 'J' : if inverse then                         status.verbosity:=status.verbosity and (not V_Parallel)                       else                         status.verbosity:=status.verbosity or V_Parallel;                 'L' : if inverse then                         status.verbosity:=status.verbosity and (not V_Status)                       else                         status.verbosity:=status.verbosity or V_Status;                 'N' : if inverse then                         status.verbosity:=status.verbosity and (not V_Note)                       else                         status.verbosity:=status.verbosity or V_Note;                 'S' : if inverse then                         status.verbosity:=status.verbosity and (not V_TimeStamps)                       else                         status.verbosity:=status.verbosity or V_TimeStamps;                 'T' : if inverse then                         status.verbosity:=status.verbosity and (not V_Tried)                       else                         status.verbosity:=status.verbosity or V_Tried;                 'U' : if inverse then                         status.verbosity:=status.verbosity and (not V_Used)                       else                         status.verbosity:=status.verbosity or V_Used;                 'W' : if inverse then                         status.verbosity:=status.verbosity and (not V_Warning)                       else                         status.verbosity:=status.verbosity or V_Warning;                 'X' : if inverse then                         status.verbosity:=status.verbosity and (not V_Executable)                       else                         status.verbosity:=status.verbosity or V_Executable;                 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,msgtxt_codepage);{$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,msgtxt_codepage);{$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;    var      lastfileidx,      lastmoduleidx : longint;    Procedure UpdateStatus;      var        module : tmodule;      begin      { fix status }        status.currentline:=current_filepos.line;        status.currentcolumn:=current_filepos.column;        if (current_filepos.moduleindex <> lastmoduleidx) or           (current_filepos.fileindex <> lastfileidx) then        begin          module:=get_module(current_filepos.moduleindex);          if assigned(module) and assigned(module.sourcefiles) then            begin              { update status record }              status.currentmodule:=module.modulename^;              status.currentsourceppufilename:=module.ppufilename;              status.currentmodulestate:=ModuleStateStr[module.state];              status.currentsource:=module.sourcefiles.get_file_name(current_filepos.fileindex);              status.currentsourcepath:=module.sourcefiles.get_file_path(current_filepos.fileindex);              status.sources_avail:=module.sources_avail;              { if currentsourcepath is relative, make it absolute }              if not path_absolute(status.currentsourcepath) then                status.currentsourcepath:=GetCurrentDir+status.currentsourcepath;              { update lastfileidx only if name known PM }              if status.currentsource<>'' then                lastfileidx:=current_filepos.fileindex              else                lastfileidx:=0;              lastmoduleidx:=module.unit_index;            end;        end;      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-1;                end;              'w','W' :                begin                  if (i<length(s)) and (s[i+1]='-') then                    begin                      inc(i);                      status.errorwarning:=false;                    end                  else                    begin                      status.errorwarning:=true;                      { Enable writing of warnings, to avoid getting errors without any message }                      status.verbosity:=status.verbosity or V_Warning;                    end;                end;              'n','N' :                begin                  if (i<length(s)) and (s[i+1]='-') then                    begin                      inc(i);                      status.errornote:=false;                    end                  else                    begin                      status.errornote:=true;                      { Enable writing of notes, to avoid getting errors without any message }                      status.verbosity:=status.verbosity or V_Note;                    end;                end;              'h','H' :                begin                  if (i<length(s)) and (s[i+1]='-') then                    begin                      inc(i);                      status.errorhint:=false;                    end                  else                    begin                      status.errorhint:=true;                      { Enable writing of hints, to avoid getting errors without any message }                      status.verbosity:=status.verbosity or V_Hint;                    end;                end;           end;         end;      end;    procedure GenerateError;      begin        inc(status.errorcount);      end;    procedure internalerror(i : longint);noreturn;      procedure doraise;        begin          raise ECompilerAbort.Create;        end;      begin        UpdateStatus;        do_internalerror(i);        GenerateError;        doraise;      end;    procedure Comment(l:longint;s:ansistring);      var        dostop : boolean;      begin        dostop:=((l and V_Fatal)<>0);        if ((l and V_Error)<>0) or           ((l and V_Fatal)<>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         GenerateError        else         if l and V_Warning <> 0 then          inc(status.countWarnings)         else          if l and V_Note <> 0 then           inc(status.countNotes)          else           if l and V_Hint <> 0 then            inc(status.countHints);      { 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,false);      { 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;    function GetMessageState(m:longint):tmsgstate;      var        i: integer;      begin        i:=m div 1000;        { get the default state }        Result:=msg^.msgstates[i][m mod 1000];        { and search at the current unit settings }        { todo }      end;    Procedure Msg2Comment(s:ansistring;w:longint;onqueue:tmsgqueueevent);      var        idx,i,v : longint;        dostop  : boolean;        doqueue : boolean;        st      : tmsgstate;        ch      : char;      begin      {Reset}        dostop:=false;        doqueue:=false;        v:=0;      {Parse options}        idx:=pos('_',s);        if idx=0 then         v:=V_None        else         if (idx >= 1) And (idx <= 5) then          begin            for i:=1 to idx do             begin               ch:=upcase(s[i]);               case ch of                'F' :                  begin                    v:=v or V_Fatal;                    GenerateError;                    dostop:=true;                  end;                'E','W','N','H':                  begin                    if ch='E' then                      st:=ms_error                    else                      st:=GetMessageState(w);                    { We only want to know about local value }                    st:= tmsgstate(ord(st) and ms_local_mask);                    if st=ms_error then                      begin                        v:=v or V_Error;                        GenerateError;                      end                    else if st<>ms_off then                      case ch of                       'W':                         begin                           v:=v or V_Warning;                           if CheckVerbosity(V_Warning) then                             if status.errorwarning then                              GenerateError                             else                              inc(status.countWarnings);                         end;                       'N' :                         begin                           v:=v or V_Note;                           if CheckVerbosity(V_Note) then                             if status.errornote then                              GenerateError                             else                              inc(status.countNotes);                         end;                       'H' :                         begin                           v:=v or V_Hint;                           if CheckVerbosity(V_Hint) then                             if status.errorhint then                              GenerateError                             else                              inc(status.countHints);                         end;                      end;                  end;                'O' :                  v:=v or V_Normal;                '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          begin            doqueue := onqueue <> nil;            if not doqueue then              exit;          end;        if (v and V_LineInfoMask)<>0 then          v:=v or V_LineInfo;      { fix status }        UpdateStatus;      { Fix replacements }        DefaultReplacements(s,false);        if status.showmsgnrs and ((v and V_Normal)=0) then          s:='('+tostr(w)+') '+s;        if doqueue then          begin            onqueue(s,v,w);            exit;          end;      { 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  MessageStr(w:longint):TMsgStr;      begin        MaybeLoadMessageFile;        MessageStr:=msg^.Get(w,[]);      end;    procedure Message(w:longint;onqueue:tmsgqueueevent=nil);      begin        MaybeLoadMessageFile;        Msg2Comment(msg^.Get(w,[]),w,onqueue);      end;    procedure Message1(w:longint;const s1:TMsgStr;onqueue:tmsgqueueevent=nil);      begin        MaybeLoadMessageFile;        Msg2Comment(msg^.Get(w,[s1]),w,onqueue);      end;    procedure Message2(w:longint;const s1,s2:TMsgStr;onqueue:tmsgqueueevent=nil);      begin        MaybeLoadMessageFile;        Msg2Comment(msg^.Get(w,[s1,s2]),w,onqueue);      end;    procedure Message3(w:longint;const s1,s2,s3:TMsgStr;onqueue:tmsgqueueevent=nil);      begin        MaybeLoadMessageFile;        Msg2Comment(msg^.Get(w,[s1,s2,s3]),w,onqueue);      end;    procedure Message4(w:longint;const s1,s2,s3,s4:TMsgStr;onqueue:tmsgqueueevent=nil);      begin        MaybeLoadMessageFile;        Msg2Comment(msg^.Get(w,[s1,s2,s3,s4]),w,onqueue);      end;    procedure MessagePos(const pos:tfileposinfo;w:longint;onqueue:tmsgqueueevent=nil);      var        oldpos : tfileposinfo;      begin        oldpos:=current_filepos;        current_filepos:=pos;        MaybeLoadMessageFile;        Msg2Comment(msg^.Get(w,[]),w,onqueue);        current_filepos:=oldpos;      end;    procedure MessagePos1(const pos:tfileposinfo;w:longint;const s1:TMsgStr;onqueue:tmsgqueueevent=nil);      var        oldpos : tfileposinfo;      begin        oldpos:=current_filepos;        current_filepos:=pos;        MaybeLoadMessageFile;        Msg2Comment(msg^.Get(w,[s1]),w,onqueue);        current_filepos:=oldpos;      end;    procedure MessagePos2(const pos:tfileposinfo;w:longint;const s1,s2:TMsgStr;onqueue:tmsgqueueevent=nil);      var        oldpos : tfileposinfo;      begin        oldpos:=current_filepos;        current_filepos:=pos;        MaybeLoadMessageFile;        Msg2Comment(msg^.Get(w,[s1,s2]),w,onqueue);        current_filepos:=oldpos;      end;    procedure MessagePos3(const pos:tfileposinfo;w:longint;const s1,s2,s3:TMsgStr;onqueue:tmsgqueueevent=nil);      var        oldpos : tfileposinfo;      begin        oldpos:=current_filepos;        current_filepos:=pos;        MaybeLoadMessageFile;        Msg2Comment(msg^.Get(w,[s1,s2,s3]),w,onqueue);        current_filepos:=oldpos;      end;    procedure MessagePos4(const pos:tfileposinfo;w:longint;const s1,s2,s3,s4:TMsgStr;onqueue:tmsgqueueevent=nil);      var        oldpos : tfileposinfo;      begin        oldpos:=current_filepos;        current_filepos:=pos;        MaybeLoadMessageFile;        Msg2Comment(msg^.Get(w,[s1,s2,s3,s4]),w,onqueue);        current_filepos:=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 : TMsgStr);      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 : TMsgStr);      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 : TMsgStr);      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 : TMsgStr);      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 : TMsgStr);      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 : TMsgStr);      var         olderrorcount : longint;      begin         if not(codegenerror) then           begin              olderrorcount:=Errorcount;              verbose.MessagePos3(pos,t,s1,s2,s3);              codegenerror:=olderrorcount<>Errorcount;           end;      end;    procedure FlushOutput;      begin        if not (Status.Use_StdErr) then (* StdErr is flushed after every line *)          begin            if Status.Use_Redir then              Flush(Status.RedirFile)            else              Flush(Output);          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,msgtxt_codepage);{$else EXTERN_MSG}        LoadMsgFile(exepath+'errore.msg');{$endif EXTERN_MSG}        FillChar(Status,sizeof(TCompilerStatus),0);        status.verbosity:=V_Default;        Status.MaxErrorCount:=50;        Status.codesize:=aword(-1);        Status.datasize:=aword(-1);        Loadprefixes;        lastfileidx:=-1;        lastmoduleidx:=-1;        status.currentmodule:='';        status.currentsourceppufilename:='';        status.currentsource:='';        status.currentsourcepath:='';        { Register internalerrorproc for cutils/cclasses }        internalerrorproc:=@internalerror;      end;    procedure DoneVerbose;      begin        if assigned(msg) then         begin           dispose(msg,Done);           msg:=nil;         end;        DoneRedirectFile;      end;    procedure printnodeindent; inline;      begin        printnodeindention:=printnodeindention+printnodespacing;      end;    procedure printnodeunindent; inline;      begin        delete(printnodeindention,1,length(printnodespacing));      end;{$ifdef DEBUG_NODE_XML}    function WritePointer(const P: Pointer): ansistring;      begin        case PtrUInt(P) of          0:            WritePointer := 'nil';          1..$FFFF:            WritePointer := '$' + hexstr(PtrUInt(P), 4);    {$if sizeof(Pointer) >= 4}          $10000..$FFFFFFFF:            WritePointer := '$' + hexstr(PtrUInt(P), 8);    {$ifend sizeof(Pointer) >= 4}    {$if sizeof(Pointer) > 4}          else            WritePointer := '$' + hexstr(PtrUInt(P), 2*sizeof(Pointer));    {$ifend sizeof(Pointer) > 4}        end;      end;    function WriteConstPUInt(const P: TConstPtrUInt): ansistring;      begin        case P of          0:            WriteConstPUInt := 'nil';          1..$FFFF:            WriteConstPUInt := '$' + hexstr(P, 4);    {$if sizeof(TConstPtrUInt) >= 4}          $10000..$FFFFFFFF:            WriteConstPUInt := '$' + hexstr(P, 8);    {$ifend sizeof(TConstPtrUInt) >= 4}    {$if sizeof(TConstPtrUInt) > 4}          else            WriteConstPUInt := '$' + hexstr(P, 2*sizeof(TConstPtrUInt));    {$endif sizeof(TConstPtrUInt) > 4}        end;      end;    function WriteGUID(const GUID: TGUID): ansistring;      var        i: Integer;      begin        Result := '{' + hexstr(GUID.D1, 8) + '-' + hexstr(GUID.D2, 4) + '-' + hexstr(GUID.D3, 4) + '-';        for i := 0 to 7 do          Result := Result + hexstr(GUID.D4[i], 2);        Result := Result + '}';      end;    function SanitiseXMLString(const S: ansistring): ansistring;      var        X, UTF8Len, CurrentChar: Integer;        needs_quoting, in_quotes, add_end_quote: Boolean;        DoASCII: Boolean;        { Write the given byte as #xxx }        procedure EncodeControlChar(Value: Byte);          begin            if X = Length(Result) then              add_end_quote := False;            Delete(Result, X, 1);            if in_quotes then              begin                Insert('#' + tostr(Value) + '''', Result, X);                { If the entire string consists of control characters, it                  doesn't need quoting, so only set the flag here }                needs_quoting := True;                in_quotes := False;              end            else              Insert('#' + tostr(Value), Result, X);          end;        { Write the given byte as either a plain character or an XML keyword }        procedure EncodeStandardChar(Value: Byte);          begin            if not in_quotes then              begin                in_quotes := True;                if (X < Length(Result)) then                  begin                    needs_quoting := True;                    Insert('''', Result, X + 1)                  end;              end;            { Check the character for anything that could be mistaken for an XML element }            case CurrentChar of              Ord('#'):                { Required to differentiate '#27' from the escape code #27, for example }                needs_quoting:=true;              Ord('<'):                begin                  Delete(Result, X, 1);                  Insert('<', Result, X);                end;              Ord('>'):                begin                  Delete(Result, X, 1);                  Insert('>', Result, X);                end;              Ord('&'):                begin                  Delete(Result, X, 1);                  Insert('&', Result, X);                end;              Ord('"'):                begin                  needs_quoting := True;                  Delete(Result, X, 1);                  Insert('"', Result, X);                end;              Ord(''''):                begin                  needs_quoting:=true;                  { Simply double it like in pascal strings }                  Insert('''', Result, X);                end;              else                { Do nothing };            end;          end;        { Convert character between $80 and $FF to UTF-8 }        procedure EncodeExtendedChar(Value: Byte);          begin            if not in_quotes then              begin                in_quotes := True;                if (X < Length(Result)) then                  begin                    needs_quoting := True;                    Insert('''', Result, X + 1)                  end;              end;            case Value of              $80..$BF: { Add $C2 before the value }                Insert(#$C2, Result, X);              $C0..$FF: { Zero the $40 bit and add $C3 before the value }                begin                  Result[X] := Char(Byte(Result[X]) and $BF);                  Insert(#$C3, Result, X);                end;              else                { Previous conditions should prevent this procedure from being                  called if Value < $80 }                InternalError(2019061901);            end;          end;      begin        needs_quoting := False;        Result := S;        { Gets set to True if an invalid UTF-8 sequence is found }        DoASCII := False;        { By setting in_quotes to false here, we can exclude the single          quotation marks surrounding the string if it doesn't contain any          control characters, or consists entirely of control characters. }        in_quotes := False;        add_end_quote := True;        X := Length(Result);        while X > 0 do          begin            CurrentChar := Ord(Result[X]);            { Control characters and extended characters need special handling }            case CurrentChar of              $00..$1F, $7F:                EncodeControlChar(CurrentChar);              $20..$7E:                EncodeStandardChar(CurrentChar);              { UTF-8 continuation byte }              $80..$BF:                begin                  if not in_quotes then                    begin                      in_quotes := True;                      if (X < Length(Result)) then                        begin                          needs_quoting := True;                          Insert('''', Result, X + 1)                        end;                    end;                  UTF8Len := 1;                  repeat                    inc(UTF8Len);                    dec(X);                  until (X = 0) or (UTF8Len >= 4) or (ord(Result[X]) shr 6 <> 2);                  if (X = 0) or (Utf8CodepointLen(@Result[X], UTF8Len, False) <> UTF8Len) then                    begin                      DoASCII := True;                      break;                    end;                end;              { Invalid UTF-8 bytes and lead bytes without continuation bytes }              $C0..$FF:                begin                  DoASCII := True;                  Break;                end;            end;            Dec(X);          end;        { UTF-8 failed, so encode the string as plain ASCII }        if DoASCII then          begin            { Reset the flags and Result }            needs_quoting := False;            Result := S;            in_quotes := False;            add_end_quote := True;            for X := Length(Result) downto 1 do              begin                CurrentChar := Ord(Result[X]);                { Control characters and extended characters need special handling }                case CurrentChar of                  $00..$1F, $7F:                    EncodeControlChar(CurrentChar);                  $20..$7E:                    EncodeStandardChar(CurrentChar);                  { Extended characters }                  else                    EncodeExtendedChar(CurrentChar);                end;              end;          end;        if needs_quoting then          begin            if in_quotes then              Result := '''' + Result;            if add_end_quote then              Result := Result + '''';          end;      end;{$endif DEBUG_NODE_XML}finalization  { Be sure to close the redirect files to flush all data }  DoneRedirectFile;end.
 |