TextFile.pas
上传用户:yj_qiu
上传日期:2022-08-08
资源大小:23636k
文件大小:9k
源码类别:

游戏引擎

开发平台:

Delphi

  1. (*
  2.  @Abstract(Text file unit)
  3.  (C) 2004-2007 George "Mirage" Bakhtadze. <a href="http://www.casteng.com">www.casteng.com</a> <br>
  4.  The source code may be used under either MPL 1.1 or LGPL 2.1 license. See included license.txt file <br>
  5.  Unit contains some text file related utilities and logging class
  6. *)
  7. {$Include GDefines.inc}
  8. unit TextFile;
  9. interface
  10. {$IFDEF LOGGING}
  11. uses
  12. //     {$IFDEF USEFASTMM} FastMM4, {$ENDIF}
  13.      SysUtils, OSUtils
  14.      {$IFDEF MULTITHREADLOG}
  15. //     {$IFDEF FPC} , FPCWindows {$ENDIF}
  16.      , Windows
  17.      {$ENDIF};
  18. {$ENDIF}
  19. type
  20.   // Levels of importance of log messages
  21.   TLogLevel = (lkDebug, lkInfo, lkNotice, lkWarning, lkError, lkFatalError);
  22.   // Log level setting type
  23.   TLogLevels = set of TLogLevel;
  24. const
  25. //  lkDebug = 0; lkInfo = 1; lkNotice = 2; lkWarning = 3; lkError = 4; lkFatalError = 5; lkTitle = lkNotice;
  26.   lkPrefix: array[TLogLevel] of string = (' (D)  ', ' (i)  ', ' (I)  ', '(WW)   ', '(EE)   ', '(!!) ');
  27. //  lfLogDebug = 1 shl 8; lfLogInfo = 1 shl 9; lfLogNotices = 1 shl 10; lfLogTitles = lfLogNotices;
  28. //  lfLogWarnings = 1 shl 11; lfLogErrors = 1 shl 12; LogFatalErrors = 1 shl 13;
  29.   llMax: TLogLevels    = [lkDebug, lkInfo, lkNotice, lkWarning, lkError, lkFatalError];
  30.   llMedium: TLogLevels = [lkNotice, lkWarning, lkError, lkFatalError];
  31.   llMin: TLogLevels    = [lkError, lkFatalError];
  32. //  lmMask: array[0..lkFatalError] of Integer = (lfLogDebug, lfLogInfo, lfLogNotices, lfLogWarnings, lfLogErrors, LogFatalErrors);
  33. type
  34.   // Log date and time setting type
  35.   TLogTimeFormat = (// doesn't output any time information
  36.                     lfNone,
  37.                     // include date in the log
  38.                     lfDate,
  39.                     // include time in the log
  40.                     lfTime,
  41.                     // include date and time in the log
  42.                     lfDateTime,
  43.                     // include time elapsed since startup in the log
  44.                     lfElapsed);
  45.   // Class reference to log session class
  46.   CLogSession = class of TLogSession;
  47.   { @Abstract(Logger class) }
  48.   TLogSession = class
  49.   private
  50.     LogFile: Text;
  51.     FLogLevels: TLogLevels;
  52.     {$IFDEF MULTITHREADLOG}
  53.     CriticalSection: _RTL_CRITICAL_SECTION;                                // ToDo: Replace with a user-mode sync
  54.     {$ENDIF}
  55.     LogKindCount: array[TLogLevel] of Integer;
  56.     procedure SetMode(NewMode: TLogLevels);
  57.   protected
  58.     // Log mode titles
  59.     ModeTitles: array[TLogLevel] of string;
  60.     // Determines which date or time to include in the log
  61.     TimeFormat: TLogTimeFormat;
  62.     // Startup timestamp in milliseconds
  63.     StartedMs: Cardinal;
  64.     // Appends a string to log. Thread-safe if <b>MULTITHREADLOG</b> defined
  65.     procedure AppendLog(const Desc: string; Level: TLogLevel = lkInfo); virtual;
  66.   public
  67.     { Initializes a log session with the specified log file name, time and level settings }
  68.     constructor Init(const FileName: string; ATimeFormat: TLogTimeFormat; ALevels: TLogLevels); virtual;
  69.     // Destructor
  70.     destructor Shutdown; virtual;
  71.     // Logs a string <b>Desc</b> if <b>Level</b> matches current logging level (see @Link(LogLevels))
  72.     procedure Log(const Desc: string; Level: TLogLevel = lkInfo);
  73.     // Set of levels which to include in the log
  74.     property LogLevels: TLogLevels read FLogLevels write SetMode;
  75.   end;
  76. //function SetLength(S : string; DLength : word):string;
  77. function SkipBeforeSTR(var TextFile : text; SkipSTR : string):boolean;
  78. function ReadLine(var TextFile : text):string;
  79. // Replaces logger with a new one of the specified class
  80. procedure ChangeLoggerClass(NewClass: CLogSession);
  81. var
  82.   // Current logger
  83.   Log: TLogSession;
  84. implementation
  85. function SkipBeforeSTR(var TextFile : text; SkipSTR : string):boolean;
  86. var s: string;
  87. begin
  88.   repeat
  89.     readln(TextFile, s);
  90.     if s = SkipSTR then begin
  91.       Result := True; Exit;
  92.     end;
  93.   until False;
  94.   Result := False;
  95. end;
  96. function ReadLine(var TextFile : Text):string;
  97. var i: Word; var s: string;
  98. begin
  99.   if EOF(TextFile) then exit;
  100.   i:=1;
  101.   repeat
  102.     ReadLn(TextFile,s);
  103.   until  (s<>'') and (s[1]<>'#') or EOF(TextFile);
  104.   if s<>'' then begin
  105.     while s[i]=' ' do inc(i);
  106.     if i=Length(s) then s:='' else s:=Copy(s, i, Length(s)-i+1);
  107.   end;
  108.   Result:=s;
  109. end;
  110. procedure ChangeLoggerClass(NewClass: CLogSession);
  111. var NewLog: TLogSession;
  112. begin
  113.   if not Assigned(Log) or (NewClass = nil) then Exit;
  114.   NewLog := NewClass.Create;
  115.   NewLog.LogKindCount := Log.LogKindCount;
  116.   NewLog.TimeFormat   := Log.TimeFormat;
  117.   NewLog.LogLevels    := Log.LogLevels;
  118.   NewLog.StartedMs    := Log.StartedMs;
  119.   AssignFile(NewLog.LogFile, TTextRec(Log.LogFile).Name);
  120.   {$IFDEF MULTITHREADLOG}
  121.   NewLog.CriticalSection := Log.CriticalSection;
  122.   {$ENDIF}
  123.   {$IFDEF MULTITHREADLOG}
  124.   EnterCriticalSection(NewLog.CriticalSection);
  125.   {$ENDIF}
  126.   Log.Free;
  127.   Log := NewLog;
  128.   {$IFDEF MULTITHREADLOG}
  129.   LeaveCriticalSection(NewLog.CriticalSection);
  130.   {$ENDIF}
  131.   Log.Log('Logger class changed to "' + NewClass.ClassName + '"', lkNotice);
  132. end;
  133. { TLogSession }
  134. procedure TLogSession.SetMode(NewMode: TLogLevels);
  135. var ModeStr: string; i: Integer;
  136. begin
  137.   {$IFDEF LOGGING}
  138.   ModeStr := '[';
  139.   for i := Ord(Low(TLogLevel)) to Ord(High(TLogLevel)) do if TLogLevel(i) in NewMode then begin
  140.     if ModeStr <> '[' then ModeStr := ModeStr + ', ';
  141.     ModeStr := ModeStr + ModeTitles[TLogLevel(i)] + ' ' + Trim(lkPrefix[TLogLevel(i)]);
  142.   end;
  143.   ModeStr := ModeStr + ']';
  144.   if NewMode = [] then ModeStr := 'nothing';
  145.   Log('Logging ' + ModeStr, lkNotice);
  146.   FLogLevels := NewMode;
  147.   {$ENDIF}
  148. end;
  149. constructor TLogSession.Init(const FileName: string; ATimeFormat: TLogTimeFormat; ALevels: TLogLevels);
  150. var i: Integer; ModeStr: string;
  151. begin
  152.   {$IFDEF LOGGING}
  153.   TextFile.Log := Self;
  154.   {$IFDEF MULTITHREADLOG}
  155.   InitializeCriticalSection(CriticalSection);
  156.   {$ENDIF}
  157.   ModeTitles[lkDebug]      := 'debug info';
  158.   ModeTitles[lkInfo]       := 'info';
  159.   ModeTitles[lkNotice]     := 'notices';
  160.   ModeTitles[lkWarning]    := 'warnings';
  161.   ModeTitles[lkError]      := 'errors';
  162.   ModeTitles[lkFatalError] := 'fatal errors';
  163.   if Pos(':', FileName) > 0 then AssignFile(LogFile, Filename) else AssignFile(LogFile, GetCurrentDir+''+Filename);
  164.   {$I-}
  165.   Rewrite(LogFile); CloseFile(LogFile);
  166.   if IOResult <> 0 then ALevels := [];
  167.   StartedMs := GetCurrentMs;
  168.   case TimeFormat of
  169.     lfNone:     ModeStr := 'no timestamp mode.';
  170.     lfDate:     ModeStr := 'date only mode.';
  171.     lfTime:     ModeStr := 'time only mode.';
  172.     lfDateTime: ModeStr := 'date and time mode.';
  173.     lfElapsed:  ModeStr := 'elapsed time mode.';
  174.   end;
  175.   TimeFormat := ATimeFormat;
  176.   LogLevels  := ALevels;
  177.   Log('Log subsystem started in ' + ModeStr, lkNotice);
  178.   for i := Ord(Low(TLogLevel)) to Ord(High(TLogLevel)) do LogKindCount[TLogLevel(i)] := 0;
  179.   {$ENDIF}
  180. end;
  181. destructor TLogSession.Shutdown;
  182. begin
  183.   {$IFDEF LOGGING}
  184.   Log('Logged fatal errors: ' + IntToStr(LogKindCount[lkFatalError]) +
  185.                  ', errors: ' + IntToStr(LogKindCount[lkError])      +
  186.                ', warnings: ' + IntToStr(LogKindCount[lkWarning])    +
  187.                  ', titles: ' + IntToStr(LogKindCount[lkNotice])     +
  188.                   ', infos: ' + IntToStr(LogKindCount[lkInfo])       +
  189.              ', debug info: ' + IntToStr(LogKindCount[lkDebug]) );
  190.   Log('Log session shutdown');
  191.   TextFile.Log := nil;
  192.   {$IFDEF MULTITHREADLOG}
  193.   DeleteCriticalSection(CriticalSection);
  194.   {$ENDIF}
  195.   {$ENDIF}
  196. end;
  197. procedure TLogSession.Log(const Desc: string; Level: TLogLevel = lkInfo);
  198. begin
  199.   {$IFDEF LOGGING}
  200.   if not (Level in LogLevels) then Exit;
  201.   {$IFDEF MULTITHREADLOG}
  202.   EnterCriticalSection(CriticalSection);
  203.   {$ENDIF}
  204.   AppendLog(Desc, Level);
  205.   {$IFDEF MULTITHREADLOG}
  206.   LeaveCriticalSection(CriticalSection);
  207.   {$ENDIF}
  208.   {$ENDIF}
  209. end;
  210. procedure TLogSession.AppendLog(const Desc: string; Level: TLogLevel = lkInfo);
  211. begin
  212.   {$IFDEF LOGGING}
  213. {$I-}
  214.   Append(LogFile);
  215.   if IOResult <> 0 then Exit;
  216.   case TimeFormat of
  217.     lfNone:     WriteLn(LogFile, lkPrefix[Level] + Desc);
  218.     lfDate:     WriteLn(LogFile, DateToStr(Now) + #9 + lkPrefix[Level] + Desc);
  219.     lfTime:     WriteLn(LogFile, TimeToStr(Now) + #9 + lkPrefix[Level] + Desc);
  220.     lfDateTime: WriteLn(LogFile, DateTimeToStr(Now) + #9 + lkPrefix[Level] + Desc);
  221.     lfElapsed:  WriteLn(LogFile, IntToStr(GetCurrentMs-StartedMs) + #9 + lkPrefix[Level] + Desc);
  222.   end;
  223.   CloseFile(LogFile);
  224.   Inc(LogKindCount[Level]);
  225.   {$ENDIF}
  226. end;
  227. initialization
  228.   {$IFDEF LOGGING}  
  229.   Log := TLogSession.Init(Copy(ExtractFileName(ParamStr(0)), 1, Length(ExtractFileName(ParamStr(0))) - Length(ExtractFileExt(ParamStr(0)))) + '.log', lfElapsed, llMax);
  230.   {$ELSE}
  231.   Log := TLogSession.Init('', lfNone, llMin);
  232.   {$ENDIF}
  233. finalization
  234.   Log.Shutdown;
  235. end.