From 40f81d19aa4f0c986d58092bfedf587040d2c32d Mon Sep 17 00:00:00 2001 From: Mehdi Abaakouk Date: Wed, 1 Mar 2017 23:02:10 +0100 Subject: [PATCH] Add debug_level/debug_file options This change allows to change debug_level and debug_file on the fly. It adds the -l mutt arguments to pass the logging file on startup. debug options passed as mutt arguments always override the configuration file. Closes #445 --- globals.h | 5 ++ init.c | 153 +++++++++++++++++++++++++++++++++++++++++------------- init.h | 17 ++++++ lib.c | 3 ++ lib.h | 3 ++ main.c | 20 +++++-- 6 files changed, 161 insertions(+), 40 deletions(-) diff --git a/globals.h b/globals.h index 8c1f7d7e5..9d250336e 100644 --- a/globals.h +++ b/globals.h @@ -233,6 +233,11 @@ WHERE short NewsPollTimeout; WHERE short NntpContext; #endif +#ifdef DEBUG +WHERE short DebugLevel; +WHERE char *DebugFile; +#endif + WHERE short ConnectTimeout; WHERE short HistSize; WHERE short MenuContext; diff --git a/init.c b/init.c index 65fe5d792..8fe1dc590 100644 --- a/init.c +++ b/init.c @@ -1913,10 +1913,17 @@ static void restore_default(struct option_t *p) break; case DT_PATH: FREE((char **) p->data); - if (p->init) + char *init = NULL; +#ifdef DEBUG + if (mutt_strcmp(p->option, "debug_file") == 0 && debugfile_cmdline) + init = debugfile_cmdline; + else +#endif + init = (char *) p->init; + if (init) { char path[_POSIX_PATH_MAX]; - strfcpy(path, (char *) p->init, sizeof(path)); + strfcpy(path, init, sizeof(path)); mutt_expand_path(path, sizeof(path)); *((char **) p->data) = safe_strdup(path); } @@ -1938,7 +1945,12 @@ static void restore_default(struct option_t *p) case DT_NUM: case DT_SORT: case DT_MAGIC: - *((short *) p->data) = p->init; +#ifdef DEBUG + if (mutt_strcmp(p->option, "debug_level") == 0 && debuglevel_cmdline) + *((short *) p->data) = debuglevel_cmdline; + else +#endif + *((short *) p->data) = p->init; break; case DT_RX: { @@ -2100,6 +2112,69 @@ char **mutt_envlist(void) return envlist; } +#ifdef DEBUG +/** + * start_debug - prepare the debugging file + * + * @return nothing + * + * This method prepares and opens a new debug file for mutt_debug. + */ +static void start_debug(void) +{ + int i; + char buf[_POSIX_PATH_MAX]; + + /* rotate the old debug logs */ + for (i = 3; i >= 0; i--) + { + snprintf(debugfilename, sizeof(debugfilename), "%s%d", DebugFile, i); + snprintf(buf, sizeof(buf), "%s%d", DebugFile, i + 1); + rename(debugfilename, buf); + } + + if ((debugfile = safe_fopen(debugfilename, "w")) != NULL) + { + setbuf(debugfile, NULL); /* don't buffer the debugging output! */ + mutt_debug(1, "NeoMutt/%s (%s) debugging at level %d\n", PACKAGE_VERSION, + MUTT_VERSION, debuglevel); + } +} + +/** + * restart_debug - reload the debugging configuration + * + * @return nothing + * + * This method closes the old debug file is debug was enabled, + * then reconfigure the debugging system from the configuration options + * and start a new debug file if debug is enabled + */ +static void restart_debug(void) +{ + bool disable_debug = (debuglevel > 0 && DebugLevel == 0); + bool enable_debug = (debuglevel == 0 && DebugLevel > 0); + bool file_changed = + ((mutt_strlen(debugfilename) - 1) != mutt_strlen(DebugFile) || + mutt_strncmp(debugfilename, DebugFile, mutt_strlen(debugfilename) - 1)); + + if (disable_debug || file_changed) + { + mutt_debug(1, "NeoMutt/%s (%s) stop debugging\n", PACKAGE_VERSION, MUTT_VERSION); + safe_fclose(&debugfile); + } + + if (!enable_debug && !disable_debug && debuglevel != DebugLevel) + mutt_debug(1, "NeoMutt/%s (%s) debugging at level %d\n", PACKAGE_VERSION, + MUTT_VERSION, DebugLevel); + + debuglevel = DebugLevel; + + if (enable_debug || (file_changed && debuglevel > 0)) + start_debug(); +} +#endif + /* Helper function for parse_setenv(). * It's broken out because some other parts of mutt (filter.c) need * to set/overwrite environment variables in envlist before execing. @@ -2456,6 +2531,14 @@ static int parse_set(BUFFER *tmp, BUFFER *s, unsigned long data, BUFFER *err) } else if (DTYPE(MuttVars[idx].type) == DT_PATH) { +#ifdef DEBUG + if (mutt_strcmp(MuttVars[idx].option, "debug_file") == 0 && debugfile_cmdline) + { + mutt_message(_("set debug_file ignored, it have been overridden " + "with cmdline")); + break; + } +#endif /* MuttVars[idx].data is already 'char**' (or some 'void**') or... * so cast to 'void*' is okay */ FREE((void *) MuttVars[idx].data); @@ -2463,6 +2546,10 @@ static int parse_set(BUFFER *tmp, BUFFER *s, unsigned long data, BUFFER *err) strfcpy(scratch, tmp->data, sizeof(scratch)); mutt_expand_path(scratch, sizeof(scratch)); *((char **) MuttVars[idx].data) = safe_strdup(scratch); +#ifdef DEBUG + if (mutt_strcmp(MuttVars[idx].option, "debug_file") == 0) + restart_debug(); +#endif } else if (DTYPE(MuttVars[idx].type) == DT_STR) { @@ -2620,6 +2707,14 @@ static int parse_set(BUFFER *tmp, BUFFER *s, unsigned long data, BUFFER *err) r = -1; break; } +#ifdef DEBUG + else if (mutt_strcmp(MuttVars[idx].option, "debug_level") == 0 && debuglevel_cmdline) + { + mutt_message( + _("set debug_level ignored, it have been overridden with cmdline")); + break; + } +#endif else *ptr = val; @@ -2630,6 +2725,14 @@ static int parse_set(BUFFER *tmp, BUFFER *s, unsigned long data, BUFFER *err) *ptr = 0; mutt_init_history(); } +#ifdef DEBUG + else if (mutt_strcmp(MuttVars[idx].option, "debug_level") == 0) + { + if (*ptr < 0) + *ptr = 0; + restart_debug(); + } +#endif else if (mutt_strcmp(MuttVars[idx].option, "pager_index_lines") == 0) { if (*ptr < 0) @@ -3700,29 +3803,6 @@ int mutt_getvaluebyname(const char *name, const struct mapping_t *map) return -1; } -#ifdef DEBUG -static void start_debug(void) -{ - int i; - char buf[_POSIX_PATH_MAX]; - char buf2[_POSIX_PATH_MAX]; - - /* rotate the old debug logs */ - for (i = 3; i >= 0; i--) - { - snprintf(buf, sizeof(buf), "%s/.muttdebug%d", NONULL(Homedir), i); - snprintf(buf2, sizeof(buf2), "%s/.muttdebug%d", NONULL(Homedir), i + 1); - rename(buf, buf2); - } - if ((debugfile = safe_fopen(buf, "w")) != NULL) - { - setbuf(debugfile, NULL); /* don't buffer the debugging output! */ - mutt_debug(1, "NeoMutt %s%s (%s) debugging at level %d\n", PACKAGE_VERSION, - GitVer, MUTT_VERSION, debuglevel); - } -} -#endif - static int execute_commands(LIST *p) { BUFFER err, token; @@ -3856,10 +3936,20 @@ void mutt_init(int skip_sys_rc, LIST *commands) Shell = safe_strdup((p = getenv("SHELL")) ? p : "/bin/sh"); } + /* Set standard defaults */ + for (i = 0; MuttVars[i].option; i++) + { + set_default(&MuttVars[i]); + restore_default(&MuttVars[i]); + } + #ifdef DEBUG - /* Start up debugging mode if requested */ - if (debuglevel > 0) + /* Start up debugging mode if requested from cmdline */ + if (debuglevel_cmdline > 0) + { + debuglevel = debuglevel_cmdline; start_debug(); + } #endif /* And about the host... */ @@ -3988,13 +4078,6 @@ void mutt_init(int skip_sys_rc, LIST *commands) Matches = safe_calloc(Matches_listsize, sizeof(char *)); - /* Set standard defaults */ - for (i = 0; MuttVars[i].option; i++) - { - set_default(&MuttVars[i]); - restore_default(&MuttVars[i]); - } - CurrentMenu = MENU_MAIN; diff --git a/init.h b/init.h index aba951669..d24d217da 100644 --- a/init.h +++ b/init.h @@ -651,6 +651,23 @@ struct option_t MuttVars[] = { ** rest of the string are expanded in the \fIC\fP locale (that is in US ** English). */ +#ifdef DEBUG + { "debug_level", DT_NUM, R_NONE, UL &DebugLevel, 0 }, + /* + ** .pp + ** The debug level. Note: to debug the early startup process (before the + ** configuration is loaded), ``-d'' mutt argument must be used. + ** debug_level/debug_file are ignored until it's read from the configuration + ** file. + */ + { "debug_file", DT_PATH, R_NONE, UL &DebugFile, UL "~/.muttdebug" }, + /* + ** .pp + ** The location prefix of the debug file, 0 is append to the debug file + ** Old debug files are renamed with the prefix 1, 2, 3 and 4. + ** See ``debug_level'' for more detail. + */ +#endif { "default_hook", DT_STR, R_NONE, UL &DefaultHook, UL "~f %s !~P | (~P ~C %s)" }, /* ** .pp diff --git a/lib.c b/lib.c index b7bcf8766..e35663af3 100644 --- a/lib.c +++ b/lib.c @@ -1015,8 +1015,11 @@ const char *mutt_strsysexit(int e) } #ifdef DEBUG +char debugfilename[_POSIX_PATH_MAX]; FILE *debugfile; int debuglevel; +char *debugfile_cmdline = NULL; +int debuglevel_cmdline; void mutt_debug(int level, const char *fmt, ...) { diff --git a/lib.h b/lib.h index 6a6fa2ca2..3b8c06275 100644 --- a/lib.h +++ b/lib.h @@ -114,8 +114,11 @@ void mutt_exit(int); #ifdef DEBUG +extern char debugfilename[_POSIX_PATH_MAX]; extern FILE *debugfile; extern int debuglevel; +extern char *debugfile_cmdline; +extern int debuglevel_cmdline; void mutt_debug(int level, const char *fmt, ...); #else #define mutt_debug(...) do { } while (0) diff --git a/main.c b/main.c index 23eff3520..761ef2ee3 100644 --- a/main.c +++ b/main.c @@ -252,9 +252,10 @@ int main(int argc, char **argv, char **environ) #ifdef USE_NNTP if ((i = getopt(argc, argv, - "+A:a:Bb:F:f:c:Dd:Ee:g:GH:s:i:hm:npQ:RSvxyzZ")) != EOF) + "+A:a:Bb:F:f:c:Dd:l:Ee:g:GH:s:i:hm:npQ:RSvxyzZ")) != EOF) #else - if ((i = getopt(argc, argv, "+A:a:Bb:F:f:c:Dd:Ee:H:s:i:hm:npQ:RSvxyzZ")) != EOF) + if ((i = getopt(argc, argv, + "+A:a:Bb:F:f:c:Dd:l:Ee:H:s:i:hm:npQ:RSvxyzZ")) != EOF) #endif switch (i) { @@ -297,14 +298,14 @@ int main(int argc, char **argv, char **environ) case 'd': #ifdef DEBUG - if (mutt_atoi(optarg, &debuglevel) < 0 || debuglevel <= 0) + if (mutt_atoi(optarg, &debuglevel_cmdline) < 0 || debuglevel_cmdline <= 0) { fprintf(stderr, _("Error: value '%s' is invalid for -d.\n"), optarg); return 1; } - printf(_("Debugging at level %d.\n"), debuglevel); + printf(_("Debugging at level %d.\n"), debuglevel_cmdline); #else - printf(_("DEBUG was not defined during compilation. Ignored.\n")); + printf(_("DEBUG was not defined during compilation. -d Ignored.\n")); #endif break; @@ -324,6 +325,15 @@ int main(int argc, char **argv, char **environ) includeFile = optarg; break; + case 'l': +#ifdef DEBUG + debugfile_cmdline = optarg; + printf(_("Debugging at file %s.\n"), debugfile_cmdline); +#else + printf(_("DEBUG was not defined during compilation. -l Ignored.\n")); +#endif + break; + case 'm': /* should take precedence over .muttrc setting, so save it for later */ newMagic = optarg; -- 2.40.0