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