/* 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 #endif #include #include #include #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 * ****************************************************************************/