1 (* Copyright (C) Doom 2D: Forever Developers
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, version 3 of the License ONLY.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * 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, see <http://www.gnu.org/licenses/>.
15 {$INCLUDE ../shared/a_modes.inc}
26 TWriteMode
= (WM_NEWFILE
, WM_OLDFILE
);
27 TMsgType
= (Fatal
, Warning
, Notify
);
30 procedure e_InitLog (fFileName
: String; fWriteMode
: TWriteMode
);
31 procedure e_DeinitLog ();
33 procedure e_SetSafeSlowLog (slowAndSafe
: Boolean);
35 procedure e_WriteLog (TextLine
: String; RecordCategory
: TMsgType
; WriteTime
: Boolean=True);
37 function DecodeIPV4 (ip
: LongWord
): string;
39 // start Write/WriteLn driver. it will write everything to cbuf.
40 procedure e_InitWritelnDriver ();
42 procedure e_LogWritefln (const fmt
: AnsiString
; args
: array of const; category
: TMsgType
=TMsgType
.Notify
; writeTime
: Boolean=true; writeConsole
: Boolean=true);
43 procedure e_LogWriteln (const s
: AnsiString
; category
: TMsgType
=TMsgType
.Notify
; writeTime
: Boolean=true);
45 procedure e_WriteStackTrace (const msg
: AnsiString
);
58 driverInited
: Boolean = false;
61 function DecodeIPV4 (ip
: LongWord
): string;
63 {$IFDEF FPC_LITTLE_ENDIAN}
64 Result
:= Format('%d.%d.%d.%d', [ip
and $FF, (ip
shr 8) and $FF, (ip
shr 16) and $FF, (ip
shr 24)]);
66 Result
:= Format('%d.%d.%d.%d', [(ip
shr 24), (ip
shr 16) and $FF, (ip
shr 8) and $FF, ip
and $FF]);
71 function consoleAllow (const s
: String): Boolean;
74 if Pos('[Chat] ', s
) = 1 then
80 procedure e_WriteLog (TextLine
: String; RecordCategory
: TMsgType
; WriteTime
: Boolean=True);
82 e_LogWritefln('%s', [TextLine
], RecordCategory
, WriteTime
, consoleAllow(TextLine
));
86 procedure e_LogWriteln (const s
: AnsiString
; category
: TMsgType
=TMsgType
.Notify
; writeTime
: Boolean=true);
88 e_LogWritefln('%s', [s
], category
, writeTime
, consoleAllow(s
));
92 // returns formatted string if `writerCB` is `nil`, empty string otherwise
93 //function formatstrf (const fmt: AnsiString; args: array of const; writerCB: TFormatStrFCallback=nil): AnsiString;
94 //TFormatStrFCallback = procedure (constref buf; len: SizeUInt);
96 procedure conwriter (constref buf
; len
: SizeUInt
);
105 if (len
< 1) then exit
;
109 cstr
:= GetMem(len
+ 1);
110 for slen
:= 0 to len
- 1 do
111 cstr
[slen
] := Chr(b
[slen
]);
119 if (len
> 255) then slen
:= 255 else slen
:= Integer(len
);
120 Move(b
^, ss
[1], slen
);
121 ss
[0] := AnsiChar(slen
);
131 xlogFileOpened
: Boolean = false;
132 xlogPrefix
: AnsiString
;
133 xlogLastWasEOL
: Boolean = false;
134 xlogWantSpace
: Boolean = false;
135 xlogSlowAndSafe
: Boolean = false;
138 procedure e_SetSafeSlowLog (slowAndSafe
: Boolean);
140 xlogSlowAndSafe
:= slowAndSafe
;
141 if xlogSlowAndSafe
and xlogFileOpened
then
144 xlogFileOpened
:= false;
149 procedure logwriter (constref buf
; len
: SizeUInt
);
155 if (len
< 1) then exit
;
157 if xlogLastWasEOL
then
159 write(xlogFile
, xlogPrefix
);
160 xlogLastWasEOL
:= false;
161 xlogWantSpace
:= true;
166 while (slen
< len
) and (b
[slen
] <> 13) and (b
[slen
] <> 10) do Inc(slen
);
167 if (slen
> 255) then slen
:= 255;
171 if xlogWantSpace
then begin write(xlogFile
, ' '); xlogWantSpace
:= false; end;
172 Move(b
^, ss
[1], slen
);
173 ss
[0] := AnsiChar(slen
);
180 if (len
> 0) and ((b
[0] = 13) or (b
[0] = 10)) then
182 if (b
[0] = 13) then begin len
-= 1; b
+= 1; end;
183 if (len
> 0) and (b
[0] = 10) then begin len
-= 1; b
+= 1; end;
184 xlogLastWasEOL
:= false;
185 writeln(xlogFile
, '');
186 write(xlogFile
, xlogPrefix
);
192 procedure e_LogWritefln (const fmt
: AnsiString
; args
: array of const; category
: TMsgType
=TMsgType
.Notify
; writeTime
: Boolean=true; writeConsole
: Boolean=true);
194 procedure xwrite (const s
: AnsiString
);
196 if (Length(s
) = 0) then exit
;
197 logwriter(PAnsiChar(s
)^, Length(s
));
201 if driverInited
and (length(fmt
) > 0) and writeConsole
then
204 TMsgType
.Fatal
: write('FATAL: ');
205 TMsgType
.Warning
: write('WARNING: ');
207 formatstrf(fmt
, args
, conwriter
);
211 if (FileName
= '') then exit
;
213 if not xlogFileOpened
then
215 AssignFile(xlogFile
, FileName
);
217 if FileExists(FileName
) then Append(xlogFile
) else Rewrite(xlogFile
);
218 xlogFileOpened
:= true;
226 writeln(xlogFile
, '--- Log started at ', TimeToStr(Time
), ' ---');
227 FirstRecord
:= false;
234 xlogPrefix
+= TimeToStr(Time
);
238 TMsgType
.Fatal
: xlogPrefix
+= '!!!';
239 TMsgType
.Warning
: xlogPrefix
+= '! ';
240 TMsgType
.Notify
: xlogPrefix
+= '***';
243 xlogLastWasEOL
:= true; // to output prefix
244 xlogWantSpace
:= true; // after prefix
245 formatstrf(fmt
, args
, logwriter
);
246 if not xlogLastWasEOL
247 then writeln(xlogFile
, '')
248 else writeln(xlogFile
, xlogPrefix
);
250 if xlogSlowAndSafe
and xlogFileOpened
then
253 xlogFileOpened
:= false;
256 //if fopened then CloseFile(xlogFile);
260 procedure e_InitLog (fFileName
: String; fWriteMode
: TWriteMode
);
262 if xlogFileOpened
then CloseFile(xlogFile
);
263 xlogFileOpened
:= false;
264 FileName
:= fFileName
;
265 if (fWriteMode
= TWriteMode
.WM_NEWFILE
) then
268 if FileExists(FileName
) then DeleteFile(FileName
);
277 procedure e_WriteStackTrace (const msg
: AnsiString
);
281 e_LogWriteln(msg
, TMsgType
.Fatal
);
282 if (Length(FileName
) > 0) then
284 if xlogFileOpened
then CloseFile(xlogFile
);
285 xlogFileOpened
:= false;
286 AssignFile(tfo
, FileName
);
288 if (IOResult
<> 0) then Rewrite(tfo
);
289 if (IOResult
= 0) then begin writeln(tfo
, '====================='); DumpExceptionBackTrace(tfo
); CloseFile(tfo
); end;
294 procedure e_DeinitLog ();
296 if xlogFileOpened
then CloseFile(xlogFile
);
297 xlogFileOpened
:= false;
301 // ////////////////////////////////////////////////////////////////////////// //
302 (* Write/WriteLn driver *)
306 // TAB: tab space = 4
308 // userData[1]: current x (for tabs)
309 // userData[2]: #13 was eaten, we should skip next #10
312 TDevFunc
= function (var f
: TTextRec
): Integer;
319 procedure ProcessOutput (var tf
: TTextRec
; buf
: PChar
; count
: Integer);
326 x
:= tf
.userData
[udX
];
327 wcr
:= (tf
.userData
[udWasCR
] <> 0);
330 // look for some special char
336 if (ch
= #13) or (ch
= #10) or (ch
= #9) or (ch
= #8) then break
;
346 cbufPutChars(buf
, f
);
352 // process special chars
369 if (ch
= #13) or (ch
= #10) then
374 if not wcr
or (ch
<> #10) then
383 tf
.userData
[udX
] := x
;
384 tf
.userData
[udWasCR
] := ord(wcr
);
388 function DevOpen (var f
: TTextRec
): Integer;
390 f
.userData
[udX
] := 0;
391 f
.userData
[udWasCR
] := 0;
397 function DevInOut (var f
: TTextRec
): Integer;
403 buf
:= Pointer(f
.BufPtr
);
405 if sz
> 0 then ProcessOutput(f
, buf
, sz
);
410 function DevFlush (var f
: TTextRec
): Integer;
412 result
:= DevInOut(f
);
415 function DevClose (var f
: TTextRec
): Integer;
421 procedure e_InitWritelnDriver ();
423 if not driverInited
then
425 driverInited
:= true;
426 with TTextRec(output
) do
431 BufSize
:= SizeOf(Buffer
);
434 OpenFunc
:= @DevOpen
;
435 InOutFunc
:= @DevInOut
;
436 FlushFunc
:= @DevFlush
;
437 CloseFunc
:= @DevClose
;
446 //e_InitWritelnDriver();