Branch data Line data Source code
1 : : #include "warnings.h"
2 : :
3 : : #include "asar.h"
4 : : #include <assert.h>
5 : : #include <stdarg.h>
6 : :
7 : : #include "interface-shared.h"
8 : :
9 : : static int asar_num_warnings = 0;
10 : : bool suppress_all_warnings = false;
11 : :
12 : : struct asar_warning_mapping
13 : : {
14 : : asar_warning_id warnid;
15 : : const char* name;
16 : : const char* message;
17 : : bool enabled;
18 : : bool enabled_default;
19 : :
20 : : asar_warning_mapping(asar_warning_id inwarnid, const char *iname, const char* inmessage, bool inenabled = true)
21 : : {
22 : : ++asar_num_warnings;
23 : :
24 : : warnid = inwarnid;
25 : : name = iname;
26 : : message = inmessage;
27 : : enabled = inenabled;
28 : : enabled_default = inenabled;
29 : :
30 : : // RPG Hacker: Sanity check. This makes sure that the order
31 : : // of entries in asar_warnings matches with the order of
32 : : // constants in asar_warning_id. This is important because
33 : : // we access asar_warnings as an array.
34 : : // Would love to do this via static_assert(), but can't
35 : : // think of a way to do so.
36 : : assert(warnid - warning_id_start == asar_num_warnings);
37 : : }
38 : : };
39 : :
40 : : // Keep in sync with asar_warning_id.
41 : : // Both, enum mapping and order, must match.
42 : : #define WRN(name) warning_id_ ## name, "W" #name
43 : : static asar_warning_mapping asar_warnings[] =
44 : : {
45 : : { WRN(relative_path_used), "Relative %s path passed to asar_patch_ex() - please use absolute paths only to prevent undefined behavior!" },
46 : :
47 : : { WRN(rom_too_short), "ROM is too short to have a title. (Expected '%s')" },
48 : : { WRN(rom_title_incorrect), "ROM title is incorrect. Expected '%s', got '%s'." },
49 : :
50 : : { WRN(65816_yy_x_does_not_exist), "($yy),x does not exist, assuming $yy,x." },
51 : : { WRN(65816_xx_y_assume_16_bit), "%s $xx,y is not valid with 8-bit parameters, assuming 16-bit." },
52 : : { WRN(spc700_assuming_8_bit), "This opcode does not exist with 16-bit parameters, assuming 8-bit." },
53 : :
54 : : { WRN(cross_platform_path), "This patch may not assemble cleanly on all platforms. Please use / instead." },
55 : :
56 : : { WRN(missing_org), "Missing org or freespace command." },
57 : : { WRN(set_middle_byte), "It would be wise to set the 008000 bit of this address." },
58 : :
59 : : { WRN(unrecognized_special_command), "Unrecognized special command - your version of Asar might be outdated." },
60 : :
61 : : { WRN(freespace_leaked), "This freespace appears to be leaked." },
62 : :
63 : : { WRN(warn_command), "warn command%s" },
64 : :
65 : : { WRN(implicitly_sized_immediate), "Implicitly sized immediate.", false },
66 : :
67 : : { WRN(xkas_deprecated), "xkas support is being deprecated and will be removed in a future version of Asar. Please use an older version of Asar (<=1.50) if you need it." },
68 : : { WRN(xkas_eat_parentheses), "xkas compatibility warning: Unlike xkas, Asar does not eat parentheses after defines." },
69 : : { WRN(xkas_label_access), "xkas compatibility warning: Label access is always 24bit in emulation mode, but may be 16bit in native mode." },
70 : : { WRN(xkas_warnpc_relaxed), "xkas conversion warning : warnpc is relaxed one byte in Asar." },
71 : : { WRN(xkas_style_conditional), "xkas-style conditional compilation detected. Please use the if command instead." },
72 : : { WRN(xkas_patch), "If you want to assemble an xkas patch, add ;@xkas at the top or you may run into a couple of problems." },
73 : : { WRN(xkas_incsrc_relative), "xkas compatibility warning: incsrc and incbin look for files relative to the patch in Asar, but xkas looks relative to the assembler." },
74 : : { WRN(convert_to_asar), "Convert the patch to native Asar format instead of making an Asar-only xkas patch." },
75 : :
76 : : { WRN(fixed_deprecated), "the 'fixed' parameter on freespace/freecode/freedata is deprecated - please use 'static' instead." },
77 : :
78 : : { WRN(autoclear_deprecated), "'autoclear' is deprecated - please use 'autoclean' instead." },
79 : :
80 : : { WRN(check_memory_file), "Accessing file '%s' which is not in memory while W%d is enabled.", false },
81 : :
82 : : { WRN(if_not_condition_deprecated), "'if !condition' is deprecated - please use 'if not(condition)' instead." },
83 : :
84 : : { WRN(function_redefined), "Function '%s' redefined." },
85 : :
86 : : { WRN(datasize_last_label), "Datasize used on last detected label '%s'." },
87 : : { WRN(datasize_exceeds_size), "Datasize exceeds 0xFFFF for label '%s'." },
88 : :
89 : : { WRN(mapper_already_set), "A mapper has already been selected." },
90 : : { WRN(feature_deprecated), "DEPRECATION NOTIFICATION: Feature \"%s\" is deprecated and will be REMOVED in the future. Please update your code to conform to newer styles. Suggested work around: %s." },
91 : :
92 : : { WRN(byte_order_mark_utf8), "UTF-8 byte order mark detected and skipped." },
93 : : };
94 : :
95 : : // RPG Hacker: Sanity check. This makes sure that the element count of asar_warnings
96 : : // matches with the number of constants in asar_warning_id. This is important, because
97 : : // we are going to access asar_warnings as an array.
98 : : static_assert(sizeof(asar_warnings) / sizeof(asar_warnings[0]) == warning_id_count, "asar_warnings and asar_warning_id are not in sync");
99 : :
100 : 427 : void asar_throw_warning(int whichpass, asar_warning_id warnid, ...)
101 : : {
102 [ + + + + ]: 427 : if (pass == whichpass && !suppress_all_warnings)
103 : : {
104 : : assert(warnid > warning_id_start && warnid < warning_id_end);
105 : :
106 : 188 : const asar_warning_mapping& warning = asar_warnings[warnid - warning_id_start - 1];
107 : :
108 [ + + ]: 188 : if (warning.enabled)
109 : : {
110 : : char warning_buffer[1024];
111 : : va_list args;
112 : 44 : va_start(args, warnid);
113 : :
114 : : #if defined(__clang__)
115 : : # pragma clang diagnostic push
116 : : // "format string is not a literal".
117 : : // The pointer we're passing here should always point to a string literal,
118 : : // thus, I think, we can safely ignore this here.
119 : : # pragma clang diagnostic ignored "-Wformat-nonliteral"
120 : : #endif
121 : :
122 : 44 : vsnprintf(warning_buffer, sizeof(warning_buffer), warning.message, args);
123 : :
124 : : #if defined(__clang__)
125 : : # pragma clang diagnostic pop
126 : : #endif
127 : :
128 : 44 : va_end(args);
129 : 44 : warn((int)warnid, warning_buffer);
130 : : }
131 : : }
132 : 427 : }
133 : :
134 : 44 : const char* get_warning_name(asar_warning_id warnid)
135 : : {
136 : : assert(warnid > warning_id_start && warnid < warning_id_end);
137 : :
138 : 44 : const asar_warning_mapping& warning = asar_warnings[warnid - warning_id_start - 1];
139 : :
140 : 44 : return warning.name;
141 : : }
142 : :
143 : :
144 : :
145 : 36 : void set_warning_enabled(asar_warning_id warnid, bool enabled)
146 : : {
147 : : assert(warnid > warning_id_start && warnid < warning_id_end);
148 : :
149 : 36 : asar_warning_mapping& warning = asar_warnings[warnid - warning_id_start - 1];
150 : :
151 : 36 : warning.enabled = enabled;
152 : 36 : }
153 : :
154 : 36 : asar_warning_id parse_warning_id_from_string(const char* string)
155 : : {
156 : : const char* pos = string;
157 : :
158 [ - + ]: 36 : if (pos == nullptr)
159 : : {
160 : : return warning_id_end;
161 : : }
162 : :
163 : :
164 [ + - + - ]: 36 : if (pos[0] == 'w' || pos[0] == 'W')
165 : : {
166 : 36 : ++pos;
167 : : }
168 [ + + ]: 702 : for(int i = 0; i < warning_id_end-warning_id_start-1; i++)
169 : : {
170 [ + + ]: 699 : if(!stricmpwithlower(pos, asar_warnings[i].name+1))
171 : : {
172 : 33 : return asar_warnings[i].warnid;
173 : : }
174 : : }
175 : 3 : char* endpos = nullptr;
176 : 3 : int numid = (int)strtol(pos, &endpos, 10);
177 : :
178 [ - + - + ]: 3 : if (endpos == nullptr || endpos[0] != '\0')
179 : : {
180 : : return warning_id_end;
181 : : }
182 : :
183 : : asar_warning_id warnid = (asar_warning_id)numid;
184 : :
185 [ - + ]: 3 : if (warnid <= warning_id_start || warnid >= warning_id_end)
186 : : {
187 : : return warning_id_end;
188 : : }
189 : :
190 : 3 : asar_throw_warning(1, warning_id_feature_deprecated, "Numerical warnings", "Please transition to Wwarning_name");
191 : : return warnid;
192 : : }
193 : :
194 : 0 : void reset_warnings_to_default()
195 : : {
196 [ # # ]: 0 : for (int i = (int)(warning_id_start + 1); i < (int)warning_id_end; ++i)
197 : : {
198 : 0 : asar_warning_mapping& warning = asar_warnings[i - (int)warning_id_start - 1];
199 : :
200 : 0 : warning.enabled = warning.enabled_default;
201 : : }
202 : 0 : }
203 : :
204 : : struct warnings_state
205 : : {
206 : : bool enabled[warning_id_count];
207 : : };
208 : :
209 : : static autoarray<warnings_state> warnings_state_stack;
210 : : static warnings_state main_warnings_state;
211 : :
212 : 290 : void push_warnings(bool warnings_command)
213 : : {
214 : : warnings_state current_state;
215 : :
216 [ + + ]: 9280 : for (int i = 0; i < (int)warning_id_count; ++i)
217 : : {
218 : 8990 : current_state.enabled[i] = asar_warnings[i].enabled;
219 : : }
220 : :
221 [ + + ]: 290 : if (warnings_command)
222 : : {
223 : 9 : warnings_state_stack.append(current_state);
224 : : }
225 : : else
226 : : {
227 : 281 : main_warnings_state = current_state;
228 : : }
229 : 290 : }
230 : :
231 : 288 : void pull_warnings(bool warnings_command)
232 : : {
233 [ + + + + ]: 288 : if (warnings_state_stack.count > 0 || !warnings_command)
234 : : {
235 : : warnings_state prev_state;
236 : :
237 [ + - ]: 6 : if (warnings_command)
238 : : {
239 : 6 : prev_state = warnings_state_stack[warnings_state_stack.count - 1];
240 : : }
241 : : else
242 : : {
243 : 279 : prev_state = main_warnings_state;
244 : : }
245 : :
246 [ + + ]: 9120 : for (int i = 0; i < (int)warning_id_count; ++i)
247 : : {
248 : 8835 : asar_warnings[i].enabled = prev_state.enabled[i];
249 : : }
250 : :
251 [ + + ]: 285 : if (warnings_command)
252 : : {
253 : 6 : warnings_state_stack.remove(warnings_state_stack.count - 1);
254 : : }
255 : 285 : }
256 : : else
257 : : {
258 : 3 : asar_throw_error(0, error_type_block, error_id_pullwarnings_without_pushwarnings);
259 : : }
260 : 285 : }
261 : :
262 : 279 : void verify_warnings()
263 : : {
264 [ + + ]: 279 : if (warnings_state_stack.count > 0)
265 : : {
266 : 3 : asar_throw_error(0, error_type_null, error_id_pushwarnings_without_pullwarnings);
267 : :
268 : 3 : warnings_state_stack.reset();
269 : : }
270 : 279 : }
|