|
|
1.1 root 1: /*
2: * Hatari - log.c
3: *
4: * This file is distributed under the GNU Public License, version 2 or at
5: * your option any later version. Read the file gpl.txt for details.
6: *
7: * Logger functions.
8: *
9: * When Hatari runs, it can output information, debug, warning and error texts
10: * to the error log file and/or displays them in alert dialog boxes.
11: *
12: * It can also dynamically output trace messages, based on the content
13: * of LogTraceFlags. Multiple trace levels can be set at once, by setting
14: * the corresponding bits in LogTraceFlags.
15: */
16: const char Log_fileid[] = "Hatari log.c : " __DATE__ " " __TIME__;
17:
18: #include <stdio.h>
19: #include <stdarg.h>
20: #include <stdlib.h>
21: #include <string.h>
22: #include <ctype.h>
23:
24: #include "main.h"
25: #include "configuration.h"
26: #include "dialog.h"
27: #include "log.h"
28: #include "screen.h"
29: #include "file.h"
30:
31:
32: static struct {
33: Uint32 Level;
34: const char *Name;
35: }
36: TraceOptions[] = {
37: { TRACE_NONE , "none" },
38:
39: { TRACE_VIDEO_SYNC , "video_sync" } ,
40: { TRACE_VIDEO_RES , "video_res" } ,
41: { TRACE_VIDEO_COLOR , "video_color" } ,
42: { TRACE_VIDEO_BORDER_V , "video_border_v" } ,
43: { TRACE_VIDEO_BORDER_H , "video_border_h" } ,
44: { TRACE_VIDEO_ADDR , "video_addr" } ,
45: { TRACE_VIDEO_HBL , "video_hbl" } ,
46: { TRACE_VIDEO_VBL , "video_vbl" } ,
47: { TRACE_VIDEO_STE , "video_ste" } ,
48: { TRACE_VIDEO_ALL , "video_all" } ,
49:
50: { TRACE_MFP_EXCEPTION , "mfp_exception" } ,
51: { TRACE_MFP_START , "mfp_start" } ,
52: { TRACE_MFP_READ , "mfp_read" } ,
53: { TRACE_MFP_WRITE , "mfp_write" } ,
54: { TRACE_MFP_ALL , "mfp_all" } ,
55:
56: { TRACE_PSG_READ , "psg_read" } ,
57: { TRACE_PSG_WRITE , "psg_write" } ,
58: { TRACE_PSG_ALL , "psg_all" } ,
59:
60: { TRACE_CPU_PAIRING , "cpu_pairing" } ,
61: { TRACE_CPU_DISASM , "cpu_disasm" } ,
62: { TRACE_CPU_EXCEPTION , "cpu_exception" } ,
63: { TRACE_CPU_ALL , "cpu_all" } ,
64:
65: { TRACE_INT , "int" } ,
66:
67: { TRACE_FDC , "fdc" } ,
68:
69: { TRACE_IKBD_CMDS , "ikbd_cmds" } ,
70: { TRACE_IKBD_ACIA , "ikbd_acia" } ,
71: { TRACE_IKBD_EXEC , "ikbd_exec" } ,
72: { TRACE_IKBD_ALL , "ikbd_all" } ,
73:
74: { TRACE_BLITTER , "blitter" } ,
75:
76: { TRACE_OS_BIOS , "bios" },
77: { TRACE_OS_XBIOS , "xbios" },
78: { TRACE_OS_GEMDOS , "gemdos" },
79: { TRACE_OS_VDI , "vdi" },
80: { TRACE_OS_ALL , "os_all" } ,
81:
82: { TRACE_IOMEM_RD , "io_read" } ,
83: { TRACE_IOMEM_WR , "io_write" } ,
84: { TRACE_IOMEM_ALL , "io_all" } ,
85:
86: { TRACE_DMASND , "dmasound" } ,
87:
88: { TRACE_CROSSBAR , "crossbar" } ,
89:
90: { TRACE_ALL , "all" }
91: };
92:
93:
94: Uint32 LogTraceFlags = TRACE_NONE;
95: FILE *TraceFile = NULL;
96:
97: static FILE *hLogFile = NULL;
98: static LOGTYPE TextLogLevel;
99: static LOGTYPE AlertDlgLogLevel;
100:
101: /*-----------------------------------------------------------------------*/
102: /**
103: * Initialize the logging and tracing functionality (open the log files etc.).
104: *
105: * Return zero if that fails.
106: */
107: int Log_Init(void)
108: {
109: TextLogLevel = ConfigureParams.Log.nTextLogLevel;
110: AlertDlgLogLevel = ConfigureParams.Log.nAlertDlgLogLevel;
111:
112: hLogFile = File_Open(ConfigureParams.Log.sLogFileName, "w");
113: TraceFile = File_Open(ConfigureParams.Log.sTraceFileName, "w");
114:
115: return (hLogFile && TraceFile);
116: }
117:
118: /**
119: * Set Alert log level temporarily without config change.
120: *
121: * Return old level for restoring the original level with this.
122: */
123: int Log_SetAlertLevel(int level)
124: {
125: int old = AlertDlgLogLevel;
126: AlertDlgLogLevel = level;
127: return old;
128: }
129:
130:
131: /*-----------------------------------------------------------------------*/
132: /**
133: * Un-Initialize - close log files etc.
134: */
135: void Log_UnInit(void)
136: {
137: hLogFile = File_Close(hLogFile);
138: TraceFile = File_Close(TraceFile);
139: }
140:
141:
142: /*-----------------------------------------------------------------------*/
143: /**
144: * Output string to log file
145: */
146: void Log_Printf(LOGTYPE nType, const char *psFormat, ...)
147: {
148: va_list argptr;
149:
150: if (hLogFile && nType <= TextLogLevel)
151: {
152: va_start(argptr, psFormat);
153: vfprintf(hLogFile, psFormat, argptr);
154: va_end(argptr);
155: /* Add a new-line if necessary: */
156: if (psFormat[strlen(psFormat)-1] != '\n')
157: fputs("\n", hLogFile);
158: }
159: }
160:
161:
162: /*-----------------------------------------------------------------------*/
163: /**
164: * Show logging alert dialog box and output string to log file
165: */
166: void Log_AlertDlg(LOGTYPE nType, const char *psFormat, ...)
167: {
168: va_list argptr;
169:
170: /* Output to log file: */
171: if (hLogFile && nType <= TextLogLevel)
172: {
173: va_start(argptr, psFormat);
174: vfprintf(hLogFile, psFormat, argptr);
175: va_end(argptr);
176: /* Add a new-line if necessary: */
177: if (psFormat[strlen(psFormat)-1] != '\n')
178: fputs("\n", hLogFile);
179: }
180:
181: /* Show alert dialog box: */
182: if (sdlscrn && nType <= AlertDlgLogLevel)
183: {
184: char *psTmpBuf;
185: psTmpBuf = malloc(2048);
186: if (!psTmpBuf)
187: {
188: perror("Log_AlertDlg");
189: return;
190: }
191: va_start(argptr, psFormat);
192: vsnprintf(psTmpBuf, 2048, psFormat, argptr);
193: va_end(argptr);
194: DlgAlert_Notice(psTmpBuf);
195: free(psTmpBuf);
196: }
197: }
198:
199:
200: /*-----------------------------------------------------------------------*/
201: /**
202: * parse what log level should be used and return it
203: */
204: LOGTYPE Log_ParseOptions(const char *arg)
205: {
206: const char *levels[] = {
207: "fatal", "error", "warn", "info", "todo", "debug", NULL
208: };
209: LOGTYPE level = LOG_FATAL;
210: const char **level_str;
211: char *input, *str;
212:
213: input = strdup(arg);
214: str = input;
215: while (*str)
216: {
217: *str++ = tolower(*arg++);
218: }
219: for (level_str = levels; *level_str; level_str++, level++)
220: {
221: if (strcmp(input, *level_str) == 0)
222: {
223: free(input);
224: return level;
225: }
226: }
227: free(input);
228: return level;
229: }
230:
231:
232: #if ENABLE_TRACING
233:
234: /*-----------------------------------------------------------------------*/
235: /**
236: * Parse a list of comma separated strings.
237: * If the string is prefixed with an optional '+',
238: * corresponding trace flag is turned on.
239: * If the string is prefixed with a '-',
240: * corresponding trace flag is turned off.
241: * Result is stored in LogTraceFlags.
242: * Return error string (""=silent 'error') or NULL for success.
243: */
244: const char* Log_SetTraceOptions (const char *OptionsStr)
245: {
246: char *OptionsCopy;
247: char *cur, *sep;
248: int i;
249: int Mode; /* 0=add, 1=del */
250: int MaxOptions;
251:
252: MaxOptions = ARRAYSIZE(TraceOptions);
253:
254: /* special case for "help" : display the list of possible trace levels */
255: if (strcmp (OptionsStr, "help") == 0)
256: {
257: fprintf(stderr, "\nList of available trace levels :\n");
258:
259: for (i = 0; i < MaxOptions; i++)
260: fprintf(stderr, " %s\n", TraceOptions[i].Name);
261:
262: fprintf(stderr, "Multiple trace levels can be separated by ','\n");
263: fprintf(stderr, "Levels can be prefixed by '+' or '-' to be mixed.\n");
264: fprintf(stderr, "Giving just trace level 'none' disables all traces.\n\n");
265: return "";
266: }
267:
268: LogTraceFlags = TRACE_NONE;
269: if (strcmp (OptionsStr, "none") == 0)
270: {
271: return NULL;
272: }
273:
274: OptionsCopy = strdup(OptionsStr);
275: if (!OptionsCopy)
276: {
277: return "strdup error in ParseTraceOptions";
278: }
279:
280: cur = OptionsCopy;
281: while (cur)
282: {
283: sep = strchr(cur, ',');
284: if (sep) /* end of next options */
285: *sep++ = '\0';
286:
287: Mode = 0; /* default is 'add' */
288: if (*cur == '+')
289: { Mode = 0; cur++; }
290: else if (*cur == '-')
291: { Mode = 1; cur++; }
292:
293: for (i = 0; i < MaxOptions; i++)
294: {
295: if (strcmp(cur, TraceOptions[i].Name) == 0)
296: break;
297: }
298:
299: if (i < MaxOptions) /* option found */
300: {
301: if (Mode == 0)
302: LogTraceFlags |= TraceOptions[i].Level;
303: else
304: LogTraceFlags &= (~TraceOptions[i].Level);
305: }
306: else
307: {
308: fprintf(stderr, "Unknown trace type '%s'\n", cur);
309: free(OptionsCopy);
310: return "Unknown trace type.";
311: }
312:
313: cur = sep;
314: }
315:
316: //fprintf(stderr, "trace parse <%x>\n", LogTraceFlags);
317:
318: free (OptionsCopy);
319: return NULL;
320: }
321:
322:
323: /**
324: * Readline match callback for trace type name completion.
325: * STATE = 0 -> different text from previous one.
326: * Return next match or NULL if no matches.
327: */
328: char *Log_MatchTrace(const char *text, int state)
329: {
330: static int i, len;
331: const char *name;
332:
333: if (!state) {
334: /* first match */
335: len = strlen(text);
336: i = 0;
337: }
338: /* next match */
339: while (i < ARRAYSIZE(TraceOptions)) {
340: name = TraceOptions[i++].Name;
341: if (strncasecmp(name, text, len) == 0)
342: return (strdup(name));
343: }
344: return NULL;
345: }
346:
347: #else /* !ENABLE_TRACING */
348:
349: /** dummy */
350: const char* Log_SetTraceOptions (const char *OptionsStr)
351: {
352: return "Hatari has been compiled without ENABLE_TRACING!";
353: }
354:
355: /** dummy */
356: char *Log_MatchTrace(const char *text, int state)
357: {
358: return NULL;
359: }
360:
361: #endif /* !ENABLE_TRACING */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.