2
0

verbose.pas 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373
  1. {
  2. Copyright (c) 1998-2002 by Peter Vreman
  3. This unit handles the verbose management
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit verbose;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. {$IFNDEF USE_FAKE_SYSUTILS}
  22. sysutils,
  23. {$ELSE}
  24. fksysutl,
  25. {$ENDIF}
  26. cutils,
  27. globtype,finput,
  28. cmsgs;
  29. {$ifndef EXTERN_MSG}
  30. {$i msgtxt.inc}
  31. {$endif}
  32. {$i msgidx.inc}
  33. var
  34. msg : pmessage;
  35. type
  36. tmsgqueueevent = procedure(const s:TMsgStr;v,w:longint) of object;
  37. const
  38. msgfilename : string = '';
  39. procedure SetRedirectFile(const fn:string);
  40. function SetVerbosity(const s:TCmdStr):boolean;
  41. procedure PrepareReport;
  42. function CheckVerbosity(v:longint):boolean;
  43. function SetMessageVerbosity(v:longint;state:tmsgstate):boolean;
  44. procedure RestoreLocalVerbosity(pstate : pmessagestaterecord);
  45. procedure FreeLocalVerbosity(var fstate : pmessagestaterecord);
  46. function ChangeMessageVerbosity(s: ansistring; var i: integer;state:tmsgstate): boolean;
  47. procedure ShowStatus;
  48. function ErrorCount:longint;
  49. procedure SetErrorFlags(const s:string);
  50. procedure GenerateError;
  51. procedure Internalerror(i:longint);noreturn;
  52. procedure Comment(l:longint;s:ansistring);
  53. function MessageStr(w:longint):TMsgStr;
  54. procedure Message(w:longint;onqueue:tmsgqueueevent=nil);
  55. procedure Message1(w:longint;const s1:TMsgStr;onqueue:tmsgqueueevent=nil);
  56. procedure Message2(w:longint;const s1,s2:TMsgStr;onqueue:tmsgqueueevent=nil);
  57. procedure Message3(w:longint;const s1,s2,s3:TMsgStr;onqueue:tmsgqueueevent=nil);
  58. procedure Message4(w:longint;const s1,s2,s3,s4:TMsgStr;onqueue:tmsgqueueevent=nil);
  59. procedure MessagePos(const pos:tfileposinfo;w:longint;onqueue:tmsgqueueevent=nil);
  60. procedure MessagePos1(const pos:tfileposinfo;w:longint;const s1:TMsgStr;onqueue:tmsgqueueevent=nil);
  61. procedure MessagePos2(const pos:tfileposinfo;w:longint;const s1,s2:TMsgStr;onqueue:tmsgqueueevent=nil);
  62. procedure MessagePos3(const pos:tfileposinfo;w:longint;const s1,s2,s3:TMsgStr;onqueue:tmsgqueueevent=nil);
  63. procedure MessagePos4(const pos:tfileposinfo;w:longint;const s1,s2,s3,s4:TMsgStr;onqueue:tmsgqueueevent=nil);
  64. { message calls with codegenerror support }
  65. procedure cgmessage(t : longint);
  66. procedure cgmessage1(t : longint;const s : TMsgStr);
  67. procedure cgmessage2(t : longint;const s1,s2 : TMsgStr);
  68. procedure cgmessage3(t : longint;const s1,s2,s3 : TMsgStr);
  69. procedure CGMessagePos(const pos:tfileposinfo;t:longint);
  70. procedure CGMessagePos1(const pos:tfileposinfo;t:longint;const s1:TMsgStr);
  71. procedure CGMessagePos2(const pos:tfileposinfo;t:longint;const s1,s2:TMsgStr);
  72. procedure CGMessagePos3(const pos:tfileposinfo;t:longint;const s1,s2,s3:TMsgStr);
  73. procedure FlushOutput;
  74. procedure InitVerbose;
  75. procedure DoneVerbose;
  76. const
  77. printnodespacing = ' ';
  78. var
  79. { indention used when writing a node tree to the screen }
  80. printnodeindention : string;
  81. { Node dumping support functions }
  82. procedure printnodeindent; inline;
  83. procedure printnodeunindent; inline;
  84. {$ifdef DEBUG_NODE_XML}
  85. function SanitiseXMLString(const S: ansistring): ansistring;
  86. function WritePointer(const P: Pointer): ansistring;
  87. function WriteConstPUInt(const P: TConstPtrUInt): ansistring;
  88. function WriteGUID(const GUID: TGUID): ansistring;
  89. {$endif DEBUG_NODE_XML}
  90. implementation
  91. uses
  92. comphook,fmodule,constexp,globals,cfileutl,switches;
  93. {****************************************************************************
  94. Extra Handlers for default compiler
  95. ****************************************************************************}
  96. procedure DoneRedirectFile;
  97. begin
  98. if status.use_redir then
  99. begin
  100. close(status.redirfile);
  101. status.use_redir:=false;
  102. end;
  103. if status.use_bugreport then
  104. begin
  105. close(status.reportbugfile);
  106. status.use_bugreport:=false;
  107. end;
  108. end;
  109. procedure SetRedirectFile(const fn:string);
  110. begin
  111. { close old redirection file because FileRedirection is handled in both passes }
  112. if status.use_redir then
  113. close(status.redirfile);
  114. assign(status.redirfile,fn);
  115. {$push}{$I-}
  116. append(status.redirfile);
  117. if ioresult <> 0 then
  118. begin
  119. assign(status.redirfile,fn);
  120. rewrite(status.redirfile);
  121. end;
  122. {$pop}
  123. status.use_redir:=(ioresult=0);
  124. end;
  125. procedure PrepareReport;
  126. var
  127. fn : string;
  128. begin
  129. if status.use_bugreport then
  130. exit;
  131. fn:='fpcdebug.txt';
  132. assign(status.reportbugfile,fn);
  133. {$push}{$I-}
  134. append(status.reportbugfile);
  135. if ioresult <> 0 then
  136. rewrite(status.reportbugfile);
  137. {$pop}
  138. status.use_bugreport:=(ioresult=0);
  139. if status.use_bugreport then
  140. writeln(status.reportbugfile,'FPC bug report file');
  141. end;
  142. procedure RestoreLocalVerbosity(pstate : pmessagestaterecord);
  143. begin
  144. msg^.ResetStates;
  145. while assigned(pstate) do
  146. begin
  147. SetMessageVerbosity(pstate^.value,pstate^.state);
  148. pstate:=pstate^.next;
  149. end;
  150. end;
  151. procedure FreeLocalVerbosity(var fstate : pmessagestaterecord);
  152. var pstate : pmessagestaterecord;
  153. begin
  154. pstate:=unaligned(fstate);
  155. while assigned(pstate) do
  156. begin
  157. unaligned(fstate):=pstate^.next;
  158. freemem(pstate);
  159. pstate:=unaligned(fstate);
  160. end;
  161. end;
  162. function ChangeMessageVerbosity(s: ansistring; var i : integer;state:tmsgstate): boolean;
  163. var
  164. tok : ansistring;
  165. msgnr, code : longint;
  166. begin
  167. { delete everything up to and including 'm' }
  168. delete(s,1,i);
  169. { the rest of the string must be message numbers }
  170. inc(i,length(s)+1);
  171. result:=false;
  172. repeat
  173. tok:=GetToken(s,',');
  174. if (tok='') then
  175. break;
  176. val(tok, msgnr, code);
  177. if (code<>0) then
  178. exit;
  179. if not msg^.setverbosity(msgnr,state) then
  180. exit
  181. else
  182. recordpendingmessagestate(msgnr, state);
  183. until false;
  184. result:=true;
  185. end;
  186. function SetMessageVerbosity(v:longint;state:tmsgstate):boolean;
  187. begin
  188. result:=msg^.setverbosity(v,state);
  189. end;
  190. function CheckVerbosity(v:longint):boolean;
  191. begin
  192. result:=do_checkverbosity(v);
  193. end;
  194. function SetVerbosity(const s:TCmdStr):boolean;
  195. const
  196. message_verbosity:array[boolean] of tmsgstate=(ms_off_global,ms_on_global);
  197. var
  198. m : Longint;
  199. i : Integer;
  200. inverse : boolean;
  201. c : char;
  202. begin
  203. Setverbosity:=false;
  204. val(s,m,i);
  205. if (i=0) and (s<>'') then
  206. status.verbosity:=m
  207. else
  208. begin
  209. i:=1;
  210. while i<=length(s) do
  211. begin
  212. c:=upcase(s[i]);
  213. inverse:=false;
  214. { on/off ? }
  215. if (i<length(s)) then
  216. case s[i+1] of
  217. '-' : begin
  218. inc(i);
  219. inverse:=true;
  220. end;
  221. '+' : inc(i);
  222. end;
  223. { handle switch }
  224. case c of
  225. { Special cases }
  226. '0' : status.verbosity:=V_Default;
  227. 'A' : status.verbosity:=V_All;
  228. 'B' : begin
  229. if inverse then
  230. status.print_source_path:=false
  231. else
  232. status.print_source_path:=true;
  233. end;
  234. 'M' : if not ChangeMessageVerbosity(s,i,message_verbosity[inverse]) then
  235. begin
  236. result:=false;
  237. exit
  238. end;
  239. 'P' : begin
  240. if inverse then
  241. paraprintnodetree:=0
  242. else
  243. paraprintnodetree:=1;
  244. end;
  245. 'Q' : begin
  246. if inverse then
  247. status.showmsgnrs:=false
  248. else
  249. status.showmsgnrs:=true;
  250. end;
  251. 'R' : begin
  252. if inverse then
  253. begin
  254. status.use_gccoutput:=false;
  255. status.use_stderr:=false;
  256. end
  257. else
  258. begin
  259. status.use_gccoutput:=true;
  260. status.use_stderr:=true;
  261. end;
  262. end;
  263. 'V' : PrepareReport;
  264. 'Z' : begin
  265. if inverse then
  266. status.use_stderr:=false
  267. else
  268. status.use_stderr:=true;
  269. end;
  270. { Normal cases - do an or }
  271. 'C' : if inverse then
  272. status.verbosity:=status.verbosity and (not V_Conditional)
  273. else
  274. status.verbosity:=status.verbosity or V_Conditional;
  275. 'D' : if inverse then
  276. status.verbosity:=status.verbosity and (not V_Debug)
  277. else
  278. status.verbosity:=status.verbosity or V_Debug;
  279. 'E' : if inverse then
  280. status.verbosity:=status.verbosity and (not V_Error)
  281. else
  282. status.verbosity:=status.verbosity or V_Error;
  283. 'H' : if inverse then
  284. status.verbosity:=status.verbosity and (not V_Hint)
  285. else
  286. status.verbosity:=status.verbosity or V_Hint;
  287. 'I' : if inverse then
  288. status.verbosity:=status.verbosity and (not V_Info)
  289. else
  290. status.verbosity:=status.verbosity or V_Info;
  291. 'L' : if inverse then
  292. status.verbosity:=status.verbosity and (not V_Status)
  293. else
  294. status.verbosity:=status.verbosity or V_Status;
  295. 'N' : if inverse then
  296. status.verbosity:=status.verbosity and (not V_Note)
  297. else
  298. status.verbosity:=status.verbosity or V_Note;
  299. 'S' : if inverse then
  300. status.verbosity:=status.verbosity and (not V_TimeStamps)
  301. else
  302. status.verbosity:=status.verbosity or V_TimeStamps;
  303. 'T' : if inverse then
  304. status.verbosity:=status.verbosity and (not V_Tried)
  305. else
  306. status.verbosity:=status.verbosity or V_Tried;
  307. 'U' : if inverse then
  308. status.verbosity:=status.verbosity and (not V_Used)
  309. else
  310. status.verbosity:=status.verbosity or V_Used;
  311. 'W' : if inverse then
  312. status.verbosity:=status.verbosity and (not V_Warning)
  313. else
  314. status.verbosity:=status.verbosity or V_Warning;
  315. 'X' : if inverse then
  316. status.verbosity:=status.verbosity and (not V_Executable)
  317. else
  318. status.verbosity:=status.verbosity or V_Executable;
  319. end;
  320. inc(i);
  321. end;
  322. end;
  323. if status.verbosity=0 then
  324. status.verbosity:=V_Default;
  325. setverbosity:=true;
  326. end;
  327. procedure Loadprefixes;
  328. function loadprefix(w:longint):string;
  329. var
  330. s : string;
  331. idx : longint;
  332. begin
  333. s:=msg^.get(w,[]);
  334. idx:=pos('_',s);
  335. if idx>0 then
  336. Loadprefix:=Copy(s,idx+1,255)
  337. else
  338. Loadprefix:=s;
  339. end;
  340. begin
  341. { Load the prefixes }
  342. fatalstr:=Loadprefix(general_i_fatal);
  343. errorstr:=Loadprefix(general_i_error);
  344. warningstr:=Loadprefix(general_i_warning);
  345. notestr:=Loadprefix(general_i_note);
  346. hintstr:=Loadprefix(general_i_hint);
  347. end;
  348. procedure LoadMsgFile(const fn:string);
  349. begin
  350. { reload the internal messages if not already loaded }
  351. {$ifndef EXTERN_MSG}
  352. if not msg^.msgintern then
  353. msg^.LoadIntern(@msgtxt,msgtxtsize,msgtxt_codepage);
  354. {$endif}
  355. if not msg^.LoadExtern(fn) then
  356. begin
  357. {$ifdef EXTERN_MSG}
  358. writeln('Fatal: Cannot find error message file.');
  359. halt(3);
  360. {$else}
  361. msg^.LoadIntern(@msgtxt,msgtxtsize,msgtxt_codepage);
  362. {$endif}
  363. end;
  364. { reload the prefixes using the new messages }
  365. Loadprefixes;
  366. end;
  367. procedure MaybeLoadMessageFile;
  368. begin
  369. { Load new message file }
  370. if (msgfilename<>'') then
  371. begin
  372. LoadMsgFile(msgfilename);
  373. msgfilename:='';
  374. end;
  375. end;
  376. var
  377. lastfileidx,
  378. lastmoduleidx : longint;
  379. Procedure UpdateStatus;
  380. var
  381. module : tmodule;
  382. begin
  383. { fix status }
  384. status.currentline:=current_filepos.line;
  385. status.currentcolumn:=current_filepos.column;
  386. if (current_filepos.moduleindex <> lastmoduleidx) or
  387. (current_filepos.fileindex <> lastfileidx) then
  388. begin
  389. module:=get_module(current_filepos.moduleindex);
  390. if assigned(module) and assigned(module.sourcefiles) then
  391. begin
  392. { update status record }
  393. status.currentmodule:=module.modulename^;
  394. status.currentsourceppufilename:=module.ppufilename;
  395. status.currentmodulestate:=ModuleStateStr[module.state];
  396. status.currentsource:=module.sourcefiles.get_file_name(current_filepos.fileindex);
  397. status.currentsourcepath:=module.sourcefiles.get_file_path(current_filepos.fileindex);
  398. status.sources_avail:=module.sources_avail;
  399. { if currentsourcepath is relative, make it absolute }
  400. if not path_absolute(status.currentsourcepath) then
  401. status.currentsourcepath:=GetCurrentDir+status.currentsourcepath;
  402. { update lastfileidx only if name known PM }
  403. if status.currentsource<>'' then
  404. lastfileidx:=current_filepos.fileindex
  405. else
  406. lastfileidx:=0;
  407. lastmoduleidx:=module.unit_index;
  408. end;
  409. end;
  410. end;
  411. procedure ShowStatus;
  412. begin
  413. UpdateStatus;
  414. if do_status() then
  415. raise ECompilerAbort.Create;
  416. end;
  417. function ErrorCount:longint;
  418. begin
  419. ErrorCount:=status.errorcount;
  420. end;
  421. procedure SetErrorFlags(const s:string);
  422. var
  423. code : integer;
  424. i,j,l : longint;
  425. begin
  426. { empty string means error count = 1 for backward compatibility (PFV) }
  427. if s='' then
  428. begin
  429. status.maxerrorcount:=1;
  430. exit;
  431. end;
  432. i:=0;
  433. while (i<length(s)) do
  434. begin
  435. inc(i);
  436. case s[i] of
  437. '0'..'9' :
  438. begin
  439. j:=i;
  440. while (j<=length(s)) and (s[j] in ['0'..'9']) do
  441. inc(j);
  442. val(copy(s,i,j-i),l,code);
  443. if code<>0 then
  444. l:=1;
  445. status.maxerrorcount:=l;
  446. i:=j-1;
  447. end;
  448. 'w','W' :
  449. begin
  450. if (i<length(s)) and (s[i+1]='-') then
  451. begin
  452. inc(i);
  453. status.errorwarning:=false;
  454. end
  455. else
  456. begin
  457. status.errorwarning:=true;
  458. { Enable writing of warnings, to avoid getting errors without any message }
  459. status.verbosity:=status.verbosity or V_Warning;
  460. end;
  461. end;
  462. 'n','N' :
  463. begin
  464. if (i<length(s)) and (s[i+1]='-') then
  465. begin
  466. inc(i);
  467. status.errornote:=false;
  468. end
  469. else
  470. begin
  471. status.errornote:=true;
  472. { Enable writing of notes, to avoid getting errors without any message }
  473. status.verbosity:=status.verbosity or V_Note;
  474. end;
  475. end;
  476. 'h','H' :
  477. begin
  478. if (i<length(s)) and (s[i+1]='-') then
  479. begin
  480. inc(i);
  481. status.errorhint:=false;
  482. end
  483. else
  484. begin
  485. status.errorhint:=true;
  486. { Enable writing of hints, to avoid getting errors without any message }
  487. status.verbosity:=status.verbosity or V_Hint;
  488. end;
  489. end;
  490. end;
  491. end;
  492. end;
  493. procedure GenerateError;
  494. begin
  495. inc(status.errorcount);
  496. end;
  497. procedure internalerror(i : longint);noreturn;
  498. procedure doraise;
  499. begin
  500. raise ECompilerAbort.Create;
  501. end;
  502. begin
  503. UpdateStatus;
  504. do_internalerror(i);
  505. GenerateError;
  506. doraise;
  507. end;
  508. procedure Comment(l:longint;s:ansistring);
  509. var
  510. dostop : boolean;
  511. begin
  512. dostop:=((l and V_Fatal)<>0);
  513. if ((l and V_Error)<>0) or
  514. ((l and V_Fatal)<>0) or
  515. (status.errorwarning and ((l and V_Warning)<>0)) or
  516. (status.errornote and ((l and V_Note)<>0)) or
  517. (status.errorhint and ((l and V_Hint)<>0)) then
  518. GenerateError
  519. else
  520. if l and V_Warning <> 0 then
  521. inc(status.countWarnings)
  522. else
  523. if l and V_Note <> 0 then
  524. inc(status.countNotes)
  525. else
  526. if l and V_Hint <> 0 then
  527. inc(status.countHints);
  528. { check verbosity level }
  529. if not CheckVerbosity(l) then
  530. exit;
  531. if (l and V_LineInfoMask)<>0 then
  532. l:=l or V_LineInfo;
  533. { Create status info }
  534. UpdateStatus;
  535. { Fix replacements }
  536. DefaultReplacements(s,false);
  537. { show comment }
  538. if do_comment(l,s) or dostop then
  539. raise ECompilerAbort.Create;
  540. if (status.errorcount>=status.maxerrorcount) and not status.skip_error then
  541. begin
  542. Message1(unit_f_errors_in_unit,tostr(status.errorcount));
  543. status.skip_error:=true;
  544. raise ECompilerAbort.Create;
  545. end;
  546. end;
  547. function GetMessageState(m:longint):tmsgstate;
  548. var
  549. i: integer;
  550. begin
  551. i:=m div 1000;
  552. { get the default state }
  553. Result:=msg^.msgstates[i]^[m mod 1000];
  554. { and search at the current unit settings }
  555. { todo }
  556. end;
  557. Procedure Msg2Comment(s:ansistring;w:longint;onqueue:tmsgqueueevent);
  558. var
  559. idx,i,v : longint;
  560. dostop : boolean;
  561. doqueue : boolean;
  562. st : tmsgstate;
  563. ch : char;
  564. begin
  565. {Reset}
  566. dostop:=false;
  567. doqueue:=false;
  568. v:=0;
  569. {Parse options}
  570. idx:=pos('_',s);
  571. if idx=0 then
  572. v:=V_None
  573. else
  574. if (idx >= 1) And (idx <= 5) then
  575. begin
  576. for i:=1 to idx do
  577. begin
  578. ch:=upcase(s[i]);
  579. case ch of
  580. 'F' :
  581. begin
  582. v:=v or V_Fatal;
  583. GenerateError;
  584. dostop:=true;
  585. end;
  586. 'E','W','N','H':
  587. begin
  588. if ch='E' then
  589. st:=ms_error
  590. else
  591. st:=GetMessageState(w);
  592. { We only want to know about local value }
  593. st:= tmsgstate(ord(st) and ms_local_mask);
  594. if st=ms_error then
  595. begin
  596. v:=v or V_Error;
  597. GenerateError;
  598. end
  599. else if st<>ms_off then
  600. case ch of
  601. 'W':
  602. begin
  603. v:=v or V_Warning;
  604. if CheckVerbosity(V_Warning) then
  605. if status.errorwarning then
  606. GenerateError
  607. else
  608. inc(status.countWarnings);
  609. end;
  610. 'N' :
  611. begin
  612. v:=v or V_Note;
  613. if CheckVerbosity(V_Note) then
  614. if status.errornote then
  615. GenerateError
  616. else
  617. inc(status.countNotes);
  618. end;
  619. 'H' :
  620. begin
  621. v:=v or V_Hint;
  622. if CheckVerbosity(V_Hint) then
  623. if status.errorhint then
  624. GenerateError
  625. else
  626. inc(status.countHints);
  627. end;
  628. end;
  629. end;
  630. 'O' :
  631. v:=v or V_Normal;
  632. 'I' :
  633. v:=v or V_Info;
  634. 'L' :
  635. v:=v or V_LineInfo;
  636. 'U' :
  637. v:=v or V_Used;
  638. 'T' :
  639. v:=v or V_Tried;
  640. 'C' :
  641. v:=v or V_Conditional;
  642. 'D' :
  643. v:=v or V_Debug;
  644. 'X' :
  645. v:=v or V_Executable;
  646. 'S' :
  647. dostop:=true;
  648. '_' : ;
  649. end;
  650. end;
  651. end;
  652. Delete(s,1,idx);
  653. { check verbosity level }
  654. if not CheckVerbosity(v) then
  655. begin
  656. doqueue := onqueue <> nil;
  657. if not doqueue then
  658. exit;
  659. end;
  660. if (v and V_LineInfoMask)<>0 then
  661. v:=v or V_LineInfo;
  662. { fix status }
  663. UpdateStatus;
  664. { Fix replacements }
  665. DefaultReplacements(s,false);
  666. if status.showmsgnrs and ((v and V_Normal)=0) then
  667. s:='('+tostr(w)+') '+s;
  668. if doqueue then
  669. begin
  670. onqueue(s,v,w);
  671. exit;
  672. end;
  673. { show comment }
  674. if do_comment(v,s) or dostop then
  675. raise ECompilerAbort.Create;
  676. if (status.errorcount>=status.maxerrorcount) and not status.skip_error then
  677. begin
  678. Message1(unit_f_errors_in_unit,tostr(status.errorcount));
  679. status.skip_error:=true;
  680. raise ECompilerAbort.Create;
  681. end;
  682. end;
  683. function MessageStr(w:longint):TMsgStr;
  684. begin
  685. MaybeLoadMessageFile;
  686. MessageStr:=msg^.Get(w,[]);
  687. end;
  688. procedure Message(w:longint;onqueue:tmsgqueueevent=nil);
  689. begin
  690. MaybeLoadMessageFile;
  691. Msg2Comment(msg^.Get(w,[]),w,onqueue);
  692. end;
  693. procedure Message1(w:longint;const s1:TMsgStr;onqueue:tmsgqueueevent=nil);
  694. begin
  695. MaybeLoadMessageFile;
  696. Msg2Comment(msg^.Get(w,[s1]),w,onqueue);
  697. end;
  698. procedure Message2(w:longint;const s1,s2:TMsgStr;onqueue:tmsgqueueevent=nil);
  699. begin
  700. MaybeLoadMessageFile;
  701. Msg2Comment(msg^.Get(w,[s1,s2]),w,onqueue);
  702. end;
  703. procedure Message3(w:longint;const s1,s2,s3:TMsgStr;onqueue:tmsgqueueevent=nil);
  704. begin
  705. MaybeLoadMessageFile;
  706. Msg2Comment(msg^.Get(w,[s1,s2,s3]),w,onqueue);
  707. end;
  708. procedure Message4(w:longint;const s1,s2,s3,s4:TMsgStr;onqueue:tmsgqueueevent=nil);
  709. begin
  710. MaybeLoadMessageFile;
  711. Msg2Comment(msg^.Get(w,[s1,s2,s3,s4]),w,onqueue);
  712. end;
  713. procedure MessagePos(const pos:tfileposinfo;w:longint;onqueue:tmsgqueueevent=nil);
  714. var
  715. oldpos : tfileposinfo;
  716. begin
  717. oldpos:=current_filepos;
  718. current_filepos:=pos;
  719. MaybeLoadMessageFile;
  720. Msg2Comment(msg^.Get(w,[]),w,onqueue);
  721. current_filepos:=oldpos;
  722. end;
  723. procedure MessagePos1(const pos:tfileposinfo;w:longint;const s1:TMsgStr;onqueue:tmsgqueueevent=nil);
  724. var
  725. oldpos : tfileposinfo;
  726. begin
  727. oldpos:=current_filepos;
  728. current_filepos:=pos;
  729. MaybeLoadMessageFile;
  730. Msg2Comment(msg^.Get(w,[s1]),w,onqueue);
  731. current_filepos:=oldpos;
  732. end;
  733. procedure MessagePos2(const pos:tfileposinfo;w:longint;const s1,s2:TMsgStr;onqueue:tmsgqueueevent=nil);
  734. var
  735. oldpos : tfileposinfo;
  736. begin
  737. oldpos:=current_filepos;
  738. current_filepos:=pos;
  739. MaybeLoadMessageFile;
  740. Msg2Comment(msg^.Get(w,[s1,s2]),w,onqueue);
  741. current_filepos:=oldpos;
  742. end;
  743. procedure MessagePos3(const pos:tfileposinfo;w:longint;const s1,s2,s3:TMsgStr;onqueue:tmsgqueueevent=nil);
  744. var
  745. oldpos : tfileposinfo;
  746. begin
  747. oldpos:=current_filepos;
  748. current_filepos:=pos;
  749. MaybeLoadMessageFile;
  750. Msg2Comment(msg^.Get(w,[s1,s2,s3]),w,onqueue);
  751. current_filepos:=oldpos;
  752. end;
  753. procedure MessagePos4(const pos:tfileposinfo;w:longint;const s1,s2,s3,s4:TMsgStr;onqueue:tmsgqueueevent=nil);
  754. var
  755. oldpos : tfileposinfo;
  756. begin
  757. oldpos:=current_filepos;
  758. current_filepos:=pos;
  759. MaybeLoadMessageFile;
  760. Msg2Comment(msg^.Get(w,[s1,s2,s3,s4]),w,onqueue);
  761. current_filepos:=oldpos;
  762. end;
  763. {*****************************************************************************
  764. override the message calls to set codegenerror
  765. *****************************************************************************}
  766. procedure cgmessage(t : longint);
  767. var
  768. olderrorcount : longint;
  769. begin
  770. if not(codegenerror) then
  771. begin
  772. olderrorcount:=Errorcount;
  773. verbose.Message(t);
  774. codegenerror:=olderrorcount<>Errorcount;
  775. end;
  776. end;
  777. procedure cgmessage1(t : longint;const s : TMsgStr);
  778. var
  779. olderrorcount : longint;
  780. begin
  781. if not(codegenerror) then
  782. begin
  783. olderrorcount:=Errorcount;
  784. verbose.Message1(t,s);
  785. codegenerror:=olderrorcount<>Errorcount;
  786. end;
  787. end;
  788. procedure cgmessage2(t : longint;const s1,s2 : TMsgStr);
  789. var
  790. olderrorcount : longint;
  791. begin
  792. if not(codegenerror) then
  793. begin
  794. olderrorcount:=Errorcount;
  795. verbose.Message2(t,s1,s2);
  796. codegenerror:=olderrorcount<>Errorcount;
  797. end;
  798. end;
  799. procedure cgmessage3(t : longint;const s1,s2,s3 : TMsgStr);
  800. var
  801. olderrorcount : longint;
  802. begin
  803. if not(codegenerror) then
  804. begin
  805. olderrorcount:=Errorcount;
  806. verbose.Message3(t,s1,s2,s3);
  807. codegenerror:=olderrorcount<>Errorcount;
  808. end;
  809. end;
  810. procedure cgmessagepos(const pos:tfileposinfo;t : longint);
  811. var
  812. olderrorcount : longint;
  813. begin
  814. if not(codegenerror) then
  815. begin
  816. olderrorcount:=Errorcount;
  817. verbose.MessagePos(pos,t);
  818. codegenerror:=olderrorcount<>Errorcount;
  819. end;
  820. end;
  821. procedure cgmessagepos1(const pos:tfileposinfo;t : longint;const s1 : TMsgStr);
  822. var
  823. olderrorcount : longint;
  824. begin
  825. if not(codegenerror) then
  826. begin
  827. olderrorcount:=Errorcount;
  828. verbose.MessagePos1(pos,t,s1);
  829. codegenerror:=olderrorcount<>Errorcount;
  830. end;
  831. end;
  832. procedure cgmessagepos2(const pos:tfileposinfo;t : longint;const s1,s2 : TMsgStr);
  833. var
  834. olderrorcount : longint;
  835. begin
  836. if not(codegenerror) then
  837. begin
  838. olderrorcount:=Errorcount;
  839. verbose.MessagePos2(pos,t,s1,s2);
  840. codegenerror:=olderrorcount<>Errorcount;
  841. end;
  842. end;
  843. procedure cgmessagepos3(const pos:tfileposinfo;t : longint;const s1,s2,s3 : TMsgStr);
  844. var
  845. olderrorcount : longint;
  846. begin
  847. if not(codegenerror) then
  848. begin
  849. olderrorcount:=Errorcount;
  850. verbose.MessagePos3(pos,t,s1,s2,s3);
  851. codegenerror:=olderrorcount<>Errorcount;
  852. end;
  853. end;
  854. procedure FlushOutput;
  855. begin
  856. if not (Status.Use_StdErr) then (* StdErr is flushed after every line *)
  857. begin
  858. if Status.Use_Redir then
  859. Flush(Status.RedirFile)
  860. else
  861. Flush(Output);
  862. end;
  863. end;
  864. {*****************************************************************************
  865. Initialization
  866. *****************************************************************************}
  867. procedure InitVerbose;
  868. begin
  869. { Init }
  870. msg:=new(pmessage,Init(20,msgidxmax));
  871. if msg=nil then
  872. begin
  873. writeln('Fatal: MsgIdx Wrong');
  874. halt(3);
  875. end;
  876. {$ifndef EXTERN_MSG}
  877. msg^.LoadIntern(@msgtxt,msgtxtsize,msgtxt_codepage);
  878. {$else EXTERN_MSG}
  879. LoadMsgFile(exepath+'errore.msg');
  880. {$endif EXTERN_MSG}
  881. FillChar(Status,sizeof(TCompilerStatus),0);
  882. status.verbosity:=V_Default;
  883. Status.MaxErrorCount:=50;
  884. Status.codesize:=aword(-1);
  885. Status.datasize:=aword(-1);
  886. Loadprefixes;
  887. lastfileidx:=-1;
  888. lastmoduleidx:=-1;
  889. status.currentmodule:='';
  890. status.currentsourceppufilename:='';
  891. status.currentsource:='';
  892. status.currentsourcepath:='';
  893. { Register internalerrorproc for cutils/cclasses }
  894. internalerrorproc:=@internalerror;
  895. end;
  896. procedure DoneVerbose;
  897. begin
  898. if assigned(msg) then
  899. begin
  900. dispose(msg,Done);
  901. msg:=nil;
  902. end;
  903. DoneRedirectFile;
  904. end;
  905. procedure printnodeindent; inline;
  906. begin
  907. printnodeindention:=printnodeindention+printnodespacing;
  908. end;
  909. procedure printnodeunindent; inline;
  910. begin
  911. delete(printnodeindention,1,length(printnodespacing));
  912. end;
  913. {$ifdef DEBUG_NODE_XML}
  914. function WritePointer(const P: Pointer): ansistring;
  915. begin
  916. case PtrUInt(P) of
  917. 0:
  918. WritePointer := 'nil';
  919. 1..$FFFF:
  920. WritePointer := '$' + hexstr(PtrUInt(P), 4);
  921. {$if sizeof(Pointer) >= 4}
  922. $10000..$FFFFFFFF:
  923. WritePointer := '$' + hexstr(PtrUInt(P), 8);
  924. {$ifend sizeof(Pointer) >= 4}
  925. {$if sizeof(Pointer) > 4}
  926. else
  927. WritePointer := '$' + hexstr(PtrUInt(P), 2*sizeof(Pointer));
  928. {$ifend sizeof(Pointer) > 4}
  929. end;
  930. end;
  931. function WriteConstPUInt(const P: TConstPtrUInt): ansistring;
  932. begin
  933. case P of
  934. 0:
  935. WriteConstPUInt := 'nil';
  936. 1..$FFFF:
  937. WriteConstPUInt := '$' + hexstr(P, 4);
  938. {$if sizeof(TConstPtrUInt) >= 4}
  939. $10000..$FFFFFFFF:
  940. WriteConstPUInt := '$' + hexstr(P, 8);
  941. {$ifend sizeof(TConstPtrUInt) >= 4}
  942. {$if sizeof(TConstPtrUInt) > 4}
  943. else
  944. WriteConstPUInt := '$' + hexstr(P, 2*sizeof(TConstPtrUInt));
  945. {$endif sizeof(TConstPtrUInt) > 4}
  946. end;
  947. end;
  948. function WriteGUID(const GUID: TGUID): ansistring;
  949. var
  950. i: Integer;
  951. begin
  952. Result := '{' + hexstr(GUID.D1, 8) + '-' + hexstr(GUID.D2, 4) + '-' + hexstr(GUID.D3, 4) + '-';
  953. for i := 0 to 7 do
  954. Result := Result + hexstr(GUID.D4[i], 2);
  955. Result := Result + '}';
  956. end;
  957. function SanitiseXMLString(const S: ansistring): ansistring;
  958. var
  959. X, UTF8Len, UTF8Char, CurrentChar: Integer;
  960. needs_quoting, in_quotes, add_end_quote: Boolean;
  961. DoASCII: Boolean;
  962. { Write the given byte as #xxx }
  963. procedure EncodeControlChar(Value: Byte);
  964. begin
  965. if X = Length(Result) then
  966. add_end_quote := False;
  967. Delete(Result, X, 1);
  968. if in_quotes then
  969. begin
  970. Insert('#' + tostr(Value) + '''', Result, X);
  971. { If the entire string consists of control characters, it
  972. doesn't need quoting, so only set the flag here }
  973. needs_quoting := True;
  974. in_quotes := False;
  975. end
  976. else
  977. Insert('#' + tostr(Value), Result, X);
  978. end;
  979. { Write the given byte as either a plain character or an XML keyword }
  980. procedure EncodeStandardChar(Value: Byte);
  981. begin
  982. if not in_quotes then
  983. begin
  984. in_quotes := True;
  985. if (X < Length(Result)) then
  986. begin
  987. needs_quoting := True;
  988. Insert('''', Result, X + 1)
  989. end;
  990. end;
  991. { Check the character for anything that could be mistaken for an XML element }
  992. case CurrentChar of
  993. Ord('#'):
  994. { Required to differentiate '#27' from the escape code #27, for example }
  995. needs_quoting:=true;
  996. Ord('<'):
  997. begin
  998. Delete(Result, X, 1);
  999. Insert('&lt;', Result, X);
  1000. end;
  1001. Ord('>'):
  1002. begin
  1003. Delete(Result, X, 1);
  1004. Insert('&gt;', Result, X);
  1005. end;
  1006. Ord('&'):
  1007. begin
  1008. Delete(Result, X, 1);
  1009. Insert('&amp;', Result, X);
  1010. end;
  1011. Ord('"'):
  1012. begin
  1013. needs_quoting := True;
  1014. Delete(Result, X, 1);
  1015. Insert('&quot;', Result, X);
  1016. end;
  1017. Ord(''''):
  1018. begin
  1019. needs_quoting:=true;
  1020. { Simply double it like in pascal strings }
  1021. Insert('''', Result, X);
  1022. end;
  1023. else
  1024. { Do nothing };
  1025. end;
  1026. end;
  1027. { Convert character between $80 and $FF to UTF-8 }
  1028. procedure EncodeExtendedChar(Value: Byte);
  1029. begin
  1030. if not in_quotes then
  1031. begin
  1032. in_quotes := True;
  1033. if (X < Length(Result)) then
  1034. begin
  1035. needs_quoting := True;
  1036. Insert('''', Result, X + 1)
  1037. end;
  1038. end;
  1039. case Value of
  1040. $80..$BF: { Add $C2 before the value }
  1041. Insert(#$C2, Result, X);
  1042. $C0..$FF: { Zero the $40 bit and add $C3 before the value }
  1043. begin
  1044. Result[X] := Char(Byte(Result[X]) and $BF);
  1045. Insert(#$C3, Result, X);
  1046. end;
  1047. else
  1048. { Previous conditions should prevent this procedure from being
  1049. called if Value < $80 }
  1050. InternalError(2019061901);
  1051. end;
  1052. end;
  1053. begin
  1054. needs_quoting := False;
  1055. Result := S;
  1056. { Gets set to True if an invalid UTF-8 sequence is found }
  1057. DoASCII := False;
  1058. { By setting in_quotes to false here, we can exclude the single
  1059. quotation marks surrounding the string if it doesn't contain any
  1060. control characters, or consists entirely of control characters. }
  1061. in_quotes := False;
  1062. add_end_quote := True;
  1063. X := Length(Result);
  1064. while X > 0 do
  1065. begin
  1066. CurrentChar := Ord(Result[X]);
  1067. { Control characters and extended characters need special handling }
  1068. case CurrentChar of
  1069. $00..$1F, $7F:
  1070. EncodeControlChar(CurrentChar);
  1071. $20..$7E:
  1072. EncodeStandardChar(CurrentChar);
  1073. { UTF-8 continuation byte }
  1074. $80..$BF:
  1075. begin
  1076. if not in_quotes then
  1077. begin
  1078. in_quotes := True;
  1079. if (X < Length(Result)) then
  1080. begin
  1081. needs_quoting := True;
  1082. Insert('''', Result, X + 1)
  1083. end;
  1084. end;
  1085. UTF8Char := CurrentChar and $3F; { The data bits of the continuation byte }
  1086. UTF8Len := 1; { This variable actually holds 1 less than the length }
  1087. { By setting DoASCII to true, it marks the string as 'invalid UTF-8'
  1088. automatically if it reaches the beginning of the string unexpectedly }
  1089. DoASCII := True;
  1090. Dec(X);
  1091. while X > 0 do
  1092. begin
  1093. CurrentChar := Ord(Result[X]);
  1094. case CurrentChar of
  1095. { A standard character here is invalid UTF-8 }
  1096. $00..$7F:
  1097. Break;
  1098. { Another continuation byte }
  1099. $80..$BF:
  1100. begin
  1101. UTF8Char := UTF8Char or ((CurrentChar and $3F) shl (6 * UTF8Len));
  1102. dec(X);
  1103. Inc(UTF8Len);
  1104. if UTF8Len >= 4 then
  1105. { Sequence too long }
  1106. Break;
  1107. end;
  1108. { Lead byte for 2-byte sequences }
  1109. $C2..$DF:
  1110. begin
  1111. if UTF8Len <> 1 then Break;
  1112. UTF8Char := UTF8Char or ((CurrentChar and $1F) shl 6);
  1113. { Check to see if the code is in range and not part of an 'overlong' sequence }
  1114. case UTF8Char of
  1115. $0080..$07FF:
  1116. DoASCII := False;
  1117. else
  1118. { Do nothing - DoASCII is already true }
  1119. end;
  1120. Break;
  1121. end;
  1122. { Lead byte for 3-byte sequences }
  1123. $E0..$EF:
  1124. begin
  1125. if UTF8Len <> 2 then Break;
  1126. UTF8Char := UTF8Char or ((CurrentChar and $0F) shl 12);
  1127. { Check to see if the code is in range and not part of an 'overlong' sequence }
  1128. case UTF8Char of
  1129. $0800..$D7FF, $E000..$FFFF: { $D800..$DFFF is reserved and hence invalid }
  1130. DoASCII := False;
  1131. else
  1132. { Do nothing - DoASCII is already true }
  1133. end;
  1134. Break;
  1135. end;
  1136. { Lead byte for 4-byte sequences }
  1137. $F0..$F4:
  1138. begin
  1139. if UTF8Len <> 3 then Break;
  1140. UTF8Char := UTF8Char or ((CurrentChar and $07) shl 18);
  1141. { Check to see if the code is in range and not part of an 'overlong' sequence }
  1142. case UTF8Char of
  1143. $010000..$10FFFF:
  1144. DoASCII := False;
  1145. else
  1146. { Do nothing - DoASCII is already true }
  1147. end;
  1148. Break;
  1149. end;
  1150. { Invalid character }
  1151. else
  1152. Break;
  1153. end;
  1154. end;
  1155. if DoASCII then
  1156. Break;
  1157. { If all is fine, we don't need to encode any more characters }
  1158. end;
  1159. { Invalid UTF-8 bytes and lead bytes without continuation bytes }
  1160. $C0..$FF:
  1161. begin
  1162. DoASCII := True;
  1163. Break;
  1164. end;
  1165. end;
  1166. Dec(X);
  1167. end;
  1168. { UTF-8 failed, so encode the string as plain ASCII }
  1169. if DoASCII then
  1170. begin
  1171. { Reset the flags and Result }
  1172. needs_quoting := False;
  1173. Result := S;
  1174. in_quotes := False;
  1175. add_end_quote := True;
  1176. for X := Length(Result) downto 1 do
  1177. begin
  1178. CurrentChar := Ord(Result[X]);
  1179. { Control characters and extended characters need special handling }
  1180. case CurrentChar of
  1181. $00..$1F, $7F:
  1182. EncodeControlChar(CurrentChar);
  1183. $20..$7E:
  1184. EncodeStandardChar(CurrentChar);
  1185. { Extended characters }
  1186. else
  1187. EncodeExtendedChar(CurrentChar);
  1188. end;
  1189. end;
  1190. end;
  1191. if needs_quoting then
  1192. begin
  1193. if in_quotes then
  1194. Result := '''' + Result;
  1195. if add_end_quote then
  1196. Result := Result + '''';
  1197. end;
  1198. end;
  1199. {$endif DEBUG_NODE_XML}
  1200. initialization
  1201. constexp.internalerrorproc:=@internalerror;
  1202. finalization
  1203. { Be sure to close the redirect files to flush all data }
  1204. DoneRedirectFile;
  1205. end.