verbose.pas 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Peter Vreman
  4. This unit handles the verbose management
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit verbose;
  19. {$i fpcdefs.inc}
  20. { Don't include messages in the executable }
  21. {.$define EXTERN_MSG}
  22. interface
  23. uses
  24. cutils,
  25. globals,finput,
  26. cmsgs;
  27. {$ifndef EXTERN_MSG}
  28. {$i msgtxt.inc}
  29. {$endif}
  30. {$i msgidx.inc}
  31. Const
  32. { <$10000 will show file and line }
  33. V_None = $0;
  34. V_Fatal = $1;
  35. V_Error = $2;
  36. V_Normal = $4; { doesn't show a text like Error: }
  37. V_Warning = $8;
  38. V_Note = $10;
  39. V_Hint = $20;
  40. V_Macro = $100;
  41. V_Procedure = $200;
  42. V_Conditional = $400;
  43. V_Assem = $800;
  44. V_Declarations = $1000;
  45. V_Info = $10000;
  46. V_Status = $20000;
  47. V_Used = $40000;
  48. V_Tried = $80000;
  49. V_Debug = $100000;
  50. V_Executable = $200000;
  51. V_ShowFile = $ffff;
  52. V_All = longint($ffffffff);
  53. V_Default = V_Fatal + V_Error + V_Normal;
  54. var
  55. msg : pmessage;
  56. const
  57. msgfilename : string = '';
  58. procedure SetRedirectFile(const fn:string);
  59. function SetVerbosity(const s:string):boolean;
  60. procedure SetCompileModule(p:tmodulebase);
  61. procedure Stop;
  62. procedure ShowStatus;
  63. function ErrorCount:longint;
  64. procedure SetErrorFlags(const s:string);
  65. procedure GenerateError;
  66. procedure Internalerror(i:longint);
  67. procedure Comment(l:longint;s:string);
  68. function MessagePchar(w:longint):pchar;
  69. procedure Message(w:longint);
  70. procedure Message1(w:longint;const s1:string);
  71. procedure Message2(w:longint;const s1,s2:string);
  72. procedure Message3(w:longint;const s1,s2,s3:string);
  73. procedure Message4(w:longint;const s1,s2,s3,s4:string);
  74. procedure MessagePos(const pos:tfileposinfo;w:longint);
  75. procedure MessagePos1(const pos:tfileposinfo;w:longint;const s1:string);
  76. procedure MessagePos2(const pos:tfileposinfo;w:longint;const s1,s2:string);
  77. procedure MessagePos3(const pos:tfileposinfo;w:longint;const s1,s2,s3:string);
  78. procedure MessagePos4(const pos:tfileposinfo;w:longint;const s1,s2,s3,s4:string);
  79. procedure InitVerbose;
  80. procedure DoneVerbose;
  81. implementation
  82. uses
  83. comphook;
  84. var
  85. current_module : tmodulebase;
  86. {****************************************************************************
  87. Extra Handlers for default compiler
  88. ****************************************************************************}
  89. procedure DoneRedirectFile;
  90. begin
  91. if status.use_redir then
  92. begin
  93. close(status.redirfile);
  94. status.use_redir:=false;
  95. end;
  96. end;
  97. procedure SetRedirectFile(const fn:string);
  98. begin
  99. assign(status.redirfile,fn);
  100. {$I-}
  101. append(status.redirfile);
  102. if ioresult <> 0 then
  103. rewrite(status.redirfile);
  104. {$I+}
  105. status.use_redir:=(ioresult=0);
  106. end;
  107. function SetVerbosity(const s:string):boolean;
  108. var
  109. m : Longint;
  110. i : Integer;
  111. inverse : boolean;
  112. c : char;
  113. begin
  114. Setverbosity:=false;
  115. val(s,m,i);
  116. if (i=0) and (s<>'') then
  117. status.verbosity:=m
  118. else
  119. begin
  120. i:=1;
  121. while i<=length(s) do
  122. begin
  123. c:=upcase(s[i]);
  124. inverse:=false;
  125. { on/off ? }
  126. if (i<length(s)) then
  127. case s[i+1] of
  128. '-' : begin
  129. inc(i);
  130. inverse:=true;
  131. end;
  132. '+' : inc(i);
  133. end;
  134. { handle switch }
  135. case c of
  136. { Special cases }
  137. 'A' : status.verbosity:=V_All;
  138. '0' : status.verbosity:=V_Default;
  139. 'R' : begin
  140. if inverse then
  141. begin
  142. status.use_gccoutput:=false;
  143. status.use_stderr:=false;
  144. end
  145. else
  146. begin
  147. status.use_gccoutput:=true;
  148. status.use_stderr:=true;
  149. end;
  150. end;
  151. { Normal cases - do an or }
  152. 'E' : if inverse then
  153. status.verbosity:=status.verbosity and (not V_Error)
  154. else
  155. status.verbosity:=status.verbosity or V_Error;
  156. 'I' : if inverse then
  157. status.verbosity:=status.verbosity and (not V_Info)
  158. else
  159. status.verbosity:=status.verbosity or V_Info;
  160. 'W' : if inverse then
  161. status.verbosity:=status.verbosity and (not V_Warning)
  162. else
  163. status.verbosity:=status.verbosity or V_Warning;
  164. 'N' : if inverse then
  165. status.verbosity:=status.verbosity and (not V_Note)
  166. else
  167. status.verbosity:=status.verbosity or V_Note;
  168. 'H' : if inverse then
  169. status.verbosity:=status.verbosity and (not V_Hint)
  170. else
  171. status.verbosity:=status.verbosity or V_Hint;
  172. 'L' : if inverse then
  173. status.verbosity:=status.verbosity and (not V_Status)
  174. else
  175. status.verbosity:=status.verbosity or V_Status;
  176. 'U' : if inverse then
  177. status.verbosity:=status.verbosity and (not V_Used)
  178. else
  179. status.verbosity:=status.verbosity or V_Used;
  180. 'T' : if inverse then
  181. status.verbosity:=status.verbosity and (not V_Tried)
  182. else
  183. status.verbosity:=status.verbosity or V_Tried;
  184. 'M' : if inverse then
  185. status.verbosity:=status.verbosity and (not V_Macro)
  186. else
  187. status.verbosity:=status.verbosity or V_Macro;
  188. 'P' : if inverse then
  189. status.verbosity:=status.verbosity and (not V_Procedure)
  190. else
  191. status.verbosity:=status.verbosity or V_Procedure;
  192. 'C' : if inverse then
  193. status.verbosity:=status.verbosity and (not V_Conditional)
  194. else
  195. status.verbosity:=status.verbosity or V_Conditional;
  196. 'D' : if inverse then
  197. status.verbosity:=status.verbosity and (not V_Debug)
  198. else
  199. status.verbosity:=status.verbosity or V_Debug;
  200. 'B' : if inverse then
  201. status.verbosity:=status.verbosity and (not V_Declarations)
  202. else
  203. status.verbosity:=status.verbosity or V_Declarations;
  204. 'X' : if inverse then
  205. status.verbosity:=status.verbosity and (not V_Executable)
  206. else
  207. status.verbosity:=status.verbosity or V_Executable;
  208. 'Z' : if inverse then
  209. status.verbosity:=status.verbosity and (not V_Assem)
  210. else
  211. status.verbosity:=status.verbosity or V_Assem;
  212. end;
  213. inc(i);
  214. end;
  215. end;
  216. if status.verbosity=0 then
  217. status.verbosity:=V_Default;
  218. setverbosity:=true;
  219. end;
  220. procedure Loadprefixes;
  221. function loadprefix(w:longint):string;
  222. var
  223. s : string;
  224. idx : longint;
  225. begin
  226. s:=msg^.get(w);
  227. idx:=pos('_',s);
  228. if idx>0 then
  229. Loadprefix:=Copy(s,idx+1,255)
  230. else
  231. Loadprefix:=s;
  232. end;
  233. begin
  234. { Load the prefixes }
  235. fatalstr:=Loadprefix(general_i_fatal);
  236. errorstr:=Loadprefix(general_i_error);
  237. warningstr:=Loadprefix(general_i_warning);
  238. notestr:=Loadprefix(general_i_note);
  239. hintstr:=Loadprefix(general_i_hint);
  240. end;
  241. procedure LoadMsgFile(const fn:string);
  242. begin
  243. { reload the internal messages if not already loaded }
  244. {$ifndef EXTERN_MSG}
  245. if not msg^.msgintern then
  246. msg^.LoadIntern(@msgtxt,msgtxtsize);
  247. {$endif}
  248. if not msg^.LoadExtern(fn) then
  249. begin
  250. {$ifdef EXTERN_MSG}
  251. writeln('Fatal: Cannot find error message file.');
  252. halt(3);
  253. {$else}
  254. msg^.LoadIntern(@msgtxt,msgtxtsize);
  255. {$endif}
  256. end;
  257. { reload the prefixes using the new messages }
  258. Loadprefixes;
  259. end;
  260. procedure MaybeLoadMessageFile;
  261. begin
  262. { Load new message file }
  263. if (msgfilename<>'') then
  264. begin
  265. LoadMsgFile(msgfilename);
  266. msgfilename:='';
  267. end;
  268. end;
  269. procedure SetCompileModule(p:tmodulebase);
  270. begin
  271. current_module:=p;
  272. end;
  273. var
  274. lastfileidx,
  275. lastmoduleidx : longint;
  276. Procedure UpdateStatus;
  277. begin
  278. { fix status }
  279. status.currentline:=aktfilepos.line;
  280. status.currentcolumn:=aktfilepos.column;
  281. if assigned(current_module) and
  282. assigned(current_module.sourcefiles) and
  283. ((current_module.unit_index<>lastmoduleidx) or
  284. (aktfilepos.fileindex<>lastfileidx)) then
  285. begin
  286. { update status record }
  287. status.currentmodule:=current_module.modulename^;
  288. status.currentsource:=current_module.sourcefiles.get_file_name(aktfilepos.fileindex);
  289. status.currentsourcepath:=current_module.sourcefiles.get_file_path(aktfilepos.fileindex);
  290. { update lastfileidx only if name known PM }
  291. if status.currentsource<>'' then
  292. lastfileidx:=aktfilepos.fileindex
  293. else
  294. lastfileidx:=0;
  295. lastmoduleidx:=current_module.unit_index;
  296. end;
  297. if assigned(current_module) then
  298. status.compiling_current:=current_module.in_compile;
  299. end;
  300. procedure stop;
  301. begin
  302. do_stop{$ifdef FPCPROCVAR}(){$endif};
  303. end;
  304. procedure ShowStatus;
  305. begin
  306. UpdateStatus;
  307. if do_status{$ifdef FPCPROCVAR}(){$endif} then
  308. stop;
  309. end;
  310. function ErrorCount:longint;
  311. begin
  312. ErrorCount:=status.errorcount;
  313. end;
  314. procedure SetErrorFlags(const s:string);
  315. var
  316. code : integer;
  317. i,j,l : longint;
  318. begin
  319. { empty string means error count = 1 for backward compatibility (PFV) }
  320. if s='' then
  321. begin
  322. status.maxerrorcount:=1;
  323. exit;
  324. end;
  325. i:=0;
  326. while (i<length(s)) do
  327. begin
  328. inc(i);
  329. case s[i] of
  330. '0'..'9' :
  331. begin
  332. j:=i;
  333. while (j<=length(s)) and (s[j] in ['0'..'9']) do
  334. inc(j);
  335. val(copy(s,i,j-i),l,code);
  336. if code<>0 then
  337. l:=1;
  338. status.maxerrorcount:=l;
  339. i:=j;
  340. end;
  341. 'w','W' :
  342. status.errorwarning:=true;
  343. 'n','N' :
  344. status.errornote:=true;
  345. 'h','H' :
  346. status.errorhint:=true;
  347. end;
  348. end;
  349. end;
  350. procedure GenerateError;
  351. begin
  352. inc(status.errorcount);
  353. end;
  354. procedure internalerror(i : longint);
  355. begin
  356. UpdateStatus;
  357. do_internalerror(i);
  358. inc(status.errorcount);
  359. stop;
  360. end;
  361. procedure Comment(l:longint;s:string);
  362. var
  363. dostop : boolean;
  364. begin
  365. dostop:=((l and V_Fatal)<>0);
  366. if ((l and V_Error)<>0) or
  367. (status.errorwarning and ((l and V_Warning)<>0)) or
  368. (status.errornote and ((l and V_Note)<>0)) or
  369. (status.errorhint and ((l and V_Hint)<>0)) then
  370. inc(status.errorcount);
  371. { check verbosity level }
  372. if (status.verbosity and l)<>l then
  373. exit;
  374. { Create status info }
  375. UpdateStatus;
  376. { Fix replacements }
  377. DefaultReplacements(s);
  378. { show comment }
  379. if do_comment(l,s) or dostop then
  380. stop;
  381. if (status.errorcount>=status.maxerrorcount) and not status.skip_error then
  382. begin
  383. Message1(unit_f_errors_in_unit,tostr(status.errorcount));
  384. status.skip_error:=true;
  385. stop;
  386. end;
  387. end;
  388. Procedure Msg2Comment(s:string);
  389. var
  390. idx,i,v : longint;
  391. dostop : boolean;
  392. begin
  393. {Reset}
  394. dostop:=false;
  395. v:=0;
  396. {Parse options}
  397. idx:=pos('_',s);
  398. if idx=0 then
  399. v:=V_Normal
  400. else
  401. if (idx >= 1) And (idx <= 5) then
  402. begin
  403. for i:=1 to idx do
  404. begin
  405. case upcase(s[i]) of
  406. 'F' :
  407. begin
  408. v:=v or V_Fatal;
  409. inc(status.errorcount);
  410. dostop:=true;
  411. end;
  412. 'E' :
  413. begin
  414. v:=v or V_Error;
  415. inc(status.errorcount);
  416. end;
  417. 'O' :
  418. v:=v or V_Normal;
  419. 'W':
  420. begin
  421. v:=v or V_Warning;
  422. if status.errorwarning then
  423. inc(status.errorcount);
  424. end;
  425. 'N' :
  426. begin
  427. v:=v or V_Note;
  428. if status.errornote then
  429. inc(status.errorcount);
  430. end;
  431. 'H' :
  432. begin
  433. v:=v or V_Hint;
  434. if status.errorhint then
  435. inc(status.errorcount);
  436. end;
  437. 'I' :
  438. v:=v or V_Info;
  439. 'L' :
  440. v:=v or V_Status;
  441. 'U' :
  442. v:=v or V_Used;
  443. 'T' :
  444. v:=v or V_Tried;
  445. 'M' :
  446. v:=v or V_Macro;
  447. 'P' :
  448. v:=v or V_Procedure;
  449. 'C' :
  450. v:=v or V_Conditional;
  451. 'D' :
  452. v:=v or V_Debug;
  453. 'B' :
  454. v:=v or V_Declarations;
  455. 'X' :
  456. v:=v or V_Executable;
  457. 'Z' :
  458. v:=v or V_Assem;
  459. 'S' :
  460. dostop:=true;
  461. '_' : ;
  462. end;
  463. end;
  464. end;
  465. Delete(s,1,idx);
  466. { check verbosity level }
  467. if (status.verbosity and v)<>v then
  468. exit;
  469. { fix status }
  470. UpdateStatus;
  471. { Fix replacements }
  472. DefaultReplacements(s);
  473. { show comment }
  474. if do_comment(v,s) or dostop then
  475. stop;
  476. if (status.errorcount>=status.maxerrorcount) and not status.skip_error then
  477. begin
  478. Message1(unit_f_errors_in_unit,tostr(status.errorcount));
  479. status.skip_error:=true;
  480. stop;
  481. end;
  482. end;
  483. function MessagePchar(w:longint):pchar;
  484. begin
  485. MaybeLoadMessageFile;
  486. MessagePchar:=msg^.GetPchar(w)
  487. end;
  488. procedure Message(w:longint);
  489. begin
  490. MaybeLoadMessageFile;
  491. Msg2Comment(msg^.Get(w));
  492. end;
  493. procedure Message1(w:longint;const s1:string);
  494. begin
  495. MaybeLoadMessageFile;
  496. Msg2Comment(msg^.Get1(w,s1));
  497. end;
  498. procedure Message2(w:longint;const s1,s2:string);
  499. begin
  500. MaybeLoadMessageFile;
  501. Msg2Comment(msg^.Get2(w,s1,s2));
  502. end;
  503. procedure Message3(w:longint;const s1,s2,s3:string);
  504. begin
  505. MaybeLoadMessageFile;
  506. Msg2Comment(msg^.Get3(w,s1,s2,s3));
  507. end;
  508. procedure Message4(w:longint;const s1,s2,s3,s4:string);
  509. begin
  510. MaybeLoadMessageFile;
  511. Msg2Comment(msg^.Get4(w,s1,s2,s3,s4));
  512. end;
  513. procedure MessagePos(const pos:tfileposinfo;w:longint);
  514. var
  515. oldpos : tfileposinfo;
  516. begin
  517. oldpos:=aktfilepos;
  518. aktfilepos:=pos;
  519. MaybeLoadMessageFile;
  520. Msg2Comment(msg^.Get(w));
  521. aktfilepos:=oldpos;
  522. end;
  523. procedure MessagePos1(const pos:tfileposinfo;w:longint;const s1:string);
  524. var
  525. oldpos : tfileposinfo;
  526. begin
  527. oldpos:=aktfilepos;
  528. aktfilepos:=pos;
  529. MaybeLoadMessageFile;
  530. Msg2Comment(msg^.Get1(w,s1));
  531. aktfilepos:=oldpos;
  532. end;
  533. procedure MessagePos2(const pos:tfileposinfo;w:longint;const s1,s2:string);
  534. var
  535. oldpos : tfileposinfo;
  536. begin
  537. oldpos:=aktfilepos;
  538. aktfilepos:=pos;
  539. MaybeLoadMessageFile;
  540. Msg2Comment(msg^.Get2(w,s1,s2));
  541. aktfilepos:=oldpos;
  542. end;
  543. procedure MessagePos3(const pos:tfileposinfo;w:longint;const s1,s2,s3:string);
  544. var
  545. oldpos : tfileposinfo;
  546. begin
  547. oldpos:=aktfilepos;
  548. aktfilepos:=pos;
  549. MaybeLoadMessageFile;
  550. Msg2Comment(msg^.Get3(w,s1,s2,s3));
  551. aktfilepos:=oldpos;
  552. end;
  553. procedure MessagePos4(const pos:tfileposinfo;w:longint;const s1,s2,s3,s4:string);
  554. var
  555. oldpos : tfileposinfo;
  556. begin
  557. oldpos:=aktfilepos;
  558. aktfilepos:=pos;
  559. MaybeLoadMessageFile;
  560. Msg2Comment(msg^.Get4(w,s1,s2,s3,s4));
  561. aktfilepos:=oldpos;
  562. end;
  563. procedure InitVerbose;
  564. begin
  565. { Init }
  566. msg:=new(pmessage,Init(20,msgidxmax));
  567. if msg=nil then
  568. begin
  569. writeln('Fatal: MsgIdx Wrong');
  570. halt(3);
  571. end;
  572. {$ifndef EXTERN_MSG}
  573. msg^.LoadIntern(@msgtxt,msgtxtsize);
  574. {$else EXTERN_MSG}
  575. LoadMsgFile(exepath+'errore.msg');
  576. {$endif EXTERN_MSG}
  577. FillChar(Status,sizeof(TCompilerStatus),0);
  578. status.verbosity:=V_Default;
  579. Status.MaxErrorCount:=50;
  580. Loadprefixes;
  581. lastfileidx:=-1;
  582. lastmoduleidx:=-1;
  583. status.currentmodule:='';
  584. status.currentsource:='';
  585. status.currentsourcepath:='';
  586. status.compiling_current:=false;
  587. end;
  588. procedure DoneVerbose;
  589. begin
  590. if assigned(msg) then
  591. begin
  592. dispose(msg,Done);
  593. msg:=nil;
  594. end;
  595. if status.use_redir then
  596. DoneRedirectFile;
  597. end;
  598. end.
  599. {
  600. $Log$
  601. Revision 1.19 2002-05-18 13:34:21 peter
  602. * readded missing revisions
  603. Revision 1.18 2002/05/16 19:46:47 carl
  604. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  605. + try to fix temp allocation (still in ifdef)
  606. + generic constructor calls
  607. + start of tassembler / tmodulebase class cleanup
  608. }