mirror of
https://github.com/mirror/make.git
synced 2025-03-14 20:00:32 +08:00
240 lines
6.7 KiB
C
240 lines
6.7 KiB
C
/* 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);
|
|
int wl, al;
|
|
|
|
if (!cp)
|
|
cp = ep;
|
|
wl = (int)(cp - value);
|
|
type = decode_warn_name (value, wl);
|
|
if (cp == ep)
|
|
action = w_warn;
|
|
else
|
|
{
|
|
/* There's a warning action: decode it. */
|
|
++cp;
|
|
al = (int)(ep - cp);
|
|
action = decode_warn_action (cp, al);
|
|
}
|
|
|
|
if (type == wt_max)
|
|
{
|
|
if (!flocp)
|
|
ONS (fatal, NILF, _("unknown warning '%.*s'"), wl, value);
|
|
ONS (error, flocp,
|
|
_("unknown warning '%.*s': ignored"), wl, value);
|
|
}
|
|
else if (action == w_unset)
|
|
{
|
|
if (!flocp)
|
|
ONS (fatal, NILF,
|
|
_("unknown warning action '%.*s'"), al, cp);
|
|
ONS (error, flocp,
|
|
_("unknown warning action '%.*s': ignored"), al, cp);
|
|
}
|
|
else
|
|
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 ();
|
|
}
|