|
|
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 {
1.1.1.2 root 33: Uint64 Level;
1.1 root 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" },
1.1.1.2 root 80: { TRACE_OS_AES , "aes" },
1.1 root 81: { TRACE_OS_ALL , "os_all" } ,
82:
83: { TRACE_IOMEM_RD , "io_read" } ,
84: { TRACE_IOMEM_WR , "io_write" } ,
85: { TRACE_IOMEM_ALL , "io_all" } ,
86:
87: { TRACE_DMASND , "dmasound" } ,
88:
89: { TRACE_CROSSBAR , "crossbar" } ,
1.1.1.2 root 90: { TRACE_VIDEL , "videl" } ,
91:
92: { TRACE_DSP_HOST_INTERFACE, "dsp_host_interface" },
93: { TRACE_DSP_HOST_COMMAND , "dsp_host_command" },
94: { TRACE_DSP_HOST_SSI , "dsp_host_ssi" },
95: { TRACE_DSP_INTERRUPT , "dsp_interrupt" },
96: { TRACE_DSP_DISASM , "dsp_disasm" },
97: { TRACE_DSP_DISASM_REG , "dsp_disasm_reg" },
98: { TRACE_DSP_DISASM_MEM , "dsp_disasm_mem" },
99: { TRACE_DSP_STATE , "dsp_state" },
100: { TRACE_DSP_ALL , "dsp_all" },
1.1 root 101:
102: { TRACE_ALL , "all" }
103: };
104:
105:
1.1.1.2 root 106: Uint64 LogTraceFlags = TRACE_NONE;
1.1 root 107: FILE *TraceFile = NULL;
108:
109: static FILE *hLogFile = NULL;
110: static LOGTYPE TextLogLevel;
111: static LOGTYPE AlertDlgLogLevel;
112:
113: /*-----------------------------------------------------------------------*/
114: /**
115: * Initialize the logging and tracing functionality (open the log files etc.).
116: *
117: * Return zero if that fails.
118: */
119: int Log_Init(void)
120: {
121: TextLogLevel = ConfigureParams.Log.nTextLogLevel;
122: AlertDlgLogLevel = ConfigureParams.Log.nAlertDlgLogLevel;
123:
124: hLogFile = File_Open(ConfigureParams.Log.sLogFileName, "w");
125: TraceFile = File_Open(ConfigureParams.Log.sTraceFileName, "w");
126:
127: return (hLogFile && TraceFile);
128: }
129:
130: /**
131: * Set Alert log level temporarily without config change.
132: *
133: * Return old level for restoring the original level with this.
134: */
135: int Log_SetAlertLevel(int level)
136: {
137: int old = AlertDlgLogLevel;
138: AlertDlgLogLevel = level;
139: return old;
140: }
141:
142:
143: /*-----------------------------------------------------------------------*/
144: /**
145: * Un-Initialize - close log files etc.
146: */
147: void Log_UnInit(void)
148: {
149: hLogFile = File_Close(hLogFile);
150: TraceFile = File_Close(TraceFile);
151: }
152:
153:
154: /*-----------------------------------------------------------------------*/
155: /**
156: * Output string to log file
157: */
158: void Log_Printf(LOGTYPE nType, const char *psFormat, ...)
159: {
160: va_list argptr;
161:
162: if (hLogFile && nType <= TextLogLevel)
163: {
164: va_start(argptr, psFormat);
165: vfprintf(hLogFile, psFormat, argptr);
166: va_end(argptr);
167: /* Add a new-line if necessary: */
168: if (psFormat[strlen(psFormat)-1] != '\n')
169: fputs("\n", hLogFile);
170: }
171: }
172:
173:
174: /*-----------------------------------------------------------------------*/
175: /**
176: * Show logging alert dialog box and output string to log file
177: */
178: void Log_AlertDlg(LOGTYPE nType, const char *psFormat, ...)
179: {
180: va_list argptr;
181:
182: /* Output to log file: */
183: if (hLogFile && nType <= TextLogLevel)
184: {
185: va_start(argptr, psFormat);
186: vfprintf(hLogFile, psFormat, argptr);
187: va_end(argptr);
188: /* Add a new-line if necessary: */
189: if (psFormat[strlen(psFormat)-1] != '\n')
190: fputs("\n", hLogFile);
191: }
192:
193: /* Show alert dialog box: */
194: if (sdlscrn && nType <= AlertDlgLogLevel)
195: {
196: char *psTmpBuf;
197: psTmpBuf = malloc(2048);
198: if (!psTmpBuf)
199: {
200: perror("Log_AlertDlg");
201: return;
202: }
203: va_start(argptr, psFormat);
204: vsnprintf(psTmpBuf, 2048, psFormat, argptr);
205: va_end(argptr);
206: DlgAlert_Notice(psTmpBuf);
207: free(psTmpBuf);
208: }
209: }
210:
211:
212: /*-----------------------------------------------------------------------*/
213: /**
214: * parse what log level should be used and return it
215: */
216: LOGTYPE Log_ParseOptions(const char *arg)
217: {
218: const char *levels[] = {
219: "fatal", "error", "warn", "info", "todo", "debug", NULL
220: };
221: LOGTYPE level = LOG_FATAL;
222: const char **level_str;
223: char *input, *str;
224:
225: input = strdup(arg);
226: str = input;
227: while (*str)
228: {
229: *str++ = tolower(*arg++);
230: }
231: for (level_str = levels; *level_str; level_str++, level++)
232: {
233: if (strcmp(input, *level_str) == 0)
234: {
235: free(input);
236: return level;
237: }
238: }
239: free(input);
240: return level;
241: }
242:
243:
244: #if ENABLE_TRACING
245:
246: /*-----------------------------------------------------------------------*/
247: /**
248: * Parse a list of comma separated strings.
249: * If the string is prefixed with an optional '+',
250: * corresponding trace flag is turned on.
251: * If the string is prefixed with a '-',
252: * corresponding trace flag is turned off.
253: * Result is stored in LogTraceFlags.
254: * Return error string (""=silent 'error') or NULL for success.
255: */
256: const char* Log_SetTraceOptions (const char *OptionsStr)
257: {
258: char *OptionsCopy;
259: char *cur, *sep;
260: int i;
261: int Mode; /* 0=add, 1=del */
262: int MaxOptions;
263:
264: MaxOptions = ARRAYSIZE(TraceOptions);
265:
266: /* special case for "help" : display the list of possible trace levels */
267: if (strcmp (OptionsStr, "help") == 0)
268: {
269: fprintf(stderr, "\nList of available trace levels :\n");
270:
271: for (i = 0; i < MaxOptions; i++)
272: fprintf(stderr, " %s\n", TraceOptions[i].Name);
273:
274: fprintf(stderr, "Multiple trace levels can be separated by ','\n");
275: fprintf(stderr, "Levels can be prefixed by '+' or '-' to be mixed.\n");
276: fprintf(stderr, "Giving just trace level 'none' disables all traces.\n\n");
277: return "";
278: }
279:
280: LogTraceFlags = TRACE_NONE;
281: if (strcmp (OptionsStr, "none") == 0)
282: {
283: return NULL;
284: }
285:
286: OptionsCopy = strdup(OptionsStr);
287: if (!OptionsCopy)
288: {
289: return "strdup error in ParseTraceOptions";
290: }
291:
292: cur = OptionsCopy;
293: while (cur)
294: {
295: sep = strchr(cur, ',');
296: if (sep) /* end of next options */
297: *sep++ = '\0';
298:
299: Mode = 0; /* default is 'add' */
300: if (*cur == '+')
301: { Mode = 0; cur++; }
302: else if (*cur == '-')
303: { Mode = 1; cur++; }
304:
305: for (i = 0; i < MaxOptions; i++)
306: {
307: if (strcmp(cur, TraceOptions[i].Name) == 0)
308: break;
309: }
310:
311: if (i < MaxOptions) /* option found */
312: {
313: if (Mode == 0)
314: LogTraceFlags |= TraceOptions[i].Level;
315: else
316: LogTraceFlags &= (~TraceOptions[i].Level);
317: }
318: else
319: {
320: fprintf(stderr, "Unknown trace type '%s'\n", cur);
321: free(OptionsCopy);
322: return "Unknown trace type.";
323: }
324:
325: cur = sep;
326: }
1.1.1.3 ! root 327:
1.1 root 328: //fprintf(stderr, "trace parse <%x>\n", LogTraceFlags);
329:
330: free (OptionsCopy);
331: return NULL;
332: }
333:
334:
335: /**
336: * Readline match callback for trace type name completion.
337: * STATE = 0 -> different text from previous one.
338: * Return next match or NULL if no matches.
339: */
340: char *Log_MatchTrace(const char *text, int state)
341: {
342: static int i, len;
343: const char *name;
344:
345: if (!state) {
346: /* first match */
347: len = strlen(text);
348: i = 0;
349: }
350: /* next match */
351: while (i < ARRAYSIZE(TraceOptions)) {
352: name = TraceOptions[i++].Name;
353: if (strncasecmp(name, text, len) == 0)
354: return (strdup(name));
355: }
356: return NULL;
357: }
358:
359: #else /* !ENABLE_TRACING */
360:
361: /** dummy */
362: const char* Log_SetTraceOptions (const char *OptionsStr)
363: {
364: return "Hatari has been compiled without ENABLE_TRACING!";
365: }
366:
367: /** dummy */
368: char *Log_MatchTrace(const char *text, int state)
369: {
370: return NULL;
371: }
372:
373: #endif /* !ENABLE_TRACING */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.