verbose.pas 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377
  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. 'J' : if inverse then
  292. status.verbosity:=status.verbosity and (not V_Parallel)
  293. else
  294. status.verbosity:=status.verbosity or V_Parallel;
  295. 'L' : if inverse then
  296. status.verbosity:=status.verbosity and (not V_Status)
  297. else
  298. status.verbosity:=status.verbosity or V_Status;
  299. 'N' : if inverse then
  300. status.verbosity:=status.verbosity and (not V_Note)
  301. else
  302. status.verbosity:=status.verbosity or V_Note;
  303. 'S' : if inverse then
  304. status.verbosity:=status.verbosity and (not V_TimeStamps)
  305. else
  306. status.verbosity:=status.verbosity or V_TimeStamps;
  307. 'T' : if inverse then
  308. status.verbosity:=status.verbosity and (not V_Tried)
  309. else
  310. status.verbosity:=status.verbosity or V_Tried;
  311. 'U' : if inverse then
  312. status.verbosity:=status.verbosity and (not V_Used)
  313. else
  314. status.verbosity:=status.verbosity or V_Used;
  315. 'W' : if inverse then
  316. status.verbosity:=status.verbosity and (not V_Warning)
  317. else
  318. status.verbosity:=status.verbosity or V_Warning;
  319. 'X' : if inverse then
  320. status.verbosity:=status.verbosity and (not V_Executable)
  321. else
  322. status.verbosity:=status.verbosity or V_Executable;
  323. end;
  324. inc(i);
  325. end;
  326. end;
  327. if status.verbosity=0 then
  328. status.verbosity:=V_Default;
  329. setverbosity:=true;
  330. end;
  331. procedure Loadprefixes;
  332. function loadprefix(w:longint):string;
  333. var
  334. s : string;
  335. idx : longint;
  336. begin
  337. s:=msg^.get(w,[]);
  338. idx:=pos('_',s);
  339. if idx>0 then
  340. Loadprefix:=Copy(s,idx+1,255)
  341. else
  342. Loadprefix:=s;
  343. end;
  344. begin
  345. { Load the prefixes }
  346. fatalstr:=Loadprefix(general_i_fatal);
  347. errorstr:=Loadprefix(general_i_error);
  348. warningstr:=Loadprefix(general_i_warning);
  349. notestr:=Loadprefix(general_i_note);
  350. hintstr:=Loadprefix(general_i_hint);
  351. end;
  352. procedure LoadMsgFile(const fn:string);
  353. begin
  354. { reload the internal messages if not already loaded }
  355. {$ifndef EXTERN_MSG}
  356. if not msg^.msgintern then
  357. msg^.LoadIntern(@msgtxt,msgtxtsize,msgtxt_codepage);
  358. {$endif}
  359. if not msg^.LoadExtern(fn) then
  360. begin
  361. {$ifdef EXTERN_MSG}
  362. writeln('Fatal: Cannot find error message file.');
  363. halt(3);
  364. {$else}
  365. msg^.LoadIntern(@msgtxt,msgtxtsize,msgtxt_codepage);
  366. {$endif}
  367. end;
  368. { reload the prefixes using the new messages }
  369. Loadprefixes;
  370. end;
  371. procedure MaybeLoadMessageFile;
  372. begin
  373. { Load new message file }
  374. if (msgfilename<>'') then
  375. begin
  376. LoadMsgFile(msgfilename);
  377. msgfilename:='';
  378. end;
  379. end;
  380. var
  381. lastfileidx,
  382. lastmoduleidx : longint;
  383. Procedure UpdateStatus;
  384. var
  385. module : tmodule;
  386. begin
  387. { fix status }
  388. status.currentline:=current_filepos.line;
  389. status.currentcolumn:=current_filepos.column;
  390. if (current_filepos.moduleindex <> lastmoduleidx) or
  391. (current_filepos.fileindex <> lastfileidx) then
  392. begin
  393. module:=get_module(current_filepos.moduleindex);
  394. if assigned(module) and assigned(module.sourcefiles) then
  395. begin
  396. { update status record }
  397. status.currentmodule:=module.modulename^;
  398. status.currentsourceppufilename:=module.ppufilename;
  399. status.currentmodulestate:=ModuleStateStr[module.state];
  400. status.currentsource:=module.sourcefiles.get_file_name(current_filepos.fileindex);
  401. status.currentsourcepath:=module.sourcefiles.get_file_path(current_filepos.fileindex);
  402. status.sources_avail:=module.sources_avail;
  403. { if currentsourcepath is relative, make it absolute }
  404. if not path_absolute(status.currentsourcepath) then
  405. status.currentsourcepath:=GetCurrentDir+status.currentsourcepath;
  406. { update lastfileidx only if name known PM }
  407. if status.currentsource<>'' then
  408. lastfileidx:=current_filepos.fileindex
  409. else
  410. lastfileidx:=0;
  411. lastmoduleidx:=module.unit_index;
  412. end;
  413. end;
  414. end;
  415. procedure ShowStatus;
  416. begin
  417. UpdateStatus;
  418. if do_status() then
  419. raise ECompilerAbort.Create;
  420. end;
  421. function ErrorCount:longint;
  422. begin
  423. ErrorCount:=status.errorcount;
  424. end;
  425. procedure SetErrorFlags(const s:string);
  426. var
  427. code : integer;
  428. i,j,l : longint;
  429. begin
  430. { empty string means error count = 1 for backward compatibility (PFV) }
  431. if s='' then
  432. begin
  433. status.maxerrorcount:=1;
  434. exit;
  435. end;
  436. i:=0;
  437. while (i<length(s)) do
  438. begin
  439. inc(i);
  440. case s[i] of
  441. '0'..'9' :
  442. begin
  443. j:=i;
  444. while (j<=length(s)) and (s[j] in ['0'..'9']) do
  445. inc(j);
  446. val(copy(s,i,j-i),l,code);
  447. if code<>0 then
  448. l:=1;
  449. status.maxerrorcount:=l;
  450. i:=j-1;
  451. end;
  452. 'w','W' :
  453. begin
  454. if (i<length(s)) and (s[i+1]='-') then
  455. begin
  456. inc(i);
  457. status.errorwarning:=false;
  458. end
  459. else
  460. begin
  461. status.errorwarning:=true;
  462. { Enable writing of warnings, to avoid getting errors without any message }
  463. status.verbosity:=status.verbosity or V_Warning;
  464. end;
  465. end;
  466. 'n','N' :
  467. begin
  468. if (i<length(s)) and (s[i+1]='-') then
  469. begin
  470. inc(i);
  471. status.errornote:=false;
  472. end
  473. else
  474. begin
  475. status.errornote:=true;
  476. { Enable writing of notes, to avoid getting errors without any message }
  477. status.verbosity:=status.verbosity or V_Note;
  478. end;
  479. end;
  480. 'h','H' :
  481. begin
  482. if (i<length(s)) and (s[i+1]='-') then
  483. begin
  484. inc(i);
  485. status.errorhint:=false;
  486. end
  487. else
  488. begin
  489. status.errorhint:=true;
  490. { Enable writing of hints, to avoid getting errors without any message }
  491. status.verbosity:=status.verbosity or V_Hint;
  492. end;
  493. end;
  494. end;
  495. end;
  496. end;
  497. procedure GenerateError;
  498. begin
  499. inc(status.errorcount);
  500. end;
  501. procedure internalerror(i : longint);noreturn;
  502. procedure doraise;
  503. begin
  504. raise ECompilerAbort.Create;
  505. end;
  506. begin
  507. UpdateStatus;
  508. do_internalerror(i);
  509. GenerateError;
  510. doraise;
  511. end;
  512. procedure Comment(l:longint;s:ansistring);
  513. var
  514. dostop : boolean;
  515. begin
  516. dostop:=((l and V_Fatal)<>0);
  517. if ((l and V_Error)<>0) or
  518. ((l and V_Fatal)<>0) or
  519. (status.errorwarning and ((l and V_Warning)<>0)) or
  520. (status.errornote and ((l and V_Note)<>0)) or
  521. (status.errorhint and ((l and V_Hint)<>0)) then
  522. GenerateError
  523. else
  524. if l and V_Warning <> 0 then
  525. inc(status.countWarnings)
  526. else
  527. if l and V_Note <> 0 then
  528. inc(status.countNotes)
  529. else
  530. if l and V_Hint <> 0 then
  531. inc(status.countHints);
  532. { check verbosity level }
  533. if not CheckVerbosity(l) then
  534. exit;
  535. if (l and V_LineInfoMask)<>0 then
  536. l:=l or V_LineInfo;
  537. { Create status info }
  538. UpdateStatus;
  539. { Fix replacements }
  540. DefaultReplacements(s,false);
  541. { show comment }
  542. if do_comment(l,s) or dostop then
  543. raise ECompilerAbort.Create;
  544. if (status.errorcount>=status.maxerrorcount) and not status.skip_error then
  545. begin
  546. Message1(unit_f_errors_in_unit,tostr(status.errorcount));
  547. status.skip_error:=true;
  548. raise ECompilerAbort.Create;
  549. end;
  550. end;
  551. function GetMessageState(m:longint):tmsgstate;
  552. var
  553. i: integer;
  554. begin
  555. i:=m div 1000;
  556. { get the default state }
  557. Result:=msg^.msgstates[i]^[m mod 1000];
  558. { and search at the current unit settings }
  559. { todo }
  560. end;
  561. Procedure Msg2Comment(s:ansistring;w:longint;onqueue:tmsgqueueevent);
  562. var
  563. idx,i,v : longint;
  564. dostop : boolean;
  565. doqueue : boolean;
  566. st : tmsgstate;
  567. ch : char;
  568. begin
  569. {Reset}
  570. dostop:=false;
  571. doqueue:=false;
  572. v:=0;
  573. {Parse options}
  574. idx:=pos('_',s);
  575. if idx=0 then
  576. v:=V_None
  577. else
  578. if (idx >= 1) And (idx <= 5) then
  579. begin
  580. for i:=1 to idx do
  581. begin
  582. ch:=upcase(s[i]);
  583. case ch of
  584. 'F' :
  585. begin
  586. v:=v or V_Fatal;
  587. GenerateError;
  588. dostop:=true;
  589. end;
  590. 'E','W','N','H':
  591. begin
  592. if ch='E' then
  593. st:=ms_error
  594. else
  595. st:=GetMessageState(w);
  596. { We only want to know about local value }
  597. st:= tmsgstate(ord(st) and ms_local_mask);
  598. if st=ms_error then
  599. begin
  600. v:=v or V_Error;
  601. GenerateError;
  602. end
  603. else if st<>ms_off then
  604. case ch of
  605. 'W':
  606. begin
  607. v:=v or V_Warning;
  608. if CheckVerbosity(V_Warning) then
  609. if status.errorwarning then
  610. GenerateError
  611. else
  612. inc(status.countWarnings);
  613. end;
  614. 'N' :
  615. begin
  616. v:=v or V_Note;
  617. if CheckVerbosity(V_Note) then
  618. if status.errornote then
  619. GenerateError
  620. else
  621. inc(status.countNotes);
  622. end;
  623. 'H' :
  624. begin
  625. v:=v or V_Hint;
  626. if CheckVerbosity(V_Hint) then
  627. if status.errorhint then
  628. GenerateError
  629. else
  630. inc(status.countHints);
  631. end;
  632. end;
  633. end;
  634. 'O' :
  635. v:=v or V_Normal;
  636. 'I' :
  637. v:=v or V_Info;
  638. 'L' :
  639. v:=v or V_LineInfo;
  640. 'U' :
  641. v:=v or V_Used;
  642. 'T' :
  643. v:=v or V_Tried;
  644. 'C' :
  645. v:=v or V_Conditional;
  646. 'D' :
  647. v:=v or V_Debug;
  648. 'X' :
  649. v:=v or V_Executable;
  650. 'S' :
  651. dostop:=true;
  652. '_' : ;
  653. end;
  654. end;
  655. end;
  656. Delete(s,1,idx);
  657. { check verbosity level }
  658. if not CheckVerbosity(v) then
  659. begin
  660. doqueue := onqueue <> nil;
  661. if not doqueue then
  662. exit;
  663. end;
  664. if (v and V_LineInfoMask)<>0 then
  665. v:=v or V_LineInfo;
  666. { fix status }
  667. UpdateStatus;
  668. { Fix replacements }
  669. DefaultReplacements(s,false);
  670. if status.showmsgnrs and ((v and V_Normal)=0) then
  671. s:='('+tostr(w)+') '+s;
  672. if doqueue then
  673. begin
  674. onqueue(s,v,w);
  675. exit;
  676. end;
  677. { show comment }
  678. if do_comment(v,s) or dostop then
  679. raise ECompilerAbort.Create;
  680. if (status.errorcount>=status.maxerrorcount) and not status.skip_error then
  681. begin
  682. Message1(unit_f_errors_in_unit,tostr(status.errorcount));
  683. status.skip_error:=true;
  684. raise ECompilerAbort.Create;
  685. end;
  686. end;
  687. function MessageStr(w:longint):TMsgStr;
  688. begin
  689. MaybeLoadMessageFile;
  690. MessageStr:=msg^.Get(w,[]);
  691. end;
  692. procedure Message(w:longint;onqueue:tmsgqueueevent=nil);
  693. begin
  694. MaybeLoadMessageFile;
  695. Msg2Comment(msg^.Get(w,[]),w,onqueue);
  696. end;
  697. procedure Message1(w:longint;const s1:TMsgStr;onqueue:tmsgqueueevent=nil);
  698. begin
  699. MaybeLoadMessageFile;
  700. Msg2Comment(msg^.Get(w,[s1]),w,onqueue);
  701. end;
  702. procedure Message2(w:longint;const s1,s2:TMsgStr;onqueue:tmsgqueueevent=nil);
  703. begin
  704. MaybeLoadMessageFile;
  705. Msg2Comment(msg^.Get(w,[s1,s2]),w,onqueue);
  706. end;
  707. procedure Message3(w:longint;const s1,s2,s3:TMsgStr;onqueue:tmsgqueueevent=nil);
  708. begin
  709. MaybeLoadMessageFile;
  710. Msg2Comment(msg^.Get(w,[s1,s2,s3]),w,onqueue);
  711. end;
  712. procedure Message4(w:longint;const s1,s2,s3,s4:TMsgStr;onqueue:tmsgqueueevent=nil);
  713. begin
  714. MaybeLoadMessageFile;
  715. Msg2Comment(msg^.Get(w,[s1,s2,s3,s4]),w,onqueue);
  716. end;
  717. procedure MessagePos(const pos:tfileposinfo;w:longint;onqueue:tmsgqueueevent=nil);
  718. var
  719. oldpos : tfileposinfo;
  720. begin
  721. oldpos:=current_filepos;
  722. current_filepos:=pos;
  723. MaybeLoadMessageFile;
  724. Msg2Comment(msg^.Get(w,[]),w,onqueue);
  725. current_filepos:=oldpos;
  726. end;
  727. procedure MessagePos1(const pos:tfileposinfo;w:longint;const s1:TMsgStr;onqueue:tmsgqueueevent=nil);
  728. var
  729. oldpos : tfileposinfo;
  730. begin
  731. oldpos:=current_filepos;
  732. current_filepos:=pos;
  733. MaybeLoadMessageFile;
  734. Msg2Comment(msg^.Get(w,[s1]),w,onqueue);
  735. current_filepos:=oldpos;
  736. end;
  737. procedure MessagePos2(const pos:tfileposinfo;w:longint;const s1,s2:TMsgStr;onqueue:tmsgqueueevent=nil);
  738. var
  739. oldpos : tfileposinfo;
  740. begin
  741. oldpos:=current_filepos;
  742. current_filepos:=pos;
  743. MaybeLoadMessageFile;
  744. Msg2Comment(msg^.Get(w,[s1,s2]),w,onqueue);
  745. current_filepos:=oldpos;
  746. end;
  747. procedure MessagePos3(const pos:tfileposinfo;w:longint;const s1,s2,s3:TMsgStr;onqueue:tmsgqueueevent=nil);
  748. var
  749. oldpos : tfileposinfo;
  750. begin
  751. oldpos:=current_filepos;
  752. current_filepos:=pos;
  753. MaybeLoadMessageFile;
  754. Msg2Comment(msg^.Get(w,[s1,s2,s3]),w,onqueue);
  755. current_filepos:=oldpos;
  756. end;
  757. procedure MessagePos4(const pos:tfileposinfo;w:longint;const s1,s2,s3,s4:TMsgStr;onqueue:tmsgqueueevent=nil);
  758. var
  759. oldpos : tfileposinfo;
  760. begin
  761. oldpos:=current_filepos;
  762. current_filepos:=pos;
  763. MaybeLoadMessageFile;
  764. Msg2Comment(msg^.Get(w,[s1,s2,s3,s4]),w,onqueue);
  765. current_filepos:=oldpos;
  766. end;
  767. {*****************************************************************************
  768. override the message calls to set codegenerror
  769. *****************************************************************************}
  770. procedure cgmessage(t : longint);
  771. var
  772. olderrorcount : longint;
  773. begin
  774. if not(codegenerror) then
  775. begin
  776. olderrorcount:=Errorcount;
  777. verbose.Message(t);
  778. codegenerror:=olderrorcount<>Errorcount;
  779. end;
  780. end;
  781. procedure cgmessage1(t : longint;const s : TMsgStr);
  782. var
  783. olderrorcount : longint;
  784. begin
  785. if not(codegenerror) then
  786. begin
  787. olderrorcount:=Errorcount;
  788. verbose.Message1(t,s);
  789. codegenerror:=olderrorcount<>Errorcount;
  790. end;
  791. end;
  792. procedure cgmessage2(t : longint;const s1,s2 : TMsgStr);
  793. var
  794. olderrorcount : longint;
  795. begin
  796. if not(codegenerror) then
  797. begin
  798. olderrorcount:=Errorcount;
  799. verbose.Message2(t,s1,s2);
  800. codegenerror:=olderrorcount<>Errorcount;
  801. end;
  802. end;
  803. procedure cgmessage3(t : longint;const s1,s2,s3 : TMsgStr);
  804. var
  805. olderrorcount : longint;
  806. begin
  807. if not(codegenerror) then
  808. begin
  809. olderrorcount:=Errorcount;
  810. verbose.Message3(t,s1,s2,s3);
  811. codegenerror:=olderrorcount<>Errorcount;
  812. end;
  813. end;
  814. procedure cgmessagepos(const pos:tfileposinfo;t : longint);
  815. var
  816. olderrorcount : longint;
  817. begin
  818. if not(codegenerror) then
  819. begin
  820. olderrorcount:=Errorcount;
  821. verbose.MessagePos(pos,t);
  822. codegenerror:=olderrorcount<>Errorcount;
  823. end;
  824. end;
  825. procedure cgmessagepos1(const pos:tfileposinfo;t : longint;const s1 : TMsgStr);
  826. var
  827. olderrorcount : longint;
  828. begin
  829. if not(codegenerror) then
  830. begin
  831. olderrorcount:=Errorcount;
  832. verbose.MessagePos1(pos,t,s1);
  833. codegenerror:=olderrorcount<>Errorcount;
  834. end;
  835. end;
  836. procedure cgmessagepos2(const pos:tfileposinfo;t : longint;const s1,s2 : TMsgStr);
  837. var
  838. olderrorcount : longint;
  839. begin
  840. if not(codegenerror) then
  841. begin
  842. olderrorcount:=Errorcount;
  843. verbose.MessagePos2(pos,t,s1,s2);
  844. codegenerror:=olderrorcount<>Errorcount;
  845. end;
  846. end;
  847. procedure cgmessagepos3(const pos:tfileposinfo;t : longint;const s1,s2,s3 : TMsgStr);
  848. var
  849. olderrorcount : longint;
  850. begin
  851. if not(codegenerror) then
  852. begin
  853. olderrorcount:=Errorcount;
  854. verbose.MessagePos3(pos,t,s1,s2,s3);
  855. codegenerror:=olderrorcount<>Errorcount;
  856. end;
  857. end;
  858. procedure FlushOutput;
  859. begin
  860. if not (Status.Use_StdErr) then (* StdErr is flushed after every line *)
  861. begin
  862. if Status.Use_Redir then
  863. Flush(Status.RedirFile)
  864. else
  865. Flush(Output);
  866. end;
  867. end;
  868. {*****************************************************************************
  869. Initialization
  870. *****************************************************************************}
  871. procedure InitVerbose;
  872. begin
  873. { Init }
  874. msg:=new(pmessage,Init(20,msgidxmax));
  875. if msg=nil then
  876. begin
  877. writeln('Fatal: MsgIdx Wrong');
  878. halt(3);
  879. end;
  880. {$ifndef EXTERN_MSG}
  881. msg^.LoadIntern(@msgtxt,msgtxtsize,msgtxt_codepage);
  882. {$else EXTERN_MSG}
  883. LoadMsgFile(exepath+'errore.msg');
  884. {$endif EXTERN_MSG}
  885. FillChar(Status,sizeof(TCompilerStatus),0);
  886. status.verbosity:=V_Default;
  887. Status.MaxErrorCount:=50;
  888. Status.codesize:=aword(-1);
  889. Status.datasize:=aword(-1);
  890. Loadprefixes;
  891. lastfileidx:=-1;
  892. lastmoduleidx:=-1;
  893. status.currentmodule:='';
  894. status.currentsourceppufilename:='';
  895. status.currentsource:='';
  896. status.currentsourcepath:='';
  897. { Register internalerrorproc for cutils/cclasses }
  898. internalerrorproc:=@internalerror;
  899. end;
  900. procedure DoneVerbose;
  901. begin
  902. if assigned(msg) then
  903. begin
  904. dispose(msg,Done);
  905. msg:=nil;
  906. end;
  907. DoneRedirectFile;
  908. end;
  909. procedure printnodeindent; inline;
  910. begin
  911. printnodeindention:=printnodeindention+printnodespacing;
  912. end;
  913. procedure printnodeunindent; inline;
  914. begin
  915. delete(printnodeindention,1,length(printnodespacing));
  916. end;
  917. {$ifdef DEBUG_NODE_XML}
  918. function WritePointer(const P: Pointer): ansistring;
  919. begin
  920. case PtrUInt(P) of
  921. 0:
  922. WritePointer := 'nil';
  923. 1..$FFFF:
  924. WritePointer := '$' + hexstr(PtrUInt(P), 4);
  925. {$if sizeof(Pointer) >= 4}
  926. $10000..$FFFFFFFF:
  927. WritePointer := '$' + hexstr(PtrUInt(P), 8);
  928. {$ifend sizeof(Pointer) >= 4}
  929. {$if sizeof(Pointer) > 4}
  930. else
  931. WritePointer := '$' + hexstr(PtrUInt(P), 2*sizeof(Pointer));
  932. {$ifend sizeof(Pointer) > 4}
  933. end;
  934. end;
  935. function WriteConstPUInt(const P: TConstPtrUInt): ansistring;
  936. begin
  937. case P of
  938. 0:
  939. WriteConstPUInt := 'nil';
  940. 1..$FFFF:
  941. WriteConstPUInt := '$' + hexstr(P, 4);
  942. {$if sizeof(TConstPtrUInt) >= 4}
  943. $10000..$FFFFFFFF:
  944. WriteConstPUInt := '$' + hexstr(P, 8);
  945. {$ifend sizeof(TConstPtrUInt) >= 4}
  946. {$if sizeof(TConstPtrUInt) > 4}
  947. else
  948. WriteConstPUInt := '$' + hexstr(P, 2*sizeof(TConstPtrUInt));
  949. {$endif sizeof(TConstPtrUInt) > 4}
  950. end;
  951. end;
  952. function WriteGUID(const GUID: TGUID): ansistring;
  953. var
  954. i: Integer;
  955. begin
  956. Result := '{' + hexstr(GUID.D1, 8) + '-' + hexstr(GUID.D2, 4) + '-' + hexstr(GUID.D3, 4) + '-';
  957. for i := 0 to 7 do
  958. Result := Result + hexstr(GUID.D4[i], 2);
  959. Result := Result + '}';
  960. end;
  961. function SanitiseXMLString(const S: ansistring): ansistring;
  962. var
  963. X, UTF8Len, UTF8Char, CurrentChar: Integer;
  964. needs_quoting, in_quotes, add_end_quote: Boolean;
  965. DoASCII: Boolean;
  966. { Write the given byte as #xxx }
  967. procedure EncodeControlChar(Value: Byte);
  968. begin
  969. if X = Length(Result) then
  970. add_end_quote := False;
  971. Delete(Result, X, 1);
  972. if in_quotes then
  973. begin
  974. Insert('#' + tostr(Value) + '''', Result, X);
  975. { If the entire string consists of control characters, it
  976. doesn't need quoting, so only set the flag here }
  977. needs_quoting := True;
  978. in_quotes := False;
  979. end
  980. else
  981. Insert('#' + tostr(Value), Result, X);
  982. end;
  983. { Write the given byte as either a plain character or an XML keyword }
  984. procedure EncodeStandardChar(Value: Byte);
  985. begin
  986. if not in_quotes then
  987. begin
  988. in_quotes := True;
  989. if (X < Length(Result)) then
  990. begin
  991. needs_quoting := True;
  992. Insert('''', Result, X + 1)
  993. end;
  994. end;
  995. { Check the character for anything that could be mistaken for an XML element }
  996. case CurrentChar of
  997. Ord('#'):
  998. { Required to differentiate '#27' from the escape code #27, for example }
  999. needs_quoting:=true;
  1000. Ord('<'):
  1001. begin
  1002. Delete(Result, X, 1);
  1003. Insert('&lt;', Result, X);
  1004. end;
  1005. Ord('>'):
  1006. begin
  1007. Delete(Result, X, 1);
  1008. Insert('&gt;', Result, X);
  1009. end;
  1010. Ord('&'):
  1011. begin
  1012. Delete(Result, X, 1);
  1013. Insert('&amp;', Result, X);
  1014. end;
  1015. Ord('"'):
  1016. begin
  1017. needs_quoting := True;
  1018. Delete(Result, X, 1);
  1019. Insert('&quot;', Result, X);
  1020. end;
  1021. Ord(''''):
  1022. begin
  1023. needs_quoting:=true;
  1024. { Simply double it like in pascal strings }
  1025. Insert('''', Result, X);
  1026. end;
  1027. else
  1028. { Do nothing };
  1029. end;
  1030. end;
  1031. { Convert character between $80 and $FF to UTF-8 }
  1032. procedure EncodeExtendedChar(Value: Byte);
  1033. begin
  1034. if not in_quotes then
  1035. begin
  1036. in_quotes := True;
  1037. if (X < Length(Result)) then
  1038. begin
  1039. needs_quoting := True;
  1040. Insert('''', Result, X + 1)
  1041. end;
  1042. end;
  1043. case Value of
  1044. $80..$BF: { Add $C2 before the value }
  1045. Insert(#$C2, Result, X);
  1046. $C0..$FF: { Zero the $40 bit and add $C3 before the value }
  1047. begin
  1048. Result[X] := Char(Byte(Result[X]) and $BF);
  1049. Insert(#$C3, Result, X);
  1050. end;
  1051. else
  1052. { Previous conditions should prevent this procedure from being
  1053. called if Value < $80 }
  1054. InternalError(2019061901);
  1055. end;
  1056. end;
  1057. begin
  1058. needs_quoting := False;
  1059. Result := S;
  1060. { Gets set to True if an invalid UTF-8 sequence is found }
  1061. DoASCII := False;
  1062. { By setting in_quotes to false here, we can exclude the single
  1063. quotation marks surrounding the string if it doesn't contain any
  1064. control characters, or consists entirely of control characters. }
  1065. in_quotes := False;
  1066. add_end_quote := True;
  1067. X := Length(Result);
  1068. while X > 0 do
  1069. begin
  1070. CurrentChar := Ord(Result[X]);
  1071. { Control characters and extended characters need special handling }
  1072. case CurrentChar of
  1073. $00..$1F, $7F:
  1074. EncodeControlChar(CurrentChar);
  1075. $20..$7E:
  1076. EncodeStandardChar(CurrentChar);
  1077. { UTF-8 continuation byte }
  1078. $80..$BF:
  1079. begin
  1080. if not in_quotes then
  1081. begin
  1082. in_quotes := True;
  1083. if (X < Length(Result)) then
  1084. begin
  1085. needs_quoting := True;
  1086. Insert('''', Result, X + 1)
  1087. end;
  1088. end;
  1089. UTF8Char := CurrentChar and $3F; { The data bits of the continuation byte }
  1090. UTF8Len := 1; { This variable actually holds 1 less than the length }
  1091. { By setting DoASCII to true, it marks the string as 'invalid UTF-8'
  1092. automatically if it reaches the beginning of the string unexpectedly }
  1093. DoASCII := True;
  1094. Dec(X);
  1095. while X > 0 do
  1096. begin
  1097. CurrentChar := Ord(Result[X]);
  1098. case CurrentChar of
  1099. { A standard character here is invalid UTF-8 }
  1100. $00..$7F:
  1101. Break;
  1102. { Another continuation byte }
  1103. $80..$BF:
  1104. begin
  1105. UTF8Char := UTF8Char or ((CurrentChar and $3F) shl (6 * UTF8Len));
  1106. dec(X);
  1107. Inc(UTF8Len);
  1108. if UTF8Len >= 4 then
  1109. { Sequence too long }
  1110. Break;
  1111. end;
  1112. { Lead byte for 2-byte sequences }
  1113. $C2..$DF:
  1114. begin
  1115. if UTF8Len <> 1 then Break;
  1116. UTF8Char := UTF8Char or ((CurrentChar and $1F) shl 6);
  1117. { Check to see if the code is in range and not part of an 'overlong' sequence }
  1118. case UTF8Char of
  1119. $0080..$07FF:
  1120. DoASCII := False;
  1121. else
  1122. { Do nothing - DoASCII is already true }
  1123. end;
  1124. Break;
  1125. end;
  1126. { Lead byte for 3-byte sequences }
  1127. $E0..$EF:
  1128. begin
  1129. if UTF8Len <> 2 then Break;
  1130. UTF8Char := UTF8Char or ((CurrentChar and $0F) shl 12);
  1131. { Check to see if the code is in range and not part of an 'overlong' sequence }
  1132. case UTF8Char of
  1133. $0800..$D7FF, $E000..$FFFF: { $D800..$DFFF is reserved and hence invalid }
  1134. DoASCII := False;
  1135. else
  1136. { Do nothing - DoASCII is already true }
  1137. end;
  1138. Break;
  1139. end;
  1140. { Lead byte for 4-byte sequences }
  1141. $F0..$F4:
  1142. begin
  1143. if UTF8Len <> 3 then Break;
  1144. UTF8Char := UTF8Char or ((CurrentChar and $07) shl 18);
  1145. { Check to see if the code is in range and not part of an 'overlong' sequence }
  1146. case UTF8Char of
  1147. $010000..$10FFFF:
  1148. DoASCII := False;
  1149. else
  1150. { Do nothing - DoASCII is already true }
  1151. end;
  1152. Break;
  1153. end;
  1154. { Invalid character }
  1155. else
  1156. Break;
  1157. end;
  1158. end;
  1159. if DoASCII then
  1160. Break;
  1161. { If all is fine, we don't need to encode any more characters }
  1162. end;
  1163. { Invalid UTF-8 bytes and lead bytes without continuation bytes }
  1164. $C0..$FF:
  1165. begin
  1166. DoASCII := True;
  1167. Break;
  1168. end;
  1169. end;
  1170. Dec(X);
  1171. end;
  1172. { UTF-8 failed, so encode the string as plain ASCII }
  1173. if DoASCII then
  1174. begin
  1175. { Reset the flags and Result }
  1176. needs_quoting := False;
  1177. Result := S;
  1178. in_quotes := False;
  1179. add_end_quote := True;
  1180. for X := Length(Result) downto 1 do
  1181. begin
  1182. CurrentChar := Ord(Result[X]);
  1183. { Control characters and extended characters need special handling }
  1184. case CurrentChar of
  1185. $00..$1F, $7F:
  1186. EncodeControlChar(CurrentChar);
  1187. $20..$7E:
  1188. EncodeStandardChar(CurrentChar);
  1189. { Extended characters }
  1190. else
  1191. EncodeExtendedChar(CurrentChar);
  1192. end;
  1193. end;
  1194. end;
  1195. if needs_quoting then
  1196. begin
  1197. if in_quotes then
  1198. Result := '''' + Result;
  1199. if add_end_quote then
  1200. Result := Result + '''';
  1201. end;
  1202. end;
  1203. {$endif DEBUG_NODE_XML}
  1204. initialization
  1205. constexp.internalerrorproc:=@internalerror;
  1206. finalization
  1207. { Be sure to close the redirect files to flush all data }
  1208. DoneRedirectFile;
  1209. end.