summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Smith <psmith@gnu.org>2023-03-18 17:24:45 -0400
committerPaul Smith <psmith@gnu.org>2023-04-02 10:02:18 -0400
commita0d1e76d604df5bd006fd5ed6a69963d3c6b4d7a (patch)
tree02d739d8168207be28535f359b0a6583f231f047 /src
parent03ecd94488b85adc38746ec3e7c2a297a522598e (diff)
downloadmake-git-a0d1e76d604df5bd006fd5ed6a69963d3c6b4d7a.tar.gz
Add support for .WARNINGS special variable
Create a new special variable, .WARNINGS, to allow per-makefile control over warnings. The command line settings will override this. Move the handling of warning flags to a new file: src/warning.c. Allow the decode to work with generic strings, and call it from decode_switches(). * Makefile.am: Add new file src/warning.c. * build_w32.bat: Ditto. * builddos.bat: Ditto. * po/POTFILES.in: Ditto. * src/makeint.h: #define for the .WARNINGS variable name. * src/warning.h: Add declarations for methods moved from main.c. Rename the enum warning_state to warning_action. * src/warning.c: New file. Move all warning encode/decode here from main.c. * src/main.c: Move methods into warning.c and call those methods instead. (main): Set .WARNINGS as a special variable. * src/job.c (construct_command_argv): Rename to warning_action. * src/read.c (tilde_expand): Ditto. * src/variable.c (set_special_var): Update warnings when the .WARNINGS special variable is set. * tests/scripts/options/warn: Check invalid warning options. * tests/scripts/variables/WARNINGS: Add tests for the .WARNINGS special variable.
Diffstat (limited to 'src')
-rw-r--r--src/expand.c1
-rw-r--r--src/job.c2
-rw-r--r--src/main.c166
-rw-r--r--src/makeint.h5
-rw-r--r--src/misc.c3
-rw-r--r--src/output.c25
-rw-r--r--src/read.c2
-rw-r--r--src/variable.c41
-rw-r--r--src/warning.c235
-rw-r--r--src/warning.h50
10 files changed, 338 insertions, 192 deletions
diff --git a/src/expand.c b/src/expand.c
index 533e7dfa..a1efa831 100644
--- a/src/expand.c
+++ b/src/expand.c
@@ -24,6 +24,7 @@ this program. If not, see <https://www.gnu.org/licenses/>. */
#include "job.h"
#include "variable.h"
#include "rule.h"
+#include "warning.h"
/* Initially, any errors reported when expanding strings will be reported
against the file where the error appears. */
diff --git a/src/job.c b/src/job.c
index b26cb2ca..bca45529 100644
--- a/src/job.c
+++ b/src/job.c
@@ -3635,7 +3635,7 @@ construct_command_argv (char *line, char **restp, struct file *file,
{
struct variable *var;
/* Turn off undefined variables warning while we expand HOME. */
- enum warning_state save = warn_get (wt_undefined_var);
+ enum warning_action save = warn_get (wt_undefined_var);
warn_set (wt_undefined_var, w_ignore);
shell = allocated_expand_variable_for_file (STRING_SIZE_TUPLE ("SHELL"), file);
diff --git a/src/main.c b/src/main.c
index 843cab09..f4250726 100644
--- a/src/main.c
+++ b/src/main.c
@@ -273,18 +273,6 @@ static struct stringlist *eval_strings = 0;
static int print_usage_flag = 0;
-/* The default state of warnings. */
-
-enum warning_state default_warnings[wt_max];
-
-/* Current state of warnings. */
-
-enum warning_state warnings[wt_max];
-
-/* Global warning settings. */
-
-enum warning_state warn_global;
-
/* Command line warning flags. */
static struct stringlist *warn_flags = 0;
@@ -663,15 +651,6 @@ initialize_global_hash_tables (void)
hash_init_function_table ();
}
-static void
-initialize_warnings ()
-{
- /* All warnings must have a default. */
- default_warnings[wt_invalid_var] = w_warn;
- default_warnings[wt_invalid_ref] = w_warn;
- default_warnings[wt_undefined_var] = w_ignore;
-}
-
/* This character map locate stop chars when parsing GNU makefiles.
Each element is true if we should stop parsing on that character. */
@@ -886,101 +865,6 @@ decode_debug_flags (void)
debug_flag = 0;
}
-static const char *w_state_map[w_error+1] = {NULL, "ignore", "warn", "error"};
-static const char *w_name_map[wt_max] = {"invalid-var",
- "invalid-ref",
- "undefined-var"};
-
-#define encode_warn_state(_b,_s) variable_buffer_output (_b, w_state_map[_s], strlen (w_state_map[_s]))
-#define encode_warn_name(_b,_t) variable_buffer_output (_b, w_name_map[_t], strlen (w_name_map[_t]))
-
-static enum warning_state
-decode_warn_state (const char *state, size_t length)
-{
- for (enum warning_state st = w_ignore; st <= w_error; ++st)
- {
- size_t len = strlen (w_state_map[st]);
- if (length == len && strncasecmp (state, w_state_map[st], length) == 0)
- return st;
- }
-
- return w_unset;
-}
-
-static enum warning_type
-decode_warn_name (const char *name, size_t length)
-{
- for (enum warning_type wt = wt_invalid_var; wt < wt_max; ++wt)
- {
- size_t len = strlen (w_name_map[wt]);
- if (length == len && strncasecmp (name, w_name_map[wt], length) == 0)
- return wt;
- }
-
- return wt_max;
-}
-
-static void
-decode_warn_flags ()
-{
- const char **pp;
-
- /* */
- if (warn_undefined_variables_flag)
- {
- warn_set (wt_undefined_var, w_warn);
- warn_undefined_variables_flag = 0;
- }
-
- if (warn_flags)
- for (pp=warn_flags->list; *pp; ++pp)
- {
- const char *p = *pp;
-
- while (*p != '\0')
- {
- enum warning_state state;
- /* See if the value is comma-separated. */
- const char *ep = strchr (p, ',');
- if (!ep)
- ep = p + strlen (p);
-
- /* If the value is just a state set it globally. */
- state = decode_warn_state (p, ep - p);
- if (state != w_unset)
- warn_global = state;
- else
- {
- enum warning_type type;
- const char *cp = memchr (p, ':', ep - p);
- if (!cp)
- cp = ep;
- type = decode_warn_name (p, cp - p);
- if (type == wt_max)
- ONS (fatal, NILF,
- _("unknown warning '%.*s'"), (int)(cp - p), p);
-
- /* If there's a warning state, decode it. */
- if (cp == ep)
- state = w_warn;
- else
- {
- ++cp;
- state = decode_warn_state (cp, ep - cp);
- if (state == w_unset)
- ONS (fatal, NILF,
- _("unknown warning state '%.*s'"), (int)(ep - cp), cp);
- }
- warn_set (type, state);
- }
-
- p = ep;
- while (*p == ',')
- ++p;
- }
- }
-}
-
static void
decode_output_sync_flags (void)
{
@@ -1323,7 +1207,7 @@ main (int argc, char **argv, char **envp)
initialize_stopchar_map ();
- initialize_warnings ();
+ warn_init ();
#ifdef SET_STACK_SIZE
/* Get rid of any avoidable limit on stack size. */
@@ -1554,6 +1438,7 @@ main (int argc, char **argv, char **envp)
define_variable_cname (".VARIABLES", "", o_default, 0)->special = 1;
/* define_variable_cname (".TARGETS", "", o_default, 0)->special = 1; */
define_variable_cname (".RECIPEPREFIX", "", o_default, 0)->special = 1;
+ define_variable_cname (WARNINGS_NAME, "", o_default, 0)->special = 1;
define_variable_cname (".SHELLFLAGS", "-c", o_default, 0);
define_variable_cname (".LOADED", "", o_default, 0);
@@ -3013,7 +2898,7 @@ main (int argc, char **argv, char **envp)
/* If we detected some clock skew, generate one last warning */
if (clock_skew_detected)
O (error, NILF,
- _("warning: Clock skew detected. Your build may be incomplete."));
+ _("warning: Clock skew detected. Your build may be incomplete."));
/* Exit. */
die (makefile_status);
@@ -3443,9 +3328,19 @@ decode_switches (int argc, const char **argv, enum variable_origin origin)
/* If there are any options that need to be decoded do it now. */
decode_debug_flags ();
- decode_warn_flags ();
decode_output_sync_flags ();
+ /* Support old-style option. */
+ if (warn_undefined_variables_flag)
+ {
+ decode_warn_actions ("undefined-var", NULL);
+ warn_undefined_variables_flag = 0;
+ }
+
+ if (warn_flags)
+ for (const char **pp = warn_flags->list; *pp; ++pp)
+ decode_warn_actions (*pp, NULL);
+
/* Perform any special switch handling. */
run_silent = silent_flag;
}
@@ -3655,38 +3550,7 @@ define_makeflags (int makefile)
case filename:
case strlist:
if (cs->c == WARN_OPT)
- {
- enum warning_type wt;
- char sp = '=';
-
- /* See if any warning options are set. */
- for (wt = 0; wt < wt_max; ++wt)
- if (warnings[wt] != w_unset)
- break;
- if (wt == wt_max && warn_global == w_unset)
- break;
-
- /* Something is set so construct a --warn option. */
- fp = variable_buffer_output(fp, STRING_SIZE_TUPLE (" --warn"));
- if (wt == wt_max && warn_global == w_warn)
- break;
-
- if (warn_global > w_unset)
- {
- fp = variable_buffer_output (fp, &sp, 1);
- sp = ',';
- fp = encode_warn_state (fp, warn_global);
- }
- for (wt = 0; wt < wt_max; ++wt)
- if (warnings[wt] > w_unset)
- {
- fp = variable_buffer_output (fp, &sp, 1);
- sp = ',';
- fp = encode_warn_name (fp, wt);
- if (warnings[wt] != w_warn)
- fp = encode_warn_state (variable_buffer_output(fp, ":", 1), warnings[wt]);
- }
- }
+ fp = encode_warn_flag (fp);
else
{
struct stringlist *sl = *(struct stringlist **) cs->value_ptr;
diff --git a/src/makeint.h b/src/makeint.h
index e130e761..f34ec361 100644
--- a/src/makeint.h
+++ b/src/makeint.h
@@ -553,6 +553,8 @@ void error (const floc *flocp, size_t length, const char *fmt, ...)
ATTRIBUTE ((__format__ (__printf__, 3, 4)));
void fatal (const floc *flocp, size_t length, const char *fmt, ...)
ATTRIBUTE ((noreturn, __format__ (__printf__, 3, 4)));
+char *format (const char *prefix, size_t length, const char *fmt, ...)
+ ATTRIBUTE ((__format__ (__printf__, 3, 4)));
void out_of_memory (void) NORETURN;
/* When adding macros to this list be sure to update the value of
@@ -760,6 +762,9 @@ extern int batch_mode_shell;
#define RECIPEPREFIX_DEFAULT '\t'
extern char cmd_prefix;
+/* Setting warning actions. */
+#define WARNINGS_NAME ".WARNINGS"
+
extern unsigned int no_intermediates;
#if HAVE_MKFIFO
diff --git a/src/misc.c b/src/misc.c
index 80fd63ac..04437c2b 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -437,6 +437,7 @@ find_next_token (const char **ptr, size_t *lengthptr)
return (char *)p;
}
+
/* Write a BUFFER of size LEN to file descriptor FD.
Retry short writes from EINTR. Return LEN, or -1 on error. */
ssize_t
@@ -611,7 +612,7 @@ get_tmpdir ()
unsigned int found = 0;
for (tp = tlist; *tp; ++tp)
- if ((tmpdir = getenv (*tp)) && *tmpdir != '\0')
+ if ((tmpdir = getenv (*tp)) != NULL && *tmpdir != '\0')
{
struct stat st;
int r;
diff --git a/src/output.c b/src/output.c
index eddabe03..2cf76072 100644
--- a/src/output.c
+++ b/src/output.c
@@ -475,8 +475,8 @@ error (const floc *flocp, size_t len, const char *fmt, ...)
void
fatal (const floc *flocp, size_t len, const char *fmt, ...)
{
- va_list args;
const char *stop = _(". Stop.\n");
+ va_list args;
char *start;
char *p;
@@ -505,6 +505,29 @@ fatal (const floc *flocp, size_t len, const char *fmt, ...)
die (MAKE_FAILURE);
}
+/* Format a message and return a pointer to an internal buffer. */
+
+char *
+format (const char *prefix, size_t len, const char *fmt, ...)
+{
+ va_list args;
+ size_t plen = prefix ? strlen (prefix) : 0;
+ char *start;
+ char *p;
+
+ len += strlen (fmt) + plen + 1;
+ start = p = get_buffer (len);
+
+ if (plen)
+ p = mempcpy (p, prefix, plen);
+
+ va_start (args, fmt);
+ vsprintf (p, fmt, args);
+ va_end (args);
+
+ return start;
+}
+
/* Print an error message from errno. */
void
diff --git a/src/read.c b/src/read.c
index 1694ec7d..878a5620 100644
--- a/src/read.c
+++ b/src/read.c
@@ -3068,7 +3068,7 @@ tilde_expand (const char *name)
{
/* Turn off undefined variables warning while we expand HOME. */
- enum warning_state save = warn_get (wt_undefined_var);
+ enum warning_action save = warn_get (wt_undefined_var);
warn_set (wt_undefined_var, w_ignore);
home_dir = allocated_expand_variable (STRING_SIZE_TUPLE ("HOME"));
diff --git a/src/variable.c b/src/variable.c
index d2cfcc94..bfaef6c1 100644
--- a/src/variable.c
+++ b/src/variable.c
@@ -198,10 +198,8 @@ check_valid_name (const floc* flocp, const char *name, size_t length)
if (cp == end)
return;
- if (warn_error (wt_invalid_var))
- ONS (fatal, flocp, _("invalid variable name '%.*s'"), (int)length, name);
-
- ONS (error, flocp, _("invalid variable name '%.*s'"), (int)length, name);
+ warning (wt_invalid_var, flocp,
+ ONS (format, 0, _("invalid variable name '%.*s'"), (int)length, name));
}
void
@@ -491,12 +489,8 @@ check_variable_reference (const char *name, size_t length)
if (cp == end)
return;
- if (warn_error (wt_invalid_ref))
- ONS (fatal, *expanding_var,
- _("invalid variable reference '%.*s'"), (int)length, name);
-
- ONS (error, *expanding_var,
- _("invalid variable reference '%.*s'"), (int)length, name);
+ warning (wt_invalid_ref, *expanding_var,
+ ONS (format, 0, _("invalid variable reference '%.*s'"), (int)length, name));
}
/* Lookup a variable whose name is a string starting at NAME
@@ -1335,11 +1329,18 @@ set_special_var (struct variable *var, enum variable_origin origin)
reset_makeflags (origin);
else if (streq (var->name, RECIPEPREFIX_NAME))
+ /* The user is resetting the command introduction prefix. This has to
+ happen immediately, so that subsequent rules are interpreted
+ properly. */
+ cmd_prefix = var->value[0]=='\0' ? RECIPEPREFIX_DEFAULT : var->value[0];
+
+ else if (streq (var->name, WARNINGS_NAME))
{
- /* The user is resetting the command introduction prefix. This has to
- happen immediately, so that subsequent rules are interpreted
- properly. */
- cmd_prefix = var->value[0]=='\0' ? RECIPEPREFIX_DEFAULT : var->value[0];
+ /* It's weird but for .WARNINGS to make sense we need to expand them
+ when they are set, even if it's a recursive variable. */
+ char *actions = allocated_expand_variable (STRING_SIZE_TUPLE (WARNINGS_NAME));
+ decode_warn_actions (actions, &var->fileinfo);
+ free (actions);
}
return var;
@@ -1499,7 +1500,7 @@ do_variable_definition (const floc *flocp, const char *varname,
{
char *s;
if (streq (varname, MAKEFLAGS_NAME)
- && (s = strstr (v->value, " -- ")))
+ && (s = strstr (v->value, " -- ")) != NULL)
/* We found a separator in MAKEFLAGS. Ignore variable
assignments: set_special_var() will reconstruct things. */
cp = mempcpy (cp, v->value, s - v->value);
@@ -1914,6 +1915,7 @@ static const struct defined_vars defined_vars[] = {
{ STRING_SIZE_TUPLE ("-*-eval-flags-*-") },
{ STRING_SIZE_TUPLE ("VPATH") },
{ STRING_SIZE_TUPLE ("GPATH") },
+ { STRING_SIZE_TUPLE (WARNINGS_NAME) },
{ NULL, 0 }
};
@@ -1927,12 +1929,9 @@ warn_undefined (const char *name, size_t len)
if (dp->len == len && memcmp (dp->name, name, len) == 0)
return;
- if (warn_error (wt_undefined_var))
- fatal (reading_file, len, _("reference to undefined variable '%.*s'"),
- (int)len, name);
- else
- error (reading_file, len, _("reference to undefined variable '%.*s'"),
- (int)len, name);
+ warning (wt_undefined_var, reading_file,
+ ONS (format, 0, _("reference to undefined variable '%.*s'"),
+ (int)len, name));
}
}
diff --git a/src/warning.c b/src/warning.c
new file mode 100644
index 00000000..c295fdc7
--- /dev/null
+++ b/src/warning.c
@@ -0,0 +1,235 @@
+/* Control warning output in GNU Make.
+Copyright (C) 2023 Free Software Foundation, Inc.
+This file is part of GNU Make.
+
+GNU Make 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; either version 3 of the License, or (at your option) any later
+version.
+
+GNU Make 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, see <https://www.gnu.org/licenses/>. */
+
+#include "makeint.h"
+#include "warning.h"
+#include "variable.h"
+
+/* Current action for each warning. */
+enum warning_action warnings[wt_max];
+
+/* The default behavior of warnings. */
+static struct warning_data warn_default;
+
+/* Warning settings from the .WARNING variable. */
+static struct warning_data warn_variable;
+
+/* Warning settings from the command line. */
+static struct warning_data warn_flag;
+
+static const char *w_action_map[w_error+1] = {NULL, "ignore", "warn", "error"};
+static const char *w_name_map[wt_max] = {
+ "invalid-var",
+ "invalid-ref",
+ "undefined-var"
+ };
+
+#define encode_warn_action(_b,_s) \
+ variable_buffer_output (_b, w_action_map[_s], strlen (w_action_map[_s]))
+#define encode_warn_name(_b,_t) \
+ variable_buffer_output (_b, w_name_map[_t], strlen (w_name_map[_t]))
+
+static void set_warnings ()
+{
+ /* Called whenever any warnings could change; resets the current actions. */
+ for (enum warning_type wt = 0; wt < wt_max; ++wt)
+ warnings[wt] =
+ warn_flag.actions[wt] != w_unset ? warn_flag.actions[wt]
+ : warn_flag.global != w_unset ? warn_flag.global
+ : warn_variable.actions[wt] != w_unset ? warn_variable.actions[wt]
+ : warn_variable.global != w_unset ? warn_variable.global
+ : warn_default.actions[wt];
+}
+
+void
+warn_init ()
+{
+ memset (&warn_default, '\0', sizeof (warn_default));
+ memset (&warn_variable, '\0', sizeof (warn_variable));
+ memset (&warn_flag, '\0', sizeof (warn_flag));
+
+ /* All warnings must have a default. */
+ warn_default.global = w_warn;
+ warn_default.actions[wt_invalid_var] = w_warn;
+ warn_default.actions[wt_invalid_ref] = w_warn;
+ warn_default.actions[wt_undefined_var] = w_ignore;
+
+ set_warnings ();
+}
+
+static void
+init_data (struct warning_data *data)
+{
+ data->global = w_unset;
+ for (enum warning_type wt = wt_invalid_var; wt < wt_max; ++wt)
+ data->actions[wt] = w_unset;
+}
+
+static enum warning_action
+decode_warn_action (const char *action, size_t length)
+{
+ for (enum warning_action st = w_ignore; st <= w_error; ++st)
+ {
+ size_t len = strlen (w_action_map[st]);
+ if (length == len && strncasecmp (action, w_action_map[st], length) == 0)
+ return st;
+ }
+
+ return w_unset;
+}
+
+static enum warning_type
+decode_warn_name (const char *name, size_t length)
+{
+ for (enum warning_type wt = wt_invalid_var; wt < wt_max; ++wt)
+ {
+ size_t len = strlen (w_name_map[wt]);
+ if (length == len && strncasecmp (name, w_name_map[wt], length) == 0)
+ return wt;
+ }
+
+ return wt_max;
+}
+
+void
+decode_warn_actions (const char *value, const floc *flocp)
+{
+ struct warning_data *data = &warn_flag;
+
+ NEXT_TOKEN (value);
+
+ if (flocp)
+ {
+ data = &warn_variable;
+ /* When a variable is set to empty, reset everything. */
+ if (*value == '\0')
+ init_data (data);
+ }
+
+ while (*value != '\0')
+ {
+ enum warning_action action;
+
+ /* Find the end of the next warning definition. */
+ const char *ep = value;
+ while (! STOP_SET (*ep, MAP_BLANK|MAP_COMMA|MAP_NUL))
+ ++ep;
+
+ /* If the value is just an action set it globally. */
+ action = decode_warn_action (value, ep - value);
+ if (action != w_unset)
+ data->global = action;
+ else
+ {
+ enum warning_type type;
+ const char *cp = memchr (value, ':', ep - value);
+ if (!cp)
+ cp = ep;
+ type = decode_warn_name (value, cp - value);
+ if (type == wt_max)
+ {
+ int l = (int)(cp - value);
+ if (!flocp)
+ ONS (fatal, NILF, _("unknown warning '%.*s'"), l, value);
+ ONS (error, flocp,
+ _("unknown warning '%.*s': ignored"), l, value);
+ }
+
+ /* If there's a warning action, decode it. */
+ if (cp == ep)
+ action = w_warn;
+ else
+ {
+ ++cp;
+ action = decode_warn_action (cp, ep - cp);
+ if (action == w_unset)
+ {
+ int l = (int)(ep - cp);
+ if (!flocp)
+ ONS (fatal, NILF, _("unknown warning action '%.*s'"), l, cp);
+ ONS (error, flocp,
+ _("unknown warning action '%.*s': ignored"), l, cp);
+ }
+ }
+ data->actions[type] = action;
+ }
+
+ value = ep;
+ while (STOP_SET (*value, MAP_BLANK|MAP_COMMA))
+ ++value;
+ }
+
+ set_warnings ();
+}
+
+char *
+encode_warn_flag (char *fp)
+{
+ enum warning_type wt;
+ char sp = '=';
+
+ /* See if any warning options are set. */
+ for (wt = 0; wt < wt_max; ++wt)
+ if (warn_flag.actions[wt] != w_unset)
+ break;
+ if (wt == wt_max && warn_flag.global == w_unset)
+ return fp;
+
+ /* Something is set so construct a --warn option. */
+ fp = variable_buffer_output (fp, STRING_SIZE_TUPLE (" --warn"));
+
+ /* If only a global action set to warn, we're done. */
+ if (wt == wt_max && warn_flag.global == w_warn)
+ return fp;
+
+ /* If a global action is set, add it. */
+ if (warn_flag.global > w_unset)
+ {
+ fp = variable_buffer_output (fp, &sp, 1);
+ sp = ',';
+ fp = encode_warn_action (fp, warn_flag.global);
+ }
+
+ /* Add any specific actions. */
+ if (wt != wt_max)
+ for (wt = 0; wt < wt_max; ++wt)
+ {
+ enum warning_action act = warn_flag.actions[wt];
+ if (act > w_unset)
+ {
+ fp = variable_buffer_output (fp, &sp, 1);
+ sp = ',';
+ fp = encode_warn_name (fp, wt);
+ if (act != w_warn)
+ fp = encode_warn_action (variable_buffer_output (fp, ":", 1), act);
+ }
+ }
+
+ return fp;
+}
+
+void
+warn_get_vardata (struct warning_data *data)
+{
+ memcpy (data, &warn_variable, sizeof (warn_variable));
+}
+
+void
+warn_set_vardata (const struct warning_data *data)
+{
+ memcpy (&warn_variable, data, sizeof (warn_variable));
+ set_warnings ();
+}
diff --git a/src/warning.h b/src/warning.h
index 78e99893..658af93a 100644
--- a/src/warning.h
+++ b/src/warning.h
@@ -23,8 +23,8 @@ enum warning_type
wt_max
};
-/* State of a given warning. */
-enum warning_state
+/* Action taken for a given warning. */
+enum warning_action
{
w_unset = 0,
w_ignore,
@@ -32,25 +32,24 @@ enum warning_state
w_error
};
-/* The default state of warnings. */
-extern enum warning_state default_warnings[wt_max];
-
-/* Current state of warnings. */
-extern enum warning_state warnings[wt_max];
+struct warning_data
+ {
+ enum warning_action global; /* Global setting. */
+ enum warning_action actions[wt_max]; /* Action for each warning type. */
+ };
-/* Global warning settings. */
-extern enum warning_state warn_global;
+/* Actions taken for each warning. */
+extern enum warning_action warnings[wt_max];
-/* Get the current state of a given warning. */
-#define warn_get(_w) (warnings[_w] != w_unset ? warnings[_w] \
- : warn_global != w_unset ? warn_global \
- : default_warnings[_w])
+/* Get the current action for a given warning. */
+#define warn_get(_w) (warnings[_w])
-/* Set the current state of a given warning. Can't use w_unset here. */
-#define warn_set(_w,_f) do{ warnings[_w] = (_f); } while (0)
+/* Set the current actin for a given warning. Can't use w_unset here.
+ This should only be used for temporary resetting of warnings. */
+#define warn_set(_w,_f) do{ warnings[_w] = (_f); }while(0)
/* True if we should check for the warning in the first place. */
-#define warn_check(_w) (warn_get (_w) > w_ignore)
+#define warn_check(_w) (warn_get (_w) > w_ignore)
/* Check if the warning is ignored. */
#define warn_ignored(_w) (warn_get (_w) == w_ignore)
@@ -60,3 +59,22 @@ extern enum warning_state warn_global;
/* Check if the warning is in "error" mode. */
#define warn_error(_w) (warn_get (_w) == w_error)
+
+void warn_init (void);
+void decode_warn_actions (const char *value, const floc *flocp);
+char *encode_warn_flag (char *fp);
+
+void warn_get_vardata (struct warning_data *data);
+void warn_set_vardata (const struct warning_data *data);
+
+#define warning(_t,_f,_m) \
+ do{ \
+ if (warn_check (_t)) \
+ { \
+ char *_a = xstrdup (_m); \
+ if (warn_error (_t)) \
+ fatal (_f, strlen (_a), "%s", _a); \
+ error (_f, strlen (_a), _("warning: %s"), _a); \
+ free (_a); \
+ } \
+ }while(0)