comphook.pas 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. {
  2. Copyright (c) 1998-2002 by Peter Vreman
  3. This unit handles the compilerhooks for output to external programs
  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 comphook;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. {$IFNDEF USE_FAKE_SYSUTILS}
  22. sysutils,
  23. {$ELSE}
  24. fksysutl,
  25. {$ENDIF}
  26. globtype,
  27. finput;
  28. const
  29. { RHIDE expect gcc like error output }
  30. fatalstr : string[6] = 'Fatal:';
  31. errorstr : string[6] = 'Error:';
  32. warningstr : string[8] = 'Warning:';
  33. notestr : string[5] = 'Note:';
  34. hintstr : string[5] = 'Hint:';
  35. warningerrorstr : string[29] = 'Warning: (treated as error)';
  36. noteerrorstr : string[27] = 'Note: (treated as error)';
  37. hinterrorstr : string[27] = 'Hint: (treated as error)';
  38. type
  39. PCompilerStatus = ^TCompilerStatus;
  40. TCompilerStatus = record
  41. { Current status }
  42. currentmodule,
  43. currentsourceppufilename, { the name of the ppu where the source file
  44. comes from where the error location is given }
  45. currentsourcepath,
  46. currentsource : string; { filename }
  47. currentline,
  48. currentcolumn : longint; { current line and column }
  49. currentmodulestate : string[20];
  50. { Total Status }
  51. compiledlines : longint; { the number of lines which are compiled }
  52. errorcount, { this field should never be increased directly,
  53. use Verbose.GenerateError procedure to do this,
  54. this allows easier error catching using GDB by
  55. adding a single breakpoint at this procedure }
  56. countWarnings,
  57. countNotes,
  58. countHints : longint; { number of found errors/warnings/notes/hints }
  59. codesize,
  60. datasize : qword;
  61. { program info }
  62. isexe,
  63. ispackage,
  64. islibrary : boolean;
  65. { Settings for the output }
  66. showmsgnrs : boolean;
  67. verbosity : longint;
  68. maxerrorcount : longint;
  69. errorwarning,
  70. errornote,
  71. errorhint,
  72. skip_error,
  73. use_stderr,
  74. use_redir,
  75. use_bugreport,
  76. use_gccoutput,
  77. sources_avail,
  78. print_source_path : boolean;
  79. { Redirection support }
  80. redirfile : text;
  81. { Special file for bug report }
  82. reportbugfile : text;
  83. end;
  84. type
  85. EControlCAbort=class(Exception)
  86. constructor Create;
  87. end;
  88. ECompilerAbort=class(Exception)
  89. constructor Create;
  90. end;
  91. ECompilerAbortSilent=class(Exception)
  92. constructor Create;
  93. end;
  94. var
  95. status : tcompilerstatus;
  96. { Default Functions }
  97. Function def_status:boolean;
  98. Function def_comment(Level:Longint;const s:ansistring):boolean;
  99. function def_internalerror(i:longint):boolean;
  100. function def_CheckVerbosity(v:longint):boolean;
  101. procedure def_initsymbolinfo;
  102. procedure def_donesymbolinfo;
  103. procedure def_extractsymbolinfo;
  104. function def_openinputfile(const filename: TPathStr): tinputfile;
  105. Function def_getnamedfiletime(Const F : TPathStr) : Longint;
  106. { Function redirecting for IDE support }
  107. type
  108. tstopprocedure = procedure(err:longint);
  109. tstatusfunction = function:boolean;
  110. tcommentfunction = function(Level:Longint;const s:ansistring):boolean;
  111. tinternalerrorfunction = function(i:longint):boolean;
  112. tcheckverbosityfunction = function(i:longint):boolean;
  113. tinitsymbolinfoproc = procedure;
  114. tdonesymbolinfoproc = procedure;
  115. textractsymbolinfoproc = procedure;
  116. topeninputfilefunc = function(const filename: TPathStr): tinputfile;
  117. tgetnamedfiletimefunc = function(const filename: TPathStr): longint;
  118. const
  119. do_status : tstatusfunction = @def_status;
  120. do_comment : tcommentfunction = @def_comment;
  121. do_internalerror : tinternalerrorfunction = @def_internalerror;
  122. do_checkverbosity : tcheckverbosityfunction = @def_checkverbosity;
  123. do_initsymbolinfo : tinitsymbolinfoproc = @def_initsymbolinfo;
  124. do_donesymbolinfo : tdonesymbolinfoproc = @def_donesymbolinfo;
  125. do_extractsymbolinfo : textractsymbolinfoproc = @def_extractsymbolinfo;
  126. needsymbolinfo : boolean =false;
  127. do_openinputfile : topeninputfilefunc = @def_openinputfile;
  128. do_getnamedfiletime : tgetnamedfiletimefunc = @def_getnamedfiletime;
  129. implementation
  130. uses
  131. cutils, systems, globals, comptty;
  132. {****************************************************************************
  133. Helper Routines
  134. ****************************************************************************}
  135. function gccfilename(const s : string) : string;
  136. var
  137. i : longint;
  138. begin
  139. for i:=1to length(s) do
  140. begin
  141. case s[i] of
  142. '\' : gccfilename[i]:='/';
  143. 'A'..'Z' : if not (tf_files_case_aware in source_info.flags) and
  144. not (tf_files_case_sensitive in source_info.flags) then
  145. gccfilename[i]:=chr(ord(s[i])+32)
  146. else
  147. gccfilename[i]:=s[i];
  148. else
  149. gccfilename[i]:=s[i];
  150. end;
  151. end;
  152. gccfilename[0]:=s[0];
  153. end;
  154. function tostr(i : longint) : string;
  155. var
  156. hs : string;
  157. begin
  158. str(i,hs);
  159. tostr:=hs;
  160. end;
  161. type
  162. TOutputColor = (oc_black,oc_red,oc_green,oc_orange,oc_blue,oc_magenta,oc_cyan,oc_lightgray);
  163. procedure WriteColoredOutput(var t: Text;color: TOutputColor;const s : AnsiString);
  164. begin
  165. if TTYCheckSupported and IsATTY(t) then
  166. begin
  167. case color of
  168. oc_black:
  169. write(t,#27'[1m'#27'[30m');
  170. oc_red:
  171. write(t,#27'[1m'#27'[31m');
  172. oc_green:
  173. write(t,#27'[1m'#27'[32m');
  174. oc_orange:
  175. write(t,#27'[1m'#27'[33m');
  176. oc_blue:
  177. write(t,#27'[1m'#27'[34m');
  178. oc_magenta:
  179. write(t,#27'[1m'#27'[35m');
  180. oc_cyan:
  181. write(t,#27'[1m'#27'[36m');
  182. oc_lightgray:
  183. write(t,#27'[1m'#27'[37m');
  184. end;
  185. end;
  186. write(t,s);
  187. if TTYCheckSupported and IsATTY(t) then
  188. write(t,#27'[0m');
  189. end;
  190. {****************************************************************************
  191. Stopping the compiler
  192. ****************************************************************************}
  193. constructor EControlCAbort.Create;
  194. begin
  195. inherited Create('Ctrl-C Signaled!');
  196. end;
  197. constructor ECompilerAbort.Create;
  198. begin
  199. inherited Create('Compilation Aborted');
  200. end;
  201. constructor ECompilerAbortSilent.Create;
  202. begin
  203. inherited Create('Compilation Aborted');
  204. end;
  205. {****************************************************************************
  206. Predefined default Handlers
  207. ****************************************************************************}
  208. function def_status:boolean;
  209. var
  210. hstatus : TFPCHeapStatus;
  211. begin
  212. def_status:=false; { never stop }
  213. { Status info?, Called every line }
  214. if ((status.verbosity and V_Status)<>0) then
  215. begin
  216. if (status.compiledlines=1) or
  217. (status.currentline mod 100=0) then
  218. begin
  219. if status.currentline>0 then
  220. Write(status.currentmodule,':',status.currentline,' ');
  221. hstatus:=GetFPCHeapStatus;
  222. WriteLn(DStr(hstatus.CurrHeapUsed shr 10),'/',DStr(hstatus.CurrHeapSize shr 10),' Kb Used');
  223. flush(output);
  224. end;
  225. end;
  226. {$ifdef macos}
  227. Yield;
  228. {$endif}
  229. end;
  230. Function def_comment(Level:Longint;const s:ansistring):boolean;
  231. const
  232. rh_errorstr = 'error:';
  233. rh_warningstr = 'warning:';
  234. procedure WriteMsgTypeColored(var t : text;const s : AnsiString);
  235. begin
  236. case (status.verbosity and Level) of
  237. V_Warning:
  238. WriteColoredOutput(t,oc_magenta,s);
  239. V_Error,
  240. V_Fatal:
  241. WriteColoredOutput(t,oc_red,s);
  242. else
  243. write(t,s);
  244. end;
  245. end;
  246. var
  247. hs2,
  248. MsgTypeStr,
  249. MsgLocStr,
  250. MsgTimeStr: AnsiString;
  251. begin
  252. def_comment:=false; { never stop }
  253. MsgTypeStr:='';
  254. MsgLocStr:='';
  255. MsgTimeStr:='';
  256. if not(status.use_gccoutput) then
  257. begin
  258. if (status.verbosity and Level)=V_Hint then
  259. if status.errorhint then
  260. MsgTypeStr:=hinterrorstr
  261. else
  262. MsgTypeStr:=hintstr;
  263. if (status.verbosity and Level)=V_Note then
  264. if status.errornote then
  265. MsgTypeStr:=noteerrorstr
  266. else
  267. MsgTypeStr:=notestr;
  268. if (status.verbosity and Level)=V_Warning then
  269. if status.errorwarning then
  270. MsgTypeStr:=warningerrorstr
  271. else
  272. MsgTypeStr:=warningstr;
  273. if (status.verbosity and Level)=V_Error then
  274. MsgTypeStr:=errorstr;
  275. if (status.verbosity and Level)=V_Fatal then
  276. MsgTypeStr:=fatalstr;
  277. if (status.verbosity and V_Parallel)=V_Parallel then
  278. begin
  279. if (inputfilename<>'') and (status.currentmodule<>'') then
  280. MsgTypeStr:=MsgTypeStr+'('+inputfilename+'/'+status.currentmodule+')'
  281. else if (status.currentmodule<>'') then
  282. MsgTypeStr:=MsgTypeStr+'('+status.currentmodule+')'
  283. else if (inputfilename<>'') then
  284. MsgTypeStr:=MsgTypeStr+'('+inputfilename+')';
  285. end
  286. else if (status.verbosity and Level)=V_Used then
  287. MsgTypeStr:=PadSpace('('+status.currentmodule+')',10);
  288. end
  289. else
  290. begin
  291. if (status.verbosity and Level)=V_Hint then
  292. MsgTypeStr:=rh_warningstr;
  293. if (status.verbosity and Level)=V_Note then
  294. MsgTypeStr:=rh_warningstr;
  295. if (status.verbosity and Level)=V_Warning then
  296. MsgTypeStr:=rh_warningstr;
  297. if (status.verbosity and Level)=V_Error then
  298. MsgTypeStr:=rh_errorstr;
  299. if (status.verbosity and Level)=V_Fatal then
  300. MsgTypeStr:=rh_errorstr;
  301. end;
  302. { Generate line prefix }
  303. if ((Level and V_LineInfo)=V_LineInfo) and
  304. (status.currentsource<>'') and
  305. (status.currentline>0) then
  306. begin
  307. {$ifndef macos}
  308. { Adding the column should not confuse RHIDE,
  309. even if it does not yet use it PM
  310. but only if it is after error or warning !! PM }
  311. if status.currentcolumn>0 then
  312. begin
  313. if status.use_gccoutput then
  314. MsgLocStr:=gccfilename(status.currentsource)+':'+tostr(status.currentline)+':'+tostr(status.currentcolumn)+':'
  315. else
  316. MsgLocStr:=status.currentsource+'('+tostr(status.currentline)+','+tostr(status.currentcolumn)+')';
  317. end
  318. else
  319. begin
  320. if status.use_gccoutput then
  321. MsgLocStr:=gccfilename(status.currentsource)+':'+tostr(status.currentline)+':'
  322. else
  323. MsgLocStr:=status.currentsource+'('+tostr(status.currentline)+')';
  324. end;
  325. if status.print_source_path then
  326. if status.sources_avail then
  327. MsgLocStr:=status.currentsourcepath+MsgLocStr
  328. else
  329. MsgLocStr:=status.currentsourceppufilename+':'+MsgLocStr;
  330. {$else macos}
  331. { MPW style error }
  332. if status.currentcolumn>0 then
  333. MsgLocStr:='File "'+status.currentsourcepath+status.currentsource+'"; Line '+tostr(status.currentline)+' #[' + tostr(status.currentcolumn) + ']'
  334. else
  335. MsgLocStr:='File "'+status.currentsourcepath+status.currentsource+'"; Line '+tostr(status.currentline)+' # ';
  336. {$endif macos}
  337. end;
  338. if MsgLocStr<>'' then
  339. MsgLocStr:=MsgLocStr+' ';
  340. if MsgTypeStr<>'' then
  341. MsgTypeStr:=MsgTypeStr+' ';
  342. if (status.verbosity and V_TimeStamps)<>0 then
  343. begin
  344. system.str(getrealtime-starttime:0:3,hs2);
  345. MsgTimeStr:='['+hs2+'] ';
  346. end;
  347. { Display line }
  348. if (Level<>V_None) and
  349. ((status.verbosity and (Level and V_LevelMask))=(Level and V_LevelMask)) then
  350. begin
  351. if status.use_stderr then
  352. begin
  353. write(StdErr,MsgTimeStr+MsgLocStr);
  354. WriteMsgTypeColored(StdErr,MsgTypeStr);
  355. writeln(StdErr,s);
  356. flush(StdErr);
  357. end
  358. else
  359. begin
  360. if status.use_redir then
  361. begin
  362. writeln(status.redirfile,MsgTimeStr+MsgLocStr+MsgTypeStr+s);
  363. flush(status.redirfile);
  364. end
  365. else
  366. begin
  367. write(MsgTimeStr+MsgLocStr);
  368. WriteMsgTypeColored(Output,MsgTypeStr);
  369. writeln(s);
  370. end;
  371. end;
  372. end;
  373. { include everything in the bugreport file }
  374. if status.use_bugreport then
  375. begin
  376. Write(status.reportbugfile,hexstr(level,8)+':');
  377. Writeln(status.reportbugfile,MsgTimeStr+MsgLocStr+MsgTypeStr+s);
  378. end;
  379. end;
  380. function def_internalerror(i : longint) : boolean;
  381. begin
  382. do_comment(V_Fatal+V_LineInfo,'Internal error '+tostr(i));
  383. {$ifdef EXTDEBUG}
  384. { Internalerror() and def_internalerror() do not
  385. have a stackframe }
  386. dump_stack(stdout,get_caller_frame(get_frame));
  387. {$endif EXTDEBUG}
  388. def_internalerror:=true;
  389. end;
  390. function def_CheckVerbosity(v:longint):boolean;
  391. begin
  392. result:=status.use_bugreport or
  393. ((v<>V_None) and
  394. ((status.verbosity and (v and V_LevelMask))=(v and V_LevelMask)));
  395. end;
  396. procedure def_initsymbolinfo;
  397. begin
  398. end;
  399. procedure def_donesymbolinfo;
  400. begin
  401. end;
  402. procedure def_extractsymbolinfo;
  403. begin
  404. end;
  405. function def_openinputfile(const filename: TPathStr): tinputfile;
  406. begin
  407. def_openinputfile:=tdosinputfile.create(filename);
  408. end;
  409. Function def_GetNamedFileTime (Const F : TPathStr) : Longint;
  410. begin
  411. Result:=FileAge(F);
  412. end;
  413. end.