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, either version 3 of the License, or
6 * (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.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 {$INCLUDE ../shared/a_modes.inc}
27 TWriteMode
= (WM_NEWFILE
, WM_OLDFILE
);
28 TMsgType
= (Fatal
, Warning
, Notify
);
31 procedure e_InitLog (fFileName
: String; fWriteMode
: TWriteMode
);
32 procedure e_DeinitLog ();
34 procedure e_SetSafeSlowLog (slowAndSafe
: Boolean);
36 procedure e_WriteLog (TextLine
: String; RecordCategory
: TMsgType
; WriteTime
: Boolean=True);
38 function DecodeIPV4 (ip
: LongWord): string;
40 // start Write/WriteLn driver. it will write everything to cbuf.
41 procedure e_InitWritelnDriver ();
43 procedure e_LogWritefln (const fmt
: AnsiString; args
: array of const; category
: TMsgType
=TMsgType
.Notify
; writeTime
: Boolean=true);
44 procedure e_LogWriteln (const s
: AnsiString; category
: TMsgType
=TMsgType
.Notify
; writeTime
: Boolean=true);
47 procedure e_WriteStackTrace (const msg
: AnsiString);
51 e_WriteToStdOut
: Boolean = False;
62 driverInited
: Boolean = false;
65 function DecodeIPV4 (ip
: LongWord): string;
67 Result
:= Format('%d.%d.%d.%d', [ip
and $FF, (ip
shr 8) and $FF, (ip
shr 16) and $FF, (ip
shr 24)]);
71 procedure e_WriteLog (TextLine
: String; RecordCategory
: TMsgType
; WriteTime
: Boolean=True);
73 e_LogWritefln('%s', [TextLine
], RecordCategory
, WriteTime
);
77 procedure e_LogWriteln (const s
: AnsiString; category
: TMsgType
=TMsgType
.Notify
; writeTime
: Boolean=true);
79 e_LogWritefln('%s', [s
], category
, writeTime
);
83 // returns formatted string if `writerCB` is `nil`, empty string otherwise
84 //function formatstrf (const fmt: AnsiString; args: array of const; writerCB: TFormatStrFCallback=nil): AnsiString;
85 //TFormatStrFCallback = procedure (constref buf; len: SizeUInt);
87 procedure conwriter (constref buf
; len
: SizeUInt
);
93 if (len
< 1) then exit
;
97 if (len
> 255) then slen
:= 255 else slen
:= Integer(len
);
98 Move(b
^, ss
[1], slen
);
99 ss
[0] := AnsiChar(slen
);
109 xlogFileOpened
: Boolean = false;
110 xlogPrefix
: AnsiString;
111 xlogLastWasEOL
: Boolean = false;
112 xlogWantSpace
: Boolean = false;
113 xlogSlowAndSafe
: Boolean = false;
116 procedure e_SetSafeSlowLog (slowAndSafe
: Boolean);
118 xlogSlowAndSafe
:= slowAndSafe
;
119 if xlogSlowAndSafe
and xlogFileOpened
then
122 xlogFileOpened
:= false;
127 procedure logwriter (constref buf
; len
: SizeUInt
);
133 if (len
< 1) then exit
;
135 if xlogLastWasEOL
then
137 write(xlogFile
, xlogPrefix
);
138 xlogLastWasEOL
:= false;
139 xlogWantSpace
:= true;
144 while (slen
< len
) and (b
[slen
] <> 13) and (b
[slen
] <> 10) do Inc(slen
);
145 if (slen
> 255) then slen
:= 255;
149 if xlogWantSpace
then begin write(xlogFile
, ' '); xlogWantSpace
:= false; end;
150 Move(b
^, ss
[1], slen
);
151 ss
[0] := AnsiChar(slen
);
158 if (len
> 0) and ((b
[0] = 13) or (b
[0] = 10)) then
160 if (b
[0] = 13) then begin len
-= 1; b
+= 1; end;
161 if (len
> 0) and (b
[0] = 10) then begin len
-= 1; b
+= 1; end;
162 xlogLastWasEOL
:= false;
163 writeln(xlogFile
, '');
164 write(xlogFile
, xlogPrefix
);
170 procedure e_LogWritefln (const fmt
: AnsiString; args
: array of const; category
: TMsgType
=TMsgType
.Notify
; writeTime
: Boolean=true);
172 procedure xwrite (const s
: AnsiString);
174 if (Length(s
) = 0) then exit
;
175 logwriter(PAnsiChar(s
)^, Length(s
));
179 if driverInited
and (length(fmt
) > 0) then
182 TMsgType
.Fatal
: write('FATAL: ');
183 TMsgType
.Warning
: write('WARNING: ');
185 formatstrf(fmt
, args
, conwriter
);
189 if (FileName
= '') then exit
;
191 if not xlogFileOpened
then
193 AssignFile(xlogFile
, FileName
);
195 if FileExists(FileName
) then Append(xlogFile
) else Rewrite(xlogFile
);
196 xlogFileOpened
:= true;
204 writeln(xlogFile
, '--- Log started at ', TimeToStr(Time
), ' ---');
205 FirstRecord
:= false;
209 if writeTime
then begin xlogPrefix
+= '['; xlogPrefix
+= TimeToStr(Time
); xlogPrefix
+= '] '; end;
211 TMsgType
.Fatal
: xlogPrefix
+= '!!!';
212 TMsgType
.Warning
: xlogPrefix
+= '! ';
213 TMsgType
.Notify
: xlogPrefix
+= '***';
215 xlogLastWasEOL
:= true; // to output prefix
216 xlogWantSpace
:= true; // after prefix
217 formatstrf(fmt
, args
, logwriter
);
218 if not xlogLastWasEOL
then writeln(xlogFile
, '') else writeln(xlogFile
, xlogPrefix
);
220 if xlogSlowAndSafe
and xlogFileOpened
then
223 xlogFileOpened
:= false;
226 //if fopened then CloseFile(xlogFile);
230 procedure e_InitLog (fFileName
: String; fWriteMode
: TWriteMode
);
232 if xlogFileOpened
then CloseFile(xlogFile
);
233 xlogFileOpened
:= false;
234 FileName
:= fFileName
;
235 if (fWriteMode
= TWriteMode
.WM_NEWFILE
) then
238 if FileExists(FileName
) then DeleteFile(FileName
);
247 procedure e_WriteStackTrace (const msg
: AnsiString);
251 e_LogWriteln(msg
, TMsgType
.Fatal
);
252 if (Length(FileName
) > 0) then
254 if xlogFileOpened
then CloseFile(xlogFile
);
255 xlogFileOpened
:= false;
256 AssignFile(tfo
, FileName
);
258 if (IOResult
<> 0) then Rewrite(tfo
);
259 if (IOResult
= 0) then begin writeln(tfo
, '====================='); DumpExceptionBackTrace(tfo
); CloseFile(tfo
); end;
264 procedure e_DeinitLog ();
266 if xlogFileOpened
then CloseFile(xlogFile
);
267 xlogFileOpened
:= false;
271 // ////////////////////////////////////////////////////////////////////////// //
272 (* Write/WriteLn driver *)
276 // TAB: tab space = 4
278 // userData[1]: current x (for tabs)
279 // userData[2]: #13 was eaten, we should skip next #10
282 TDevFunc
= function (var f
: TTextRec
): Integer;
289 procedure ProcessOutput (var tf
: TTextRec
; buf
: PChar; count
: Integer);
296 x
:= tf
.userData
[udX
];
297 wcr
:= (tf
.userData
[udWasCR
] <> 0);
300 // look for some special char
306 if (ch
= #13) or (ch
= #10) or (ch
= #9) or (ch
= #8) then break
;
316 cbufPutChars(buf
, f
);
322 // process special chars
339 if (ch
= #13) or (ch
= #10) then
344 if not wcr
or (ch
<> #10) then
353 tf
.userData
[udX
] := x
;
354 tf
.userData
[udWasCR
] := ord(wcr
);
358 function DevOpen (var f
: TTextRec
): Integer;
360 f
.userData
[udX
] := 0;
361 f
.userData
[udWasCR
] := 0;
367 function DevInOut (var f
: TTextRec
): Integer;
373 buf
:= Pointer(f
.BufPtr
);
375 if sz
> 0 then ProcessOutput(f
, buf
, sz
);
380 function DevFlush (var f
: TTextRec
): Integer;
382 result
:= DevInOut(f
);
385 function DevClose (var f
: TTextRec
): Integer;
391 procedure e_InitWritelnDriver ();
393 if not driverInited
then
395 driverInited
:= true;
396 with TTextRec(output
) do
401 BufSize
:= SizeOf(Buffer
);
404 OpenFunc
:= @DevOpen
;
405 InOutFunc
:= @DevInOut
;
406 FlushFunc
:= @DevFlush
;
407 CloseFunc
:= @DevClose
;
416 //e_InitWritelnDriver();