File:  [HATARI the Atari ST Emulator] / hatari / src / log.c
Revision 1.1.1.6 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 9 08:47:01 2019 UTC (7 years, 1 month ago) by root
Branches: hatari, MAIN
CVS tags: hatari01310, hatari01300, HEAD
hatari 1.3.0

/*
 * Hatari - log.c
 *
 * This file is distributed under the GNU Public License, version 2 or at
 * your option any later version. Read the file gpl.txt for details.
 *
 * Logger functions.
 *
 * When Hatari runs, it can output information, debug, warning and error texts
 * to the error log file and/or displays them in alert dialog boxes.
 *
 * It can also dynamically output trace messages, based on the content
 * of LogTraceFlags. Multiple trace levels can be set at once, by setting
 * the corresponding bits in LogTraceFlags.
 */
const char Log_fileid[] = "Hatari log.c : " __DATE__ " " __TIME__;

#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "main.h"
#include "configuration.h"
#include "dialog.h"
#include "log.h"
#include "screen.h"
#include "file.h"


struct {
	Uint32 Level;
	const char *Name;
}
TraceOptions[] = {
	{ TRACE_NONE		 , "none" },

	{ TRACE_VIDEO_SYNC	 , "video_sync" } ,
	{ TRACE_VIDEO_RES	 , "video_res" } ,
	{ TRACE_VIDEO_COLOR	 , "video_color" } ,
	{ TRACE_VIDEO_BORDER_V   , "video_border_v" } ,
	{ TRACE_VIDEO_BORDER_H   , "video_border_h" } ,
	{ TRACE_VIDEO_ADDR	 , "video_addr" } ,
	{ TRACE_VIDEO_HBL	 , "video_hbl" } ,
	{ TRACE_VIDEO_VBL	 , "video_vbl" } ,
	{ TRACE_VIDEO_STE	 , "video_ste" } ,
	{ TRACE_VIDEO_ALL	 , "video_all" } ,

	{ TRACE_MFP_EXCEPTION	 , "mfp_exception" } ,
	{ TRACE_MFP_START	 , "mfp_start" } ,
	{ TRACE_MFP_READ	 , "mfp_read" } ,
	{ TRACE_MFP_WRITE	 , "mfp_write" } ,
	{ TRACE_MFP_ALL 	 , "mfp_all" } ,

	{ TRACE_PSG_READ	 , "psg_read" } ,
	{ TRACE_PSG_WRITE	 , "psg_write" } ,
	{ TRACE_PSG_ALL 	 , "psg_all" } ,

	{ TRACE_CPU_PAIRING	 , "cpu_pairing" } ,
	{ TRACE_CPU_DISASM	 , "cpu_disasm" } ,
	{ TRACE_CPU_EXCEPTION	 , "cpu_exception" } ,
	{ TRACE_CPU_ALL 	 , "cpu_all" } ,

	{ TRACE_INT		 , "int" } ,

	{ TRACE_FDC		 , "fdc" } ,

	{ TRACE_IKBD_CMDS	 , "ikbd_cmds" } ,
	{ TRACE_IKBD_ACIA	 , "ikbd_acia" } ,
	{ TRACE_IKBD_EXEC	 , "ikbd_exec" } ,
	{ TRACE_IKBD_ALL	 , "ikbd_all" } ,

	{ TRACE_BLITTER 	 , "blitter" } ,

	{ TRACE_OS_BIOS 	 , "bios" },
	{ TRACE_OS_XBIOS	 , "xbios" },
	{ TRACE_OS_GEMDOS	 , "gemdos" },
	{ TRACE_OS_VDI  	 , "vdi" },
	{ TRACE_OS_ALL  	 , "os_all" } ,

	{ TRACE_IOMEM_RD	 , "io_read" } ,
	{ TRACE_IOMEM_WR	 , "io_write" } ,
	{ TRACE_IOMEM_ALL	 , "io_all" } ,

	{ TRACE_DMASND  	 , "dmasound" } ,

	{ TRACE_ALL		 , "all" }
};


Uint32	LogTraceFlags = TRACE_NONE;
FILE *TraceFile = NULL;

static FILE *hLogFile = NULL;
static LOGTYPE TextLogLevel;
static LOGTYPE AlertDlgLogLevel;

/*-----------------------------------------------------------------------*/
/**
 * Initialize the logging and tracing functionality (open the log files etc.).
 * 
 * Return zero if that fails.
 */
int Log_Init(void)
{
	TextLogLevel = ConfigureParams.Log.nTextLogLevel;
	AlertDlgLogLevel = ConfigureParams.Log.nAlertDlgLogLevel;

	hLogFile = File_Open(ConfigureParams.Log.sLogFileName, "w");
	TraceFile = File_Open(ConfigureParams.Log.sTraceFileName, "w");
   
	return (hLogFile && TraceFile);
}


/*-----------------------------------------------------------------------*/
/**
 * Un-Initialize - close log files etc.
 */
void Log_UnInit(void)
{
	hLogFile = File_Close(hLogFile);
	TraceFile = File_Close(TraceFile);
}


/*-----------------------------------------------------------------------*/
/**
 * Output string to log file
 */
void Log_Printf(LOGTYPE nType, const char *psFormat, ...)
{
	va_list argptr;

	if (hLogFile && nType <= TextLogLevel)
	{
		va_start(argptr, psFormat);
		vfprintf(hLogFile, psFormat, argptr);
		va_end(argptr);
		/* Add a new-line if necessary: */
		if (psFormat[strlen(psFormat)-1] != '\n')
			fputs("\n", hLogFile);
	}
}


/*-----------------------------------------------------------------------*/
/**
 * Show logging alert dialog box and output string to log file
 */
void Log_AlertDlg(LOGTYPE nType, const char *psFormat, ...)
{
	va_list argptr;

	/* Output to log file: */
	if (hLogFile && nType <= TextLogLevel)
	{
		va_start(argptr, psFormat);
		vfprintf(hLogFile, psFormat, argptr);
		va_end(argptr);
		/* Add a new-line if necessary: */
		if (psFormat[strlen(psFormat)-1] != '\n')
			fputs("\n", hLogFile);
	}

	/* Show alert dialog box: */
	if (sdlscrn && nType <= AlertDlgLogLevel)
	{
		char *psTmpBuf;
		psTmpBuf = malloc(2048);
		if (!psTmpBuf)
		{
			perror("Log_AlertDlg");
			return;
		}
		va_start(argptr, psFormat);
		vsnprintf(psTmpBuf, 2048, psFormat, argptr);
		va_end(argptr);
		DlgAlert_Notice(psTmpBuf);
		free(psTmpBuf);
	}
}


/*-----------------------------------------------------------------------*/
/**
 * parse what log level should be used and return it
 */
LOGTYPE Log_ParseOptions(const char *arg)
{
	const char *levels[] = {
		"fatal", "error", "warn", "info", "todo", "debug", NULL
	};
	LOGTYPE level = LOG_FATAL;
	const char **level_str;
	char *input, *str;

	input = strdup(arg);
	str = input;
	while (*str)
	{
		*str++ = tolower(*arg++);
	}
	for (level_str = levels; *level_str; level_str++, level++)
	{
		if (strcmp(input, *level_str) == 0)
		{
			free(input);
			return level;
		}
	}
	free(input);
	return level;
}

/*-----------------------------------------------------------------------*/
/**
 * Parse a list of comma separated strings.
 * If the string is prefixed with an optional '+',
 * corresponding trace flag is turned on.
 * If the string is prefixed with a '-',
 * corresponding trace flag is turned off.
 * Result is stored in LogTraceFlags.
 * Return error string or NULL for success.
 */
const char* Log_SetTraceOptions (const char *OptionsStr)
{
#if ENABLE_TRACING

	char *OptionsCopy;
	char *cur, *sep;
	int i;
	int Mode;				/* 0=add, 1=del */
	int MaxOptions;

	MaxOptions = sizeof(TraceOptions) / sizeof(TraceOptions[0]);
	
	/* special case for "help" : display the list of possible trace levels */
	if (strcmp (OptionsStr, "help") == 0)
	{
		fprintf(stderr, "\nList of available trace levels :\n");
		
		for (i = 0; i < MaxOptions; i++)
			fprintf(stderr, "  %s\n", TraceOptions[i].Name);
		
		fprintf(stderr, "Multiple trace levels can be separated by ','\n");
		fprintf(stderr, "Levels can be prefixed by '+' or '-' to be mixed.\n");
		fprintf(stderr, "Giving just trace level 'none' disables all traces.\n\n");
		return NULL;
	}
	
	LogTraceFlags = TRACE_NONE;
	if (strcmp (OptionsStr, "none") == 0)
	{
		return NULL;
	}
	
	OptionsCopy = strdup(OptionsStr);
	if (!OptionsCopy)
	{
		return "strdup error in ParseTraceOptions";
	}
	
	cur = OptionsCopy;
	while (cur)
	{
		sep = strchr(cur, ',');
		if (sep)			/* end of next options */
			*sep++ = '\0';
		
		Mode = 0;				/* default is 'add' */
		if (*cur == '+')
		{ Mode = 0; cur++; }
		else if (*cur == '-')
		{ Mode = 1; cur++; }
		
		for (i = 0; i < MaxOptions; i++)
		{
			if (strcmp(cur, TraceOptions[i].Name) == 0)
				break;
		}
		
		if (i < MaxOptions)		/* option found */
		{
			if (Mode == 0)
				LogTraceFlags |= TraceOptions[i].Level;
			else
				LogTraceFlags &= (~TraceOptions[i].Level);
		}
		else
		{
			fprintf(stderr, "Unknown trace type '%s'\n", cur);
			free(OptionsCopy);
			return "Unknown trace type.";
		}
		
		cur = sep;
	}
	
	//fprintf(stderr, "trace parse <%x>\n", LogTraceFlags);
	
	free (OptionsCopy);
	return NULL;

#else	/* ENABLE_TRACING */
	return "Hatari has been compiled without ENABLE_TRACING!";
#endif
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.