359 lines
9.9 KiB
ObjectPascal
359 lines
9.9 KiB
ObjectPascal
{
|
|
********************************************************************************
|
|
|
|
YaPeTaVi - Yet another Periodic Table Viewer
|
|
Copyright (C) 2000-2012 Geoffray Levasseur <geoffray.levasseurbrandin@numericable.fr>.
|
|
All rights reserved.
|
|
http://www.geoffray-levasseur.org/
|
|
|
|
This program is free software; you can redistribute it and/or modify it under
|
|
the terms of the GNU General Public License as published by the Free Software
|
|
Foundation; either version 3 of the License, or (at your option) any later
|
|
version.
|
|
|
|
This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License along with
|
|
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
|
Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
********************************************************************************
|
|
|
|
Description:
|
|
Console debuging facilities
|
|
|
|
}
|
|
unit uDebug;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes;
|
|
|
|
type
|
|
TVerboseLevel = (vlFull, vlHigh, vlLow, vlNone);
|
|
|
|
var
|
|
DebugLevel: Integer;
|
|
VerboseLevel: TVerboseLevel;
|
|
LogError: Boolean;
|
|
sLogFileName: string;
|
|
FLogFile: Text;
|
|
|
|
// init logging facilities
|
|
function InitDbg(const FileName: string): Boolean;
|
|
|
|
// close logging file
|
|
procedure TerminateDbg;
|
|
|
|
// print and log messages
|
|
procedure PrintDbg(Mes: string; Verbosity: TVerboseLevel);
|
|
procedure PrintDbg(Mes: string);
|
|
procedure PrintLnDbg(Mes: string; Verbosity: TVerboseLevel);
|
|
procedure PrintLnDbg(Mes: TStringList; Verbosity: TVerboseLevel);
|
|
procedure PrintLnDbg(Verbosity: TVerboseLevel);
|
|
procedure PrintLnDbg(Mes: string);
|
|
procedure PrintDbgStat(Stat: Boolean; Verbosity: TVerboseLevel);
|
|
procedure PrintDbgResult(Res: Boolean; Verbosity: TVerboseLevel);
|
|
procedure PrintDbgResult(Res: string; Verbosity: TVerboseLevel);
|
|
|
|
// put full informations about heap inside a string
|
|
function GetHeapStatus(aHS: THeapStatus): string;
|
|
|
|
implementation
|
|
|
|
uses
|
|
Crt, SysUtils;
|
|
|
|
const
|
|
dbgStatOk = '-';
|
|
dbgStatWarn = '!';
|
|
dbgOk = 'Ok';
|
|
dbgFail = 'Fail';
|
|
sTimeJump = ' '; //number of space = time length with braces
|
|
|
|
resourcestring
|
|
rsErrorBase = '*** ERROR: ';
|
|
rsWarningBase = '! WARNING: ';
|
|
rsInfoBase = 'Info: ';
|
|
rsDebugBase = '[Debug]: ';
|
|
|
|
rsErrorLogrotate = 'E logrotate failed on file %s';
|
|
rsErrorButLogrotate = 'E logrotate worked but the log file %s still exists';
|
|
rsErrorCreatingLogfile = 'E could not create log file %s';
|
|
rsErrorWritingLogFile = 'E unable to write in logfile %s';
|
|
rsWarningNoLogfile = 'W no log file will be created, ' +
|
|
'logging on stdout (console) only';
|
|
rsInfoLoggingStarted = 'Logging started: %s';
|
|
rsInfoLoggingTerminated = 'Closing log file %s: application terminated';
|
|
|
|
procedure LoggingError(Msg: string);
|
|
begin
|
|
LogError := True;
|
|
PrintLnDbg(Msg, vlLow);
|
|
PrintLnDbg(rsWarningNoLogfile, vlLow);
|
|
end;
|
|
|
|
//create logfile and rotate old ones (10 max)
|
|
function InitDbg(const FileName: string): Boolean;
|
|
var
|
|
Count: Byte;
|
|
I: Integer;
|
|
F: File;
|
|
Orig, Dest: string;
|
|
begin
|
|
{$I-}
|
|
//init some vars
|
|
Count := 1;
|
|
Result := True;
|
|
//first step: do the logrotate (10 logfile max fixed)
|
|
if FileExists(Trim(FileName)) then
|
|
while FileExists(Trim(FileName) + '.' + IntToStr(Count)) do
|
|
Inc(Count)
|
|
else
|
|
Count := 0;
|
|
if Count > 0 then
|
|
for I := Count downto 1 do
|
|
begin
|
|
Assign(F, Trim(FileName) + '.' + IntToStr(I - 1));
|
|
if I = 1 then
|
|
Orig := Trim(FileName)
|
|
else
|
|
Orig := Trim(FileName) + '.' + IntToStr(I - 1);
|
|
Dest := Trim(FileName) + '.' + IntToStr(I);
|
|
if I >= 10 then
|
|
if not FileIsReadOnly(Orig) then
|
|
Erase(F)
|
|
else
|
|
begin
|
|
LoggingError(Format(rsErrorLogrotate, [Trim(FileName)]));
|
|
Result := False;
|
|
Exit;
|
|
end
|
|
else
|
|
if (not FileIsReadOnly(Orig)) and (not FileExists(Dest)) then
|
|
RenameFile(Orig, Dest)
|
|
else
|
|
begin
|
|
LoggingError(Format(rsErrorLogrotate, [Trim(FileName)]));
|
|
Result := False;
|
|
Exit;
|
|
end;
|
|
end;
|
|
{$I+}
|
|
//second step: check if file can be safely created and create it
|
|
if FileExists(Trim(FileName)) then
|
|
begin
|
|
LoggingError(Format(rsErrorButLogrotate, [Trim(FileName)]));
|
|
Result := False;
|
|
Exit;
|
|
end;
|
|
Assign(FLogFile, Trim(FileName));
|
|
{$I-}
|
|
Rewrite(FLogFile);
|
|
{$I+}
|
|
if IOResult <> 0 then
|
|
begin
|
|
LoggingError(Format(rsErrorCreatingLogfile, [Trim(FileName)]));
|
|
Result := False;
|
|
Exit;
|
|
end;
|
|
//third step: write header and assign vars
|
|
LogError := False;
|
|
sLogFileName := Trim(FileName);
|
|
PrintLnDbg(Format(rsInfoLoggingStarted, [sLogFileName]), vlLow);
|
|
end;
|
|
|
|
procedure TerminateDbg;
|
|
begin
|
|
PrintLnDbg(Format(rsInfoLoggingTerminated, [sLogFileName]), vlLow);
|
|
if (not LogError) and (Trim(sLogFileName) <> '') then
|
|
CloseFile(FLogFile);
|
|
end;
|
|
|
|
function VerbosityToInt(V: TVerboseLevel): integer;
|
|
begin
|
|
Result := 4; //default is all the messages to be shown
|
|
case V of
|
|
vlFull: Result := 4;
|
|
vlHigh: Result := 2;
|
|
vlLow: Result := 1;
|
|
vlNone: Result := 0; //nothing is displayed
|
|
end;
|
|
end;
|
|
|
|
procedure PrintDbg(Mes: string; Verbosity: TVerboseLevel);
|
|
var
|
|
I: integer;
|
|
Err: Boolean;
|
|
C: Char;
|
|
LineBegining: Boolean;
|
|
begin
|
|
//showing debugging message only if Debug is defined
|
|
{$IFNDEF Debug}
|
|
if LineBegining and (Length(Mes) > 2) and (Mes[2] = ' ') and
|
|
(Mes[1] = 'D') then
|
|
Exit;
|
|
{$ENDIF}
|
|
//if it's not meant to be displayed get out of here
|
|
if VerbosityToInt(Verbosity) > VerbosityToInt(VerboseLevel) then
|
|
Exit;
|
|
//init error state
|
|
{$I-}
|
|
Err := False;
|
|
//display time only if we are on a new line
|
|
try
|
|
LineBegining := WhereX <= 1;
|
|
if LineBegining or ((Length(Mes) > Length(sTimeJump)) and
|
|
(Copy(Mes, 1, Length(sTimeJump)) = sTimeJump)) then
|
|
begin
|
|
Write('[' + TimeToStr(Time) + '] ');
|
|
if (not LogError) and (Trim(sLogFileName) <> '') then
|
|
begin
|
|
Write(FLogFile, '[' + TimeToStr(Time) + '] ');
|
|
Err := (IOResult <> 0) or Err;
|
|
end;
|
|
//this is used in case where indentation is needed in log
|
|
if DebugLevel > 0 then
|
|
for I := 0 to DebugLevel do
|
|
begin
|
|
Write(' '); //this is 3 spaces
|
|
if (not LogError) and (Trim(sLogFileName) <> '') then
|
|
begin
|
|
Write(FLogFile, ' '); //this is 3 spaces
|
|
Err := (IOResult <> 0) or Err;
|
|
end;
|
|
end;
|
|
end;
|
|
// we use the first char to know if it's error warning or info
|
|
if LineBegining and (Length(Mes) > 2) and (Mes[2] = ' ') and
|
|
(Mes[1] in ['E', 'W', 'i', 'D']) then
|
|
begin
|
|
C := Mes[1];
|
|
Mes := Copy(Mes, 3, Length(Mes) - 2);
|
|
case C of
|
|
'E': Mes := rsErrorBase + Mes;
|
|
'W': Mes := rsWarningBase + Mes;
|
|
'i': Mes := rsInfoBase + Mes;
|
|
'D': Mes := rsDebugBase + Mes;
|
|
end;
|
|
end;
|
|
//write the message
|
|
Write(Mes);
|
|
if (not LogError) and (Trim(sLogFileName) <> '') then
|
|
begin
|
|
Write(FLogFile, Mes);
|
|
Err := (IOResult <> 0) or Err;
|
|
end;
|
|
except
|
|
Err := True;
|
|
end;
|
|
{$I+}
|
|
//force truely writing the file
|
|
if not LogError then
|
|
Flush(FLogFile);
|
|
//if error occurs somewhere, trigger an error
|
|
if Err then
|
|
LoggingError(Format(rsErrorWritingLogFile, [sLogFileName]));
|
|
end;
|
|
|
|
procedure PrintDbg(Mes: string);
|
|
begin
|
|
PrintDbg(Mes, vlFull);
|
|
end;
|
|
|
|
procedure PrintLnDbg(Mes: TStringList; Verbosity: TVerboseLevel);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if VerbosityToInt(Verbosity) > VerbosityToInt(VerboseLevel) then
|
|
Exit;
|
|
for I := 0 to Mes.Count - 1 do
|
|
if I = 0 then
|
|
PrintLnDbg(Mes[I], Verbosity)
|
|
else
|
|
PrintDbg(sTimeJump + Mes[I] + sLineBreak, Verbosity);
|
|
end;
|
|
|
|
procedure PrintLnDbg(Mes: string);
|
|
begin
|
|
PrintLnDbg(Mes, vlFull);
|
|
end;
|
|
|
|
procedure PrintLnDbg(Mes: string; Verbosity: TVerboseLevel);
|
|
begin
|
|
if VerbosityToInt(Verbosity) > VerbosityToInt(VerboseLevel) then
|
|
Exit;
|
|
PrintDbg(Mes + sLineBreak, Verbosity);
|
|
end;
|
|
|
|
procedure PrintLnDbg(Verbosity: TVerboseLevel);
|
|
begin
|
|
if VerbosityToInt(Verbosity) > VerbosityToInt(VerboseLevel) then
|
|
Exit;
|
|
Writeln;
|
|
if (not LogError) and (Trim(sLogFileName) <> '') then
|
|
Writeln(FLogFile);
|
|
end;
|
|
|
|
procedure PrintDbgStat(Stat: Boolean; Verbosity: TVerboseLevel);
|
|
begin
|
|
if VerbosityToInt(Verbosity) > VerbosityToInt(VerboseLevel) then
|
|
Exit;
|
|
if Stat then
|
|
PrintDbg(dbgStatOk, Verbosity)
|
|
else
|
|
PrintDbg(dbgStatWarn, Verbosity);
|
|
end;
|
|
|
|
procedure PrintDbgResult(Res: Boolean; Verbosity: TVerboseLevel);
|
|
begin
|
|
if VerbosityToInt(Verbosity) > VerbosityToInt(VerboseLevel) then
|
|
Exit;
|
|
if Res then
|
|
PrintLnDbg(dbgOk, Verbosity)
|
|
else
|
|
PrintLnDbg(dbgFail, Verbosity);
|
|
end;
|
|
|
|
procedure PrintDbgResult(Res: string; Verbosity: TVerboseLevel);
|
|
begin
|
|
if VerbosityToInt(Verbosity) > VerbosityToInt(VerboseLevel) then
|
|
Exit;
|
|
PrintLnDbg(Res, Verbosity);
|
|
end;
|
|
|
|
function GetHeapStatus(aHS: THeapStatus): string;
|
|
begin
|
|
Result := Format(
|
|
'Heap Status: ' + LineEnding + LineEnding +
|
|
'Addr Space: ' + #9 + ' %d ' + LineEnding +
|
|
'Uncommitted: ' + #9 + ' %d ' + LineEnding +
|
|
'Committed: ' + #9 + ' %d ' + LineEnding +
|
|
'Allocated: ' + #9 + ' %d ' + LineEnding +
|
|
'Free: ' + #9 + ' %d ' + LineEnding +
|
|
'Free Small: ' + #9 + ' %d ' + LineEnding +
|
|
'Free Big: ' + #9 + ' %d ' + LineEnding +
|
|
'Unused: ' + #9 + ' %d ' + LineEnding +
|
|
'Overhead: ' + #9 + ' %d ' + LineEnding +
|
|
'Heap Errorcode:' + #9 + ' %d ',
|
|
[aHS.TotalAddrSpace, aHS.TotalUncommitted, aHS.TotalCommitted,
|
|
aHS.TotalAllocated, aHS.TotalFree, aHS.FreeSmall, aHS.FreeBig,
|
|
aHS.Unused, aHS.Overhead, aHS.HeapErrorCode]);
|
|
end;
|
|
|
|
initialization
|
|
{$IFDEF Debug}
|
|
VerboseLevel := vlFull;
|
|
{$ELSE}
|
|
VerboseLevel := vlLow;
|
|
{$ENDIF}
|
|
DebugLevel := 0;
|
|
LogError := True; //means that we can't write in the log file as it's not opened
|
|
end.
|
|
|