|
|
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.