/*
elmo - ELectronic Mail Operator
Copyright (C) 2002, 2003 rzyjontko
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
----------------------------------------------------------------------
*/
/****************************************************************************
* IMPLEMENTATION HEADERS
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include "debug.h"
#include "error.h"
#include "select.h"
#include "color.h"
#include "ask.h"
#include "gettext.h"
#include "label.h"
#include "interface.h"
#include "str.h"
#include "xmalloc.h"
#include "cmd.h"
/****************************************************************************
* IMPLEMENTATION PRIVATE DEFINITIONS / ENUMERATIONS / SIMPLE TYPEDEFS
****************************************************************************/
#ifndef DEBUG
# define DEBUG 0
#endif
#define DEBUG_FILE "debug.log"
#define DEFAULT_BACKLOG_SIZE 50
/****************************************************************************
* IMPLEMENTATION PRIVATE CLASS PROTOTYPES / EXTERNAL CLASS REFERENCES
****************************************************************************/
/****************************************************************************
* IMPLEMENTATION PRIVATE STRUCTURES / UTILITY CLASSES
****************************************************************************/
struct debug {
str_t *str;
enum level level;
};
/****************************************************************************
* IMPLEMENTATION REQUIRED EXTERNAL REFERENCES (AVOID)
****************************************************************************/
/****************************************************************************
* IMPLEMENTATION PRIVATE DATA
****************************************************************************/
#if DEBUG
/* Every debug information is written to this file. */
static FILE *debug_file = NULL;
/* These are colors used to diplay different kinds of messages. */
static chtype error_color;
static chtype warn_color;
static chtype info_color;
static chtype text_color;
/* Debug window consists (like most of windows) of select_t object, and
optional label. */
static elabel_t *label = NULL;
static select_t *debug_select = NULL;
/* The backlog is a kind of queue. We store only backlog_size last
messages. */
static struct debug *backlog = NULL;
static int backlog_size = DEFAULT_BACKLOG_SIZE;
static int backlog_first = 0;
static int backlog_count = 0;
#endif
/****************************************************************************
* INTERFACE DATA
****************************************************************************/
/****************************************************************************
* IMPLEMENTATION PRIVATE FUNCTION PROTOTYPES
****************************************************************************/
#if DEBUG
static void initialize_backlog (void);
#endif
/****************************************************************************
* IMPLEMENTATION PRIVATE FUNCTIONS
****************************************************************************/
#if DEBUG
static void
debug_refresh (void)
{
select_show (debug_select);
if (label)
label_show (label);
}
static void
debug_redraw (void)
{
select_redraw (debug_select);
if (label)
label_redraw (label);
}
static void
debug_set_focus (void)
{
if (label)
label_set_focus (label);
cmd_state_push (CMD_DEBUG);
}
static void
debug_unset_focus (void)
{
if (label)
label_unset_focus (label);
cmd_state_pop ();
}
static void
print_line (WINDOW *win, int maxlen, int index, search_t *search)
{
str_t *str;
if (index < backlog_count)
str = backlog[index].str;
else
str = NULL;
if (win == NULL)
return;
if (str){
switch (backlog[index].level){
case DEBUG_ERROR:
wattrset (win, error_color);
break;
case DEBUG_WARN:
wattrset (win, warn_color);
break;
case DEBUG_INFO:
wattrset (win, info_color);
break;
default:
wattrset (win, text_color);
break;
}
maxlen -= window_addnstr (win, str->str, maxlen);
}
while (maxlen-- > 0)
window_addch (win, ' ');
}
static int
debug_count (select_t *nothing)
{
return backlog_count;
}
/* This file is generated by interface.pl script from interface.desc,
and inc.in. */
static WINDOW *interface_init (void);
#include "debug.inc"
#endif
/****************************************************************************
* BACKLOG FUNCTIONS
****************************************************************************/
#if DEBUG
static void
initialize_backlog (void)
{
if (backlog_size <= 0)
backlog_size = DEFAULT_BACKLOG_SIZE;
backlog = xcalloc (backlog_size, sizeof (struct debug));
backlog_count = 0;
backlog_first = 0;
}
static void
backlog_destroy (void)
{
int i;
if (backlog == NULL)
return;
for (i = 0; i < backlog_size; i++){
if (backlog[i].str)
str_destroy (backlog[i].str);
}
xfree (backlog);
backlog = NULL;
}
static void
backlog_add (enum level level, const char *fmt, va_list ap)
{
int index;
str_t *str;
index = (backlog_count + backlog_first) % backlog_size;
str = backlog[index].str;
if (str){
str_clear (str);
}
else {
str = str_create ();
backlog[index].str = str;
}
backlog[index].level = level;
str_vsprintf (str, fmt, ap);
if (backlog_count == backlog_size){
backlog_first++;
}
else {
backlog_count++;
}
}
#endif
/****************************************************************************
* INTERFACE FUNCTIONS
****************************************************************************/
void
debug_start (void)
{
#if DEBUG
WINDOW *window;
window = interface_init ();
initialize_backlog ();
debug_select = select_open (window, 1, print_line, debug_count);
debug_file = fopen (DEBUG_FILE, "a");
window_set_functions (window, debug_refresh, debug_redraw,
debug_set_focus, debug_unset_focus);
if (! debug_file)
return;
fprintf (debug_file, "start\n");
fflush (debug_file);
#endif
}
void
debug_end (void)
{
#if DEBUG
if (debug_select)
select_close (debug_select);
debug_select = NULL;
if (label)
label_destroy (label);
label = NULL;
backlog_destroy ();
if (! debug_file)
return;
fprintf (debug_file, "\n");
fflush (debug_file);
fclose (debug_file);
#endif
}
void
debug_msg (enum level level, const char *fmt, ...)
{
#if DEBUG
va_list arg;
if (!debug_file)
return;
va_start (arg, fmt);
backlog_add (level, fmt, arg);
va_end (arg);
switch (level){
case DEBUG_ERROR:
fprintf (debug_file, "ERROR: ");
break;
case DEBUG_WARN:
fprintf (debug_file, "WARN: ");
break;
case DEBUG_INFO:
fprintf (debug_file, "INFO: ");
break;
}
va_start (arg, fmt);
vfprintf (debug_file, fmt, arg);
fprintf (debug_file, "\n");
fflush (debug_file);
va_end (arg);
#endif
}
void
debug_next (void)
{
#if DEBUG
select_next (debug_select);
#endif
}
void
debug_prev (void)
{
#if DEBUG
select_prev (debug_select);
#endif
}
void
debug_next_page (void)
{
#if DEBUG
select_next_page (debug_select);
#endif
}
void
debug_prev_page (void)
{
#if DEBUG
select_prev_page (debug_select);
#endif
}
void
debug_first (void)
{
#if DEBUG
select_first (debug_select);
#endif
}
void
debug_last (void)
{
#if DEBUG
select_last (debug_select);
#endif
}
void
debug_show (void)
{
#if DEBUG
select_redraw (debug_select);
#endif
}
/****************************************************************************
* INTERFACE CLASS BODIES
****************************************************************************/
/****************************************************************************
*
* END MODULE debug.c
*
****************************************************************************/
syntax highlighted by Code2HTML, v. 0.9.1