1 /*
2     $Id: error.c 2620 2021-04-25 12:05:16Z soci $
3 
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License along
15     with this program; if not, write to the Free Software Foundation, Inc.,
16     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 
18 */
19 #include "error.h"
20 #include <string.h>
21 #include <errno.h>
22 #include "wchar.h"
23 #include "file.h"
24 #include "64tass.h"
25 #include "unicode.h"
26 #include "eval.h"
27 #include "arguments.h"
28 #include "opcodes.h"
29 #include "section.h"
30 #include "macro.h"
31 
32 #include "strobj.h"
33 #include "addressobj.h"
34 #include "registerobj.h"
35 #include "namespaceobj.h"
36 #include "operobj.h"
37 #include "typeobj.h"
38 #include "labelobj.h"
39 #include "errorobj.h"
40 #include "noneobj.h"
41 #include "symbolobj.h"
42 #include "anonsymbolobj.h"
43 #include "console.h"
44 
45 struct file_list_s *current_file_list;
46 const struct file_list_s *dummy_file_list;
47 
48 #define ALIGN(v) (((v) + (sizeof(int *) - 1)) & ~(sizeof(int *) - 1))
49 
50 static unsigned int errors = 0, warnings = 0;
51 
52 struct file_listnode_s {
53     struct file_list_s flist;
54     struct file_listnode_s *parent;
55     struct avltree_node node;
56     struct avltree members;
57     uint8_t pass;
58 };
59 
60 static struct file_listnode_s file_list;
61 static const struct file_listnode_s *included_from = &file_list;
62 static const char *prgname;
63 
64 struct errorbuffer_s {
65     size_t max;
66     size_t len;
67     size_t header_pos;
68     size_t header_stop;
69     uint8_t *data;
70     struct avltree members;
71 };
72 
73 static struct errorbuffer_s error_list;
74 static struct avltree notdefines;
75 
76 typedef enum Severity_types {
77     SV_NOTE, SV_WARNING, SV_NONEERROR, SV_ERROR, SV_FATAL
78 } Severity_types;
79 
80 struct errorentry_s {
81     Severity_types severity;
82     size_t error_len;
83     size_t line_len;
84     const struct file_list_s *file_list;
85     struct linepos_s epoint;
86     linecpos_t caret;
87     struct avltree_node node;
88 };
89 
90 struct notdefines_s {
91     str_t cfname;
92     const struct file_list_s *file_list;
93     struct linepos_s epoint;
94     uint8_t pass;
95     struct avltree_node node;
96 };
97 
duplicate_compare(const struct avltree_node * aa,const struct avltree_node * bb)98 static FAST_CALL int duplicate_compare(const struct avltree_node *aa, const struct avltree_node *bb)
99 {
100     const struct errorentry_s *a = cavltree_container_of(aa, struct errorentry_s, node);
101     const struct errorentry_s *b = cavltree_container_of(bb, struct errorentry_s, node);
102     const uint8_t *aerr, *berr;
103 
104     if (a->severity != b->severity) return (int)a->severity - (int)b->severity;
105     if (a->file_list != b->file_list) return a->file_list > b->file_list ? 1 : -1;
106     if (a->error_len != b->error_len) return a->error_len > b->error_len ? 1 : -1;
107     if (a->epoint.line != b->epoint.line) return a->epoint.line > b->epoint.line ? 1 : -1;
108     if (a->epoint.pos != b->epoint.pos) return a->epoint.pos > b->epoint.pos ? 1 : -1;
109 
110     aerr = (const uint8_t *)(a + 1);
111     berr = (const uint8_t *)(b + 1);
112 
113     if ((a->line_len | b->line_len) != 0) {
114         int i;
115         const uint8_t *aline, *bline;
116 
117         if (a->line_len != 0) {
118             aline = aerr;
119             aerr += a->line_len;
120         } else if (a->epoint.line == 0) {
121             aline = (const uint8_t *)"";
122         } else {
123             aline = &a->file_list->file->data[a->file_list->file->line[a->epoint.line - 1]];
124         }
125 
126         if (b->line_len != 0) {
127             bline = berr;
128             berr += b->line_len;
129         } else if (a->epoint.line == 0) {
130             bline = (const uint8_t *)"";
131         } else {
132             bline = &a->file_list->file->data[a->file_list->file->line[a->epoint.line - 1]];
133         }
134 
135         i = strcmp((const char *)aline, (const char *)bline);
136         if (i != 0) return i;
137     }
138     return memcmp(aerr, berr, a->error_len);
139 }
140 
close_error(void)141 static void close_error(void) {
142     static bool duplicate;
143     if (error_list.header_pos < error_list.len) {
144         struct errorentry_s *err = (struct errorentry_s *)&error_list.data[error_list.header_pos];
145         err->error_len = error_list.len - error_list.header_pos - (sizeof *err) - err->line_len;
146         switch (err->severity) {
147         case SV_NOTE:
148             if (!duplicate) memset(&err->node, 0, sizeof err->node);
149             break;
150         default:
151             duplicate = avltree_insert(&err->node, &error_list.members, duplicate_compare) != NULL;
152         }
153         if (duplicate) {
154             error_list.len = error_list.header_pos;
155         }
156         error_list.header_pos = ALIGN(error_list.len);
157     }
158 }
159 
error_extend(void)160 static void error_extend(void) {
161     struct errorentry_s *err;
162     uint8_t *data = (uint8_t *)realloc(error_list.data, error_list.max);
163     size_t diff, pos;
164     bool dir;
165     if (data == NULL) err_msg_out_of_memory2();
166     dir = data >= error_list.data;
167     diff = dir ? (size_t)(data - error_list.data) : (size_t)(error_list.data - data);
168     error_list.data = data;
169     if (diff == 0) return;
170     for (pos = 0; pos < error_list.header_pos; pos = ALIGN(pos + (sizeof *err) + err->line_len + err->error_len)) {
171         err = (struct errorentry_s *)&data[pos];
172         if (err->node.left != NULL) err->node.left = (struct avltree_node *)((dir ? ((uint8_t *)err->node.left + diff) : ((uint8_t *)err->node.left - diff)));
173         if (err->node.right != NULL) err->node.right = (struct avltree_node *)((dir ? ((uint8_t *)err->node.right + diff) : ((uint8_t *)err->node.right - diff)));
174         if (err->node.parent != NULL) err->node.parent = (struct avltree_node *)((dir ? ((uint8_t *)err->node.parent + diff) : ((uint8_t *)err->node.parent - diff)));
175     }
176     if (error_list.members.root != NULL) error_list.members.root = (struct avltree_node *)((dir ? ((uint8_t *)error_list.members.root + diff) : ((uint8_t *)error_list.members.root - diff)));
177 }
178 
new_error_msg_common(Severity_types severity,const struct file_list_s * flist,linepos_t epoint,size_t line_len,linecpos_t pos)179 static void new_error_msg_common(Severity_types severity, const struct file_list_s *flist, linepos_t epoint, size_t line_len, linecpos_t pos) {
180     struct errorentry_s *err;
181     close_error();
182     error_list.len = error_list.header_pos + sizeof *err;
183     if (error_list.len < sizeof *err) err_msg_out_of_memory2(); /* overflow */
184     error_list.len += line_len;
185     if (error_list.len < line_len) err_msg_out_of_memory2(); /* overflow */
186     if (error_list.len > error_list.max) {
187         error_list.max = error_list.len + 0x200;
188         if (error_list.max < 0x200) err_msg_out_of_memory2(); /* overflow */
189         error_extend();
190     }
191     err = (struct errorentry_s *)&error_list.data[error_list.header_pos];
192     err->severity = severity;
193     err->error_len = 0;
194     err->line_len = line_len;
195     err->file_list = flist;
196     err->epoint.line = epoint->line;
197     err->epoint.pos = pos;
198     err->caret = epoint->pos;
199 }
200 
201 static struct {
202     Severity_types severity;
203     const struct file_list_s *flist;
204     linepos_t epoint;
205 } new_error_msg_more_param;
206 
207 static void new_error_msg_more(void);
new_error_msg(Severity_types severity,const struct file_list_s * flist,linepos_t epoint)208 static bool new_error_msg(Severity_types severity, const struct file_list_s *flist, linepos_t epoint) {
209     size_t line_len;
210     if (in_macro && flist == current_file_list && epoint->line == lpoint.line) {
211         struct linepos_s opoint;
212         const struct file_list_s *eflist = macro_error_translate(&opoint, epoint->pos);
213         if (eflist != NULL) {
214             new_error_msg_common(severity, eflist, &opoint, 0, opoint.pos);
215             new_error_msg_more_param.severity = severity;
216             new_error_msg_more_param.flist = flist;
217             new_error_msg_more_param.epoint = epoint;
218             return true;
219         }
220     }
221     switch (severity) {
222     case SV_NOTE: line_len = 0; break;
223     default: line_len = ((epoint->line == lpoint.line) && not_in_file(pline, flist->file)) ? (strlen((const char *)pline) + 1) : 0; break;
224     }
225     new_error_msg_common(severity, flist, epoint, line_len, macro_error_translate2(epoint->pos));
226     if (line_len != 0) memcpy(&error_list.data[error_list.header_pos + sizeof(struct errorentry_s)], pline, line_len);
227     return false;
228 }
229 
new_error_msg_err(const Error * err)230 static bool new_error_msg_err(const Error *err) {
231     struct linepos_s opoint;
232     size_t line_len;
233     if (in_macro && err->file_list == current_file_list && err->epoint.line == lpoint.line) {
234         const struct file_list_s *eflist = macro_error_translate(&opoint, err->caret);
235         if (eflist != NULL) {
236             new_error_msg_common(SV_ERROR, eflist, &opoint, 0, opoint.pos);
237             return true;
238         }
239     }
240     if (err->line == NULL) {
241         opoint = err->epoint;
242         line_len = 0;
243     } else {
244         opoint.line = err->epoint.line;
245         opoint.pos = err->caret;
246         line_len = strlen((const char *)err->line) + 1;
247     }
248     new_error_msg_common(SV_ERROR, err->file_list, &opoint, line_len, err->epoint.pos);
249     if (line_len != 0) memcpy(&error_list.data[error_list.header_pos + sizeof(struct errorentry_s)], err->line, line_len);
250     return false;
251 }
252 
new_error_msg2(bool type,linepos_t epoint)253 static void new_error_msg2(bool type, linepos_t epoint) {
254     Severity_types severity = type ? SV_ERROR : SV_WARNING;
255     bool more = new_error_msg(severity, current_file_list, epoint);
256     if (more) new_error_msg_more();
257 }
258 
file_list_compare(const struct avltree_node * aa,const struct avltree_node * bb)259 static FAST_CALL int file_list_compare(const struct avltree_node *aa, const struct avltree_node *bb)
260 {
261     const struct file_list_s *a = &cavltree_container_of(aa, struct file_listnode_s, node)->flist;
262     const struct file_list_s *b = &cavltree_container_of(bb, struct file_listnode_s, node)->flist;
263     if (a->epoint.line != b->epoint.line) return a->epoint.line > b->epoint.line ? 1 : -1;
264     if (a->epoint.pos != b->epoint.pos) return a->epoint.pos > b->epoint.pos ? 1 : -1;
265     return a->file->uid - b->file->uid;
266 }
267 
268 static struct file_lists_s {
269     struct file_listnode_s file_lists[90];
270     struct file_lists_s *next;
271 } *file_lists = NULL;
272 
parent_file_list(const struct file_list_s * cflist)273 const struct file_list_s *parent_file_list(const struct file_list_s *cflist) {
274     return &((const struct file_listnode_s *)cflist)->parent->flist;
275 }
276 
277 static struct file_listnode_s *lastfl;
278 static int file_listsp;
enterfile(struct file_s * file,linepos_t epoint)279 void enterfile(struct file_s *file, linepos_t epoint) {
280     struct avltree_node *b;
281     struct file_listnode_s *cflist = (struct file_listnode_s *)current_file_list;
282     lastfl->flist.file = file;
283     lastfl->flist.epoint = *epoint;
284     b = avltree_insert(&lastfl->node, &cflist->members, file_list_compare);
285     if (b == NULL) {
286         lastfl->parent = cflist;
287         avltree_init(&lastfl->members);
288         cflist = lastfl;
289         if (file_listsp == 89) {
290             struct file_lists_s *old = file_lists;
291             file_lists = (struct file_lists_s *)mallocx(sizeof *file_lists);
292             file_lists->next = old;
293             file_listsp = 0;
294         } else file_listsp++;
295         lastfl = &file_lists->file_lists[file_listsp];
296     } else {
297         cflist = avltree_container_of(b, struct file_listnode_s, node);
298     }
299     cflist->pass = pass;
300     current_file_list = &cflist->flist;
301 }
302 
exitfile(void)303 void exitfile(void) {
304     struct file_listnode_s *cflist = (struct file_listnode_s *)current_file_list;
305     if (cflist->parent != NULL) current_file_list = &cflist->parent->flist;
306 }
307 
adderror2(const uint8_t * s,size_t len)308 static void adderror2(const uint8_t *s, size_t len) {
309     if (len + error_list.len > error_list.max) {
310         error_list.max += (len > 0x200) ? len : 0x200;
311         error_extend();
312     }
313     memcpy(error_list.data + error_list.len, s, len);
314     error_list.len += len;
315 }
316 
adderror(const char * s)317 static void adderror(const char *s) {
318     adderror2((const uint8_t *)s, strlen(s));
319 }
320 
321 static const char * const terr_warning[] = {
322     "deprecated modulo operator, use '%' instead",
323     "deprecated not equal operator, use '!=' instead",
324     "deprecated directive, only for TASM compatible mode",
325     "please use format(\"%d\", ...) as '^' will change it's meaning",
326     "please use quotes now to allow expressions in future",
327     "constant result, possibly changeable to 'lda'",
328     "independent result, possibly changeable to 'lda'",
329 #ifdef _WIN32
330     "the file's real name is not '",
331 #endif
332 #if defined _WIN32 || defined __WIN32__ || defined __MSDOS__ || defined __DOS__
333     "use '/' as path separation '",
334 #else
335     "this name uses reserved characters '",
336 #endif
337     "use relative path for '"
338 };
339 
340 static const char * const terr_error[] = {
341     "double defined range",
342     "double defined escape",
343     "extra characters on line",
344     "more than two characters",
345     "floating point overflow",
346     "general syntax",
347     "expression syntax",
348     "label required",
349     "division by zero ",
350     "zero value not allowed",
351     "most significiant bit must be clear in byte",
352     "at least one byte is needed",
353     "last byte must not be gap",
354     "address in different program bank ",
355     "address out of section",
356     "negative number raised on fractional power",
357     "zero raised to negative power ",
358     "square root of negative number ",
359     "logarithm of non-positive number ",
360     "not in range -1.0 to 1.0 ",
361     "empty range not allowed",
362     "empty string not allowed",
363     "empty list not allowed",
364     "more than a single character",
365     "requirements not met",
366     "conflict",
367     "index out of range ",
368     "key not in dictionary ",
369     "offset out of range",
370     "not hashable ",
371     "not a key and value pair ",
372     "too large for a %u bit signed integer ",
373     "too large for a %u bit unsigned integer ",
374     "value needs to be non-negative ",
375     "operands could not be broadcast together with shapes %" PRIuSIZE " and %" PRIuSIZE,
376     "can't get sign of ",
377     "can't get absolute value of ",
378     "can't get integer value of ",
379     "can't get length of ",
380     "can't get size of ",
381     "can't get boolean value of ",
382     "not iterable ",
383     "no byte sized",
384     "no word sized",
385     "no long sized",
386     "not a direct page address ",
387     "not a data bank address ",
388     "not a bank 0 address ",
389     "out of memory",
390     "addressing mode too complex",
391     "empty encoding, add something or correct name",
392     "closing directive '",
393     "opening directive '",
394     "must be used within a loop",
395     "not measurable as start offset beyond size of original"
396 };
397 
398 static const char * const terr_fatal[] = {
399     "can't open file",
400     "error reading file",
401     "can't write object file",
402     "can't write listing file",
403     "can't write label file",
404     "can't write make file",
405     "can't write error file",
406     "file recursion",
407     "macro recursion too deep",
408     "function recursion too deep",
409     "weak recursion too deep",
410     "too many passes"
411 };
412 
err_msg_variable(Obj * val)413 static void err_msg_variable(Obj *val) {
414     Obj *err;
415     adderror(val->obj->name);
416     err = val->obj->str(val, NULL, 40);
417     if (err != NULL) {
418         if (err->obj == STR_OBJ) {
419             Str *str = Str(err);
420             adderror(" '");
421             adderror2(str->data, str->len);
422             adderror("'");
423         }
424         val_destroy(err);
425     }
426 }
427 
str_name(const uint8_t * data,size_t len)428 static void str_name(const uint8_t *data, size_t len) {
429     adderror(" '");
430     if (len != 0) {
431         if (data[0] == '-') {
432             adderror("-");
433         } else if (data[0] == '+') {
434             adderror("+");
435         } else if (data[0] == '.' || data[0] == '#') {
436             adderror("<anonymous>");
437         } else adderror2(data, len);
438     }
439     adderror("'");
440 }
441 
442 static void err_opcode(uint32_t);
443 
err_msg2(Error_types no,const void * prm,linepos_t epoint)444 void err_msg2(Error_types no, const void *prm, linepos_t epoint) {
445     bool more;
446     if (no < 0x40) {
447         switch (no) {
448         case ERROR___OPTIMIZABLE:
449             new_error_msg2(diagnostic_errors.optimize, epoint);
450             adderror("could be shorter by using '");
451             adderror((const char *)prm);
452             adderror("' instead");
453             adderror(" [-Woptimize]");
454             break;
455         case ERROR______SIMPLIFY:
456             new_error_msg2(diagnostic_errors.optimize, epoint);
457             adderror("could be simpler by using '");
458             adderror((const char *)prm);
459             adderror("' instead");
460             adderror(" [-Woptimize]");
461             break;
462         case ERROR_____REDUNDANT:
463             new_error_msg2(diagnostic_errors.optimize, epoint);
464             adderror("possibly redundant ");
465             adderror((const char *)prm);
466             adderror(" [-Woptimize]");
467             break;
468         case ERROR__CONST_RESULT:
469             new_error_msg2(diagnostic_errors.optimize, epoint);
470             adderror(terr_warning[no]);
471             adderror(" [-Woptimize]");
472             break;
473         case ERROR_______OLD_NEQ:
474         case ERROR____OLD_MODULO:
475         case ERROR____OLD_STRING:
476         case ERROR_______OLD_ENC:
477             new_error_msg2(diagnostic_errors.deprecated, epoint);
478             adderror(terr_warning[no]);
479             adderror(" [-Wdeprecated]");
480             break;
481         case ERROR_____OLD_EQUAL:
482             new_error_msg2(diagnostic_errors.old_equal, epoint);
483             adderror("deprecated equal operator, use '==' instead [-Wold-equal]");
484             break;
485         case ERROR_NONIMMEDCONST:
486             new_error_msg2(diagnostic_errors.immediate, epoint);
487             adderror("immediate addressing mode suggested [-Wimmediate]");
488             break;
489         case ERROR_LEADING_ZEROS:
490             new_error_msg2(diagnostic_errors.leading_zeros, epoint);
491             adderror("leading zeros ignored [-Wleading-zeros]");
492             break;
493         case ERROR_DIRECTIVE_IGN:
494             new_error_msg2(diagnostic_errors.ignored, epoint);
495             adderror("directive ignored [-Wignored]");
496             break;
497         case ERROR_FLOAT_COMPARE:
498             new_error_msg2(diagnostic_errors.float_compare, epoint);
499             adderror("approximate floating point ");
500             adderror((const char *)prm);
501             adderror("' [-Wfloat-compare]");
502             break;
503         case ERROR___FLOAT_ROUND:
504             new_error_msg2(diagnostic_errors.float_round, epoint);
505             adderror("implicit floating point rounding [-Wfloat-round]");
506             break;
507         case ERROR___LONG_BRANCH:
508             new_error_msg2(diagnostic_errors.long_branch, epoint);
509             adderror("long branch used [-Wlong-branch]");
510             break;
511         case ERROR_WUSER_DEFINED:
512             more = new_error_msg(SV_WARNING, current_file_list, epoint);
513             adderror2(((const Str *)prm)->data, ((const Str *)prm)->len);
514             if (more) new_error_msg_more();
515             break;
516 #ifdef _WIN32
517         case ERROR___INSENSITIVE:
518 #endif
519 #if defined _WIN32 || defined __WIN32__ || defined __MSDOS__ || defined __DOS__
520         case ERROR_____BACKSLASH:
521 #else
522         case ERROR__RESERVED_CHR:
523 #endif
524         case ERROR_ABSOLUTE_PATH:
525             new_error_msg2(diagnostic_errors.portable, epoint);
526             adderror(terr_warning[no]);
527             adderror2(((const str_t *)prm)->data, ((const str_t *)prm)->len);
528             adderror("' [-Wportable]");
529             break;
530         default:
531             more = new_error_msg(SV_WARNING, current_file_list, epoint);
532             adderror(terr_warning[no]);
533             if (more) new_error_msg_more();
534             break;
535         }
536         return;
537     }
538 
539     if (no < 0xc0) {
540         char line[1024];
541         more = new_error_msg(SV_ERROR, current_file_list, epoint);
542         switch (no) {
543         case ERROR_BRANCH_TOOFAR:
544             sprintf(line,"branch too far by %+d bytes", *(const int *)prm); adderror(line);
545             break;
546         case ERROR____PTEXT_LONG:
547             sprintf(line,"ptext too long by %" PRIuSIZE " bytes", *(const size_t *)prm - 0x100); adderror(line);
548             break;
549         case ERROR__BRANCH_CROSS:
550             sprintf(line,"branch crosses page by %+d bytes", *(const int *)prm); adderror(line);
551             break;
552         case ERROR__USER_DEFINED:
553             adderror2(((const Str *)prm)->data, ((const Str *)prm)->len);
554             break;
555         case ERROR______EXPECTED:
556             adderror((const char *)prm);
557             adderror(" expected");
558             break;
559         case ERROR__MISSING_OPEN:
560         case ERROR_MISSING_CLOSE:
561             adderror(terr_error[no - 0x40]);
562             adderror((const char *)prm);
563             adderror("' not found");
564             break;
565         case ERROR_RESERVED_LABL:
566             adderror("reserved symbol name '");
567             adderror2(((const str_t *)prm)->data, ((const str_t *)prm)->len);
568             adderror("'");
569             break;
570         case ERROR_____NOT_BANK0:
571         case ERROR____NOT_DIRECT:
572         case ERROR__NOT_DATABANK:
573         case ERROR_CANT_CROSS_BA:
574             adderror(terr_error[no - 0x40]);
575             if (prm != NULL) err_msg_variable((Obj *)prm);
576             break;
577         case ERROR___UNKNOWN_CPU:
578             adderror("unknown processor '");
579             adderror2(((const str_t *)prm)->data, ((const str_t *)prm)->len);
580             adderror("'");
581             break;
582         case ERROR__NO_BYTE_ADDR:
583         case ERROR__NO_WORD_ADDR:
584         case ERROR__NO_LONG_ADDR:
585             adderror(terr_error[no - 0x40]);
586             err_opcode(*(const uint32_t *)prm);
587             break;
588         default:
589             adderror(terr_error[no - 0x40]);
590         }
591         if (more) new_error_msg_more();
592         return;
593     }
594 
595     more = new_error_msg(SV_FATAL, current_file_list, epoint);
596     switch (no) {
597     case ERROR_UNKNOWN_OPTIO:
598         adderror("unknown option '");
599         adderror2(((const str_t *)prm)->data, ((const str_t *)prm)->len);
600         adderror("'");
601         break;
602     case ERROR____LABEL_ROOT:
603         adderror("scope '");
604         adderror2(((const str_t *)prm)->data, ((const str_t *)prm)->len);
605         adderror("' for label listing not found");
606         break;
607     case ERROR__SECTION_ROOT:
608         adderror("section '");
609         adderror2(((const str_t *)prm)->data, ((const str_t *)prm)->len);
610         adderror("' for output not found");
611         break;
612     default:
613         adderror(terr_fatal[no - 0xc0]);
614     }
615     if (more) new_error_msg_more();
616 }
617 
err_msg(Error_types no,const void * prm)618 void err_msg(Error_types no, const void* prm) {
619     err_msg2(no, prm, &lpoint);
620 }
621 
err_msg_str_name(const char * msg,const str_t * name,linepos_t epoint)622 static void err_msg_str_name(const char *msg, const str_t *name, linepos_t epoint) {
623     bool more = new_error_msg(SV_ERROR, current_file_list, epoint);
624     adderror(msg);
625     if (name != NULL) str_name(name->data, name->len);
626     if (more) new_error_msg_more();
627 }
628 
err_msg_big_address(linepos_t epoint)629 void err_msg_big_address(linepos_t epoint) {
630     Obj *val = get_star_value(current_address->l_address, current_address->l_address_val);
631     bool more = new_error_msg(SV_ERROR, current_file_list, epoint);
632     adderror("address not in processor address space ");
633     err_msg_variable(val);
634     val_destroy(val);
635     if (more) new_error_msg_more();
636 }
637 
err_msg_big_integer(const Error * err)638 static bool err_msg_big_integer(const Error *err) {
639     char msg2[256];
640     bool more = new_error_msg_err(err);
641     sprintf(msg2, terr_error[err->num - 0x40], err->u.intconv.bits);
642     adderror(msg2);
643     err_msg_variable(err->u.intconv.val);
644     return more;
645 }
646 
new_error_msg_err_more(const Error * err)647 static void new_error_msg_err_more(const Error *err) {
648     size_t line_len;
649     struct linepos_s opoint;
650     if (err->line == NULL) {
651         opoint = err->epoint;
652         line_len = 0;
653     } else {
654         opoint.line = err->epoint.line;
655         opoint.pos = err->caret;
656         line_len = strlen((const char *)err->line) + 1;
657     }
658     new_error_msg_common(SV_NOTE, err->file_list, &opoint, line_len, err->epoint.pos);
659     if (line_len != 0) memcpy(&error_list.data[error_list.header_pos + sizeof(struct errorentry_s)], err->line, line_len);
660     adderror("original location in an expanded macro was here");
661 }
662 
new_error_msg_more(void)663 static void new_error_msg_more(void) {
664     const struct file_list_s *flist = new_error_msg_more_param.flist;
665     linepos_t epoint = new_error_msg_more_param.epoint;
666     size_t line_len;
667     switch (new_error_msg_more_param.severity) {
668     case SV_NOTE: line_len = 0; break;
669     default: line_len = ((epoint->line == lpoint.line) && not_in_file(pline, flist->file)) ? (strlen((const char *)pline) + 1) : 0; break;
670     }
671     new_error_msg_common(SV_NOTE, flist, epoint, line_len, macro_error_translate2(epoint->pos));
672     if (line_len != 0) memcpy(&error_list.data[error_list.header_pos + sizeof(struct errorentry_s)], pline, line_len);
673     adderror("original location in an expanded macro was here");
674 }
675 
err_msg_invalid_conv(const Error * err)676 static bool err_msg_invalid_conv(const Error *err) {
677     bool more;
678     Obj *v1 = err->u.conv.val;
679     if (v1->obj == ERROR_OBJ) {
680         err_msg_output((const Error *)v1);
681         return false;
682     }
683     more = new_error_msg_err(err);
684     adderror("conversion of ");
685     err_msg_variable(v1);
686     adderror(" to ");
687     adderror(err->u.conv.t->name);
688     adderror(" is not possible");
689     return more;
690 }
691 
notdefines_compare(const struct avltree_node * aa,const struct avltree_node * bb)692 static FAST_CALL int notdefines_compare(const struct avltree_node *aa, const struct avltree_node *bb)
693 {
694     const struct notdefines_s *a = cavltree_container_of(aa, struct notdefines_s, node);
695     const struct notdefines_s *b = cavltree_container_of(bb, struct notdefines_s, node);
696     if (a->file_list != b->file_list) return a->file_list > b->file_list ? 1 : -1;
697     if (a->epoint.line != b->epoint.line) return a->epoint.line > b->epoint.line ? 1 : -1;
698     if (a->epoint.pos != b->epoint.pos) return a->epoint.pos > b->epoint.pos ? 1 : -1;
699     return str_cmp(&a->cfname, &b->cfname);
700 }
701 
notdefines_free(struct avltree_node * aa)702 static void notdefines_free(struct avltree_node *aa) {
703     struct notdefines_s *a = avltree_container_of(aa, struct notdefines_s, node);
704     free((uint8_t *)a->cfname.data);
705     free(a);
706 }
707 
708 static struct notdefines_s *lastnd = NULL;
err_msg_not_defined3(const Error * err)709 static void err_msg_not_defined3(const Error *err) {
710     Namespace *l = err->u.notdef.names;
711     struct notdefines_s *tmp2;
712     struct avltree_node *b;
713     bool more;
714 
715     if (constcreated && pass < max_pass) return;
716 
717     if (lastnd == NULL) {
718         lastnd = (struct notdefines_s *)mallocx(sizeof *lastnd);
719     }
720 
721     if (err->u.notdef.symbol->obj == SYMBOL_OBJ) {
722         const str_t *name = &Symbol(err->u.notdef.symbol)->name;
723         str_cfcpy(&lastnd->cfname, name);
724         lastnd->file_list = l->file_list;
725         lastnd->epoint = l->epoint;
726         lastnd->pass = pass;
727         b = avltree_insert(&lastnd->node, &notdefines, notdefines_compare);
728         if (b != NULL) {
729             tmp2 = avltree_container_of(b, struct notdefines_s, node);
730             if (tmp2->pass == pass) {
731                 return;
732             }
733             tmp2->pass = pass;
734         } else {
735             if (lastnd->cfname.data == name->data) str_cpy(&lastnd->cfname, name);
736             else str_cfcpy(&lastnd->cfname, NULL);
737             lastnd = NULL;
738         }
739     }
740 
741     more = new_error_msg_err(err);
742     adderror("not defined ");
743     err_msg_variable(err->u.notdef.symbol);
744     if (more) new_error_msg_err_more(err);
745 
746     if (l->file_list == NULL) {
747         struct linepos_s nopoint = {0, 0};
748         new_error_msg(SV_NOTE, err->file_list, &nopoint);
749         adderror("searched in the global scope");
750     } else {
751         new_error_msg(SV_NOTE, l->file_list, &l->epoint);
752         if (err->u.notdef.down) adderror("searched in this scope and in all it's parents");
753         else adderror("searched in this object only");
754     }
755 }
756 
err_msg_not_defined2(const str_t * name,Namespace * l,bool down,linepos_t epoint)757 void err_msg_not_defined2(const str_t *name, Namespace *l, bool down, linepos_t epoint) {
758     Error *err = new_error(ERROR___NOT_DEFINED, epoint);
759     err->u.notdef.down = down;
760     err->u.notdef.names = ref_namespace(l);
761     err->u.notdef.symbol = new_symbol(name, epoint);
762     err_msg_not_defined3(err);
763     val_destroy(Obj(err));
764 }
765 
err_msg_not_defined2a(ssize_t count,Namespace * l,bool down,linepos_t epoint)766 void err_msg_not_defined2a(ssize_t count, Namespace *l, bool down, linepos_t epoint) {
767     Error *err = new_error(ERROR___NOT_DEFINED, epoint);
768     err->u.notdef.down = down;
769     err->u.notdef.names = ref_namespace(l);
770     err->u.notdef.symbol = new_anonsymbol(count);
771     err_msg_not_defined3(err);
772     val_destroy(Obj(err));
773 }
774 
err_opcode(uint32_t cod)775 static void err_opcode(uint32_t cod) {
776     adderror(" addressing mode ");
777     if (cod != 0) {
778         char tmp[17];
779         memcpy(tmp, "for opcode 'xxx'", sizeof tmp);
780         tmp[12] = (char)(cod >> 16);
781         tmp[13] = (char)(cod >> 8);
782         tmp[14] = (char)cod;
783         adderror(tmp);
784     } else adderror("accepted");
785 }
786 
err_msg_no_addressing(atype_t addrtype,uint32_t cod)787 static void err_msg_no_addressing(atype_t addrtype, uint32_t cod) {
788     adderror("no");
789     if (addrtype == A_NONE) adderror(" implied");
790     for (; (addrtype & MAX_ADDRESS_MASK) != 0; addrtype <<= 4) {
791         const char *txt = "?";
792         switch ((Address_types)((addrtype & 0xf000) >> 12)) {
793         case A_NONE: continue;
794         case A_IMMEDIATE: txt = " immediate"; break;
795         case A_IMMEDIATE_SIGNED: txt = " signed immediate"; break;
796         case A_XR: txt = " x indexed"; break;
797         case A_YR: txt = " y indexed"; break;
798         case A_ZR: txt = " z indexed"; break;
799         case A_SR: txt = " stack"; break;
800         case A_RR: txt = " data stack"; break;
801         case A_DR: txt = " direct page"; break;
802         case A_BR: txt = " data bank"; break;
803         case A_KR: txt = " program bank"; break;
804         case A_I: txt = " indirect"; break;
805         case A_LI: txt = " long indirect"; break;
806         }
807         adderror(txt);
808     }
809     err_opcode(cod);
810 }
811 
err_msg_no_register(const Error * err)812 static bool err_msg_no_register(const Error *err) {
813     bool more = new_error_msg_err(err);
814     Register *val = err->u.reg.reg;
815     adderror("no register '");
816     adderror2(val->data, val->len);
817     adderror("'");
818     err_opcode(err->u.reg.cod);
819     return more;
820 }
821 
err_msg_no_lot_operand(const Error * err)822 static bool err_msg_no_lot_operand(const Error *err) {
823     char msg2[256];
824     bool more = new_error_msg_err(err);
825     sprintf(msg2, "no %" PRIuSIZE " operand", err->u.opers.num);
826     adderror(msg2);
827     err_opcode(err->u.opers.cod);
828     return more;
829 }
830 
err_msg_cant_broadcast(const Error * err)831 static bool err_msg_cant_broadcast(const Error *err) {
832     char msg2[256];
833     bool more = new_error_msg_err(err);
834     sprintf(msg2, terr_error[err->num - 0x40], err->u.broadcast.v1, err->u.broadcast.v2);
835     adderror(msg2);
836     return more;
837 }
838 
err_msg_invalid_oper2(Oper_types op,Obj * v1,Obj * v2)839 static void err_msg_invalid_oper2(Oper_types op, Obj *v1, Obj *v2) {
840     adderror(operators[op].name);
841     adderror("' of ");
842     err_msg_variable(v1);
843     if (v2 != NULL) {
844         adderror(" and ");
845         err_msg_variable(v2);
846     }
847     adderror(" not possible");
848 }
849 
err_msg_invalid_oper3(const Error * err)850 static void err_msg_invalid_oper3(const Error *err) {
851     Obj *v1 = err->u.invoper.v1, *v2;
852     bool more;
853     if (v1->obj == ERROR_OBJ) {
854         err_msg_output((const Error *)v1);
855         return;
856     }
857     v2 = err->u.invoper.v2;
858     if (v2 != NULL && v2->obj == ERROR_OBJ) {
859         err_msg_output((const Error *)v2);
860         return;
861     }
862 
863     more = new_error_msg_err(err);
864     err_msg_invalid_oper2(err->u.invoper.op, v1, v2);
865     if (more) new_error_msg_err_more(err);
866 }
867 
err_msg_still_none2(const Error * err)868 static bool err_msg_still_none2(const Error *err) {
869     struct errorentry_s *e;
870     bool more;
871     if ((constcreated || !fixeddig) && pass < max_pass) return false;
872     more = new_error_msg_err(err);
873     e = (struct errorentry_s *)&error_list.data[error_list.header_pos];
874     e->severity = SV_NONEERROR;
875     adderror("can't calculate this");
876     return more;
877 }
878 
err_msg_argnum2(argcount_t num,argcount_t min,argcount_t max)879 static void err_msg_argnum2(argcount_t num, argcount_t min, argcount_t max) {
880     argcount_t n;
881     char line[1024];
882     adderror("expected ");
883     n = min;
884     if (min == max) { if (min != 0) adderror("exactly "); }
885     else if (num < min) adderror("at least ");
886     else {n = max; adderror("at most "); }
887     switch (n) {
888     case 0: adderror("no arguments"); break;
889     case 1: adderror("one argument"); break;
890     default: sprintf(line, "%" PRIuargcount " arguments", n); adderror(line); break;
891     }
892     if (num != 0) {
893         sprintf(line, ", got %" PRIuargcount, num);
894         adderror(line);
895     }
896 }
897 
err_msg_output(const Error * val)898 void err_msg_output(const Error *val) {
899     bool more = false;
900     switch (val->num) {
901     case ERROR___NOT_DEFINED: err_msg_not_defined3(val);break;
902     case ERROR__INVALID_CONV: more = err_msg_invalid_conv(val);break;
903     case ERROR__INVALID_OPER: err_msg_invalid_oper3(val);break;
904     case ERROR____STILL_NONE: more = err_msg_still_none2(val); break;
905     case ERROR_____CANT_IVAL:
906     case ERROR_____CANT_UVAL:
907     case ERROR______NOT_UVAL: more = err_msg_big_integer(val); break;
908     case ERROR_REQUIREMENTS_:
909     case ERROR______CONFLICT:
910     case ERROR_NOT_TWO_CHARS:
911     case ERROR_NUMERIC_OVERF:
912     case ERROR_NEGFRAC_POWER:
913     case ERROR___EMPTY_RANGE:
914     case ERROR__EMPTY_STRING:
915     case ERROR____EMPTY_LIST:
916     case ERROR__BYTES_NEEDED:
917     case ERROR___NO_LAST_GAP:
918     case ERROR__NOT_ONE_CHAR:
919     case ERROR_NO_ZERO_VALUE:
920     case ERROR_OUT_OF_MEMORY:
921     case ERROR__ADDR_COMPLEX:
922     case ERROR_NEGATIVE_SIZE: more = new_error_msg_err(val); adderror(terr_error[val->num - 0x40]); break;
923     case ERROR_NO_ADDRESSING: more = new_error_msg_err(val); err_msg_no_addressing(val->u.addressing.am, val->u.addressing.cod);break;
924     case ERROR___NO_REGISTER: more = err_msg_no_register(val);break;
925     case ERROR___NO_LOT_OPER: more = err_msg_no_lot_operand(val);break;
926     case ERROR_CANT_BROADCAS: more = err_msg_cant_broadcast(val);break;
927     case ERROR__NO_BYTE_ADDR:
928     case ERROR__NO_WORD_ADDR:
929     case ERROR__NO_LONG_ADDR: more = new_error_msg_err(val); adderror(terr_error[val->num - 0x40]); err_opcode(val->u.addresssize.cod); break;
930     case ERROR_DIVISION_BY_Z:
931     case ERROR_ZERO_NEGPOWER:
932     case ERROR__NOT_KEYVALUE:
933     case ERROR__NOT_HASHABLE:
934     case ERROR_____CANT_SIGN:
935     case ERROR______CANT_ABS:
936     case ERROR______CANT_INT:
937     case ERROR______CANT_LEN:
938     case ERROR_____CANT_SIZE:
939     case ERROR_____CANT_BOOL:
940     case ERROR______NOT_ITER:
941     case ERROR___MATH_DOMAIN:
942     case ERROR_LOG_NON_POSIT:
943     case ERROR_SQUARE_ROOT_N:
944     case ERROR___INDEX_RANGE:
945     case ERROR_____KEY_ERROR: more = new_error_msg_err(val); adderror(terr_error[val->num - 0x40]); err_msg_variable(val->u.obj);break;
946     case ERROR__WRONG_ARGNUM: more = new_error_msg_err(val); err_msg_argnum2(val->u.argnum.num, val->u.argnum.min, val->u.argnum.max); break;
947     default: break;
948     }
949     if (more) new_error_msg_err_more(val);
950 }
951 
err_msg_output_and_destroy(Error * val)952 void err_msg_output_and_destroy(Error *val) {
953     err_msg_output(val);
954     val_destroy(Obj(val));
955 }
956 
err_msg_wrong_type(const Obj * val,Type * expected,linepos_t epoint)957 void err_msg_wrong_type(const Obj *val, Type *expected, linepos_t epoint) {
958     bool more = new_error_msg(SV_ERROR, current_file_list, epoint);
959     adderror("wrong type '");
960     adderror(val->obj->name);
961     if (expected != NULL) {
962         adderror("', expected '");
963         adderror(expected->name);
964     }
965     adderror("'");
966     if (more) new_error_msg_more();
967 }
968 
err_msg_wrong_type2(const Obj * val,Type * expected,linepos_t epoint)969 void err_msg_wrong_type2(const Obj *val, Type *expected, linepos_t epoint) {
970     if (val->obj == ADDRESS_OBJ) {
971         const Obj *val2 = Address(val)->val;
972         if (val2 == none_value || val2->obj == ERROR_OBJ) val = val2;
973     }
974     if (val->obj == ERROR_OBJ) err_msg_output(Error(val));
975     else if (val == none_value) err_msg_still_none(NULL, epoint);
976     else err_msg_wrong_type(val, expected, epoint);
977 }
978 
err_msg_cant_unpack(size_t expect,size_t got,linepos_t epoint)979 void err_msg_cant_unpack(size_t expect, size_t got, linepos_t epoint) {
980     char line[1024];
981     bool more = new_error_msg(SV_ERROR, current_file_list, epoint);
982     sprintf(line, "expected %" PRIuSIZE " values but got %" PRIuSIZE " to unpack", expect, got);
983     adderror(line);
984     if (more) new_error_msg_more();
985 }
986 
err_msg_cant_calculate(const str_t * name,linepos_t epoint)987 void err_msg_cant_calculate(const str_t *name, linepos_t epoint) {
988     err_msg_str_name("can't calculate stable value", name, epoint);
989 }
990 
err_msg_cant_calculate2(const str_t * name,const struct file_list_s * flist,linepos_t epoint)991 void err_msg_cant_calculate2(const str_t *name, const struct file_list_s *flist, linepos_t epoint) {
992     bool more = new_error_msg(SV_ERROR, flist, epoint);
993     adderror("can't calculate stable value");
994     str_name(name->data, name->len);
995     if (more) new_error_msg_more();
996 }
997 
err_msg_still_none(const str_t * name,linepos_t epoint)998 void err_msg_still_none(const str_t *name, linepos_t epoint) {
999     if ((constcreated || !fixeddig) && pass < max_pass) return;
1000     new_error_msg(SV_NONEERROR, current_file_list, epoint);
1001     adderror("can't calculate this");
1002     if (name != NULL) str_name(name->data, name->len);
1003 }
1004 
err_msg_not_defined(const str_t * name,linepos_t epoint)1005 void err_msg_not_defined(const str_t *name, linepos_t epoint) {
1006     err_msg_str_name("not defined", name, epoint);
1007 }
1008 
err_msg_unknown_formatchar(const Str * s,size_t offs,linepos_t epoint)1009 unsigned int err_msg_unknown_formatchar(const Str *s, size_t offs, linepos_t epoint) {
1010     struct linepos_s epoint2 = *epoint;
1011     unsigned int len;
1012     bool more;
1013     epoint2.pos = interstring_position(&epoint2, s->data, offs);
1014     len = offs < s->len ? utf8len(s->data[offs]) : 0;
1015     more = new_error_msg(SV_ERROR, current_file_list, &epoint2);
1016     if (len == 0) {
1017         adderror("format character expected");
1018     } else {
1019         adderror("unknown format character '");
1020         adderror2(s->data + offs, len);
1021         adderror("'");
1022     }
1023     if (more) new_error_msg_more();
1024     return len;
1025 }
1026 
err_msg_double_note(const struct file_list_s * cflist,linepos_t epoint,const str_t * labelname2)1027 static void err_msg_double_note(const struct file_list_s *cflist, linepos_t epoint, const str_t *labelname2) {
1028     new_error_msg(SV_NOTE, cflist, epoint);
1029     adderror("original definition of");
1030     str_name(labelname2->data, labelname2->len);
1031     adderror(" was here");
1032 }
1033 
err_msg_star_assign(linepos_t epoint)1034 void err_msg_star_assign(linepos_t epoint) {
1035     new_error_msg2(diagnostic_errors.star_assign, epoint);
1036     adderror("label defined instead of variable multiplication for compatibility [-Wstar-assign]");
1037 }
1038 
err_msg_compound_note(linepos_t epoint)1039 void err_msg_compound_note(linepos_t epoint) {
1040     static unsigned once;
1041     if (once != pass) {
1042         new_error_msg(SV_NOTE, current_file_list, epoint);
1043         adderror("for reserving space use '.fill x' or '.byte ?' [-Wpitfalls]");
1044         once = pass;
1045     }
1046 }
1047 
err_msg_byte_note(linepos_t epoint)1048 void err_msg_byte_note(linepos_t epoint) {
1049     static unsigned int once;
1050     if (once != pass) {
1051         new_error_msg(SV_NOTE, current_file_list, epoint);
1052         adderror("for long strings mixed with bytes please use the '.text' directive [-Wpitfalls]");
1053         once = pass;
1054     }
1055 }
1056 
err_msg_char_note(const char * directive,linepos_t epoint)1057 void err_msg_char_note(const char *directive, linepos_t epoint) {
1058     new_error_msg(SV_NOTE, current_file_list, epoint);
1059     adderror("for signed values '");
1060     adderror(directive);
1061     adderror("' is a better fit [-Wpitfalls]");
1062 }
1063 
err_msg_immediate_note(linepos_t epoint)1064 void err_msg_immediate_note(linepos_t epoint) {
1065     new_error_msg(SV_NOTE, current_file_list, epoint);
1066     adderror("to accept signed values use the '#+' operator [-Wpitfalls]");
1067 }
1068 
err_msg_symbol_case(const str_t * labelname1,const Label * l,linepos_t epoint)1069 void err_msg_symbol_case(const str_t *labelname1, const Label *l, linepos_t epoint) {
1070     new_error_msg2(diagnostic_errors.case_symbol, epoint);
1071     adderror("symbol case mismatch");
1072     str_name(labelname1->data, labelname1->len);
1073     adderror(" [-Wcase-symbol]");
1074     if (l != NULL) err_msg_double_note(l->file_list, &l->epoint, &l->name);
1075 }
1076 
err_msg_symbol_case2(const Symbol * l1,const Symbol * l2)1077 void err_msg_symbol_case2(const Symbol *l1, const Symbol *l2) {
1078     Severity_types severity = diagnostic_errors.case_symbol ? SV_ERROR : SV_WARNING;
1079     bool more = new_error_msg(severity, l1->file_list, &l1->epoint);
1080     adderror("symbol case mismatch");
1081     str_name(l1->name.data, l1->name.len);
1082     adderror(" [-Wcase-symbol]");
1083     if (more) new_error_msg_more();
1084     err_msg_double_note(l2->file_list, &l2->epoint, &l2->name);
1085 }
1086 
err_msg_macro_prefix(linepos_t epoint)1087 void err_msg_macro_prefix(linepos_t epoint) {
1088     new_error_msg2(diagnostic_errors.macro_prefix, epoint);
1089     adderror("macro call without prefix [-Wmacro-prefix]");
1090 }
1091 
1092 static const char * const opr_names[ADR_LEN] = {
1093     "", /* ADR_REG */
1094     "", /* ADR_IMPLIED */
1095     "", /* ADR_IMMEDIATE */
1096     "long", /* ADR_LONG */
1097     "data bank", /* ADR_ADDR */
1098     "direct page", /* ADR_ZP */
1099     "long x indexed", /* ADR_LONG_X */
1100     "data bank x indexed", /* ADR_ADDR_X */
1101     "direct page x indexed", /* ADR_ZP_X */
1102     "", /* ADR_ADDR_X_I */
1103     "", /* ADR_ZP_X_I */
1104     "", /* ADR_ZP_S */
1105     "long y indexed", /* ADR_ZP_S_I_Y */
1106     "data bank y indexed", /* ADR_ADDR_Y */
1107     "direct page y indexed", /* ADR_ZP_Y */
1108     "", /* ADR_ZP_LI_Y */
1109     "", /* ADR_ZP_I_Y */
1110     "", /* ADR_ADDR_LI */
1111     "", /* ADR_ZP_LI */
1112     "", /* ADR_ADDR_I */
1113     "", /* ADR_ZP_I */
1114     "", /* ADR_REL_L */
1115     "", /* ADR_REL */
1116     "", /* ADR_MOVE */
1117     "", /* ADR_ZP_R */
1118     "", /* ADR_ZP_R_I_Y */
1119     "", /* ADR_BIT_ZP */
1120     "", /* ADR_BIT_ZP_REL */
1121 };
1122 
err_msg_address_mismatch(unsigned int a,unsigned int b,linepos_t epoint)1123 void err_msg_address_mismatch(unsigned int a, unsigned int b, linepos_t epoint) {
1124     new_error_msg2(diagnostic_errors.altmode, epoint);
1125     adderror("using ");
1126     adderror(opr_names[a]);
1127     adderror(" addressing instead of ");
1128     adderror(opr_names[b]);
1129     adderror(" [-Waltmode]");
1130 }
1131 
err_msg_double_defined2(const char * msg,Severity_types severity,const struct file_list_s * cflist,const str_t * labelname2,linepos_t epoint2)1132 static void err_msg_double_defined2(const char *msg, Severity_types severity, const struct file_list_s *cflist, const str_t *labelname2, linepos_t epoint2) {
1133     bool more = new_error_msg(severity, cflist, epoint2);
1134     adderror(msg);
1135     str_name(labelname2->data, labelname2->len);
1136     if (more) new_error_msg_more();
1137 }
1138 
err_msg_not_variable(Label * l,const str_t * labelname2,linepos_t epoint2)1139 void err_msg_not_variable(Label *l, const str_t *labelname2, linepos_t epoint2) {
1140     err_msg_double_defined2("not a variable", SV_ERROR, current_file_list, labelname2, epoint2);
1141     err_msg_double_note(l->file_list, &l->epoint, labelname2);
1142 }
1143 
err_msg_double_defined(Label * l,const str_t * labelname2,linepos_t epoint2)1144 void err_msg_double_defined(Label *l, const str_t *labelname2, linepos_t epoint2) {
1145     err_msg_double_defined2("duplicate definition", SV_ERROR, current_file_list, labelname2, epoint2);
1146     err_msg_double_note(l->file_list, &l->epoint, labelname2);
1147 }
1148 
err_msg_double_definedo(const struct file_list_s * cflist,linepos_t epoint,const str_t * labelname2,linepos_t epoint2)1149 void err_msg_double_definedo(const struct file_list_s *cflist, linepos_t epoint, const str_t *labelname2, linepos_t epoint2) {
1150     err_msg_double_defined2("duplicate definition", SV_ERROR, current_file_list, labelname2, epoint2);
1151     err_msg_double_note(cflist, epoint, labelname2);
1152 }
1153 
err_msg_shadow_defined(Label * l,Label * l2)1154 void err_msg_shadow_defined(Label *l, Label *l2) {
1155     err_msg_double_defined2("shadow definition", diagnostic_errors.shadow ? SV_ERROR : SV_WARNING, l2->file_list, &l2->name, &l2->epoint);
1156     adderror(" [-Wshadow]");
1157     err_msg_double_note(l->file_list, &l->epoint, &l2->name);
1158 }
1159 
err_msg_shadow_defined2(Label * l)1160 void err_msg_shadow_defined2(Label *l) {
1161     err_msg_double_defined2("shadow definition of built-in", diagnostic_errors.shadow ? SV_ERROR : SV_WARNING, l->file_list, &l->name, &l->epoint);
1162     adderror(" [-Wshadow]");
1163 }
1164 
1165 static const char * const order_suffix[4] = {
1166     "st", "nd", "rd", "th"
1167 };
1168 
err_msg_missing_argument(linepos_t epoint,argcount_t n)1169 void err_msg_missing_argument(linepos_t epoint, argcount_t n) {
1170     char msg2[4];
1171     bool more = new_error_msg(SV_ERROR, &((const struct file_listnode_s *)current_file_list)->parent->flist, &current_file_list->epoint);
1172     msg2[0] = (char)(n + '1');
1173     memcpy(msg2 + 1, order_suffix[n < 4 ? n : 3], 3);
1174     adderror(msg2);
1175     adderror(" argument is missing");
1176     if (more) new_error_msg_more();
1177     new_error_msg(SV_NOTE, current_file_list, epoint);
1178     adderror("argument reference was here");
1179 }
1180 
err_msg_unknown_argument(const str_t * labelname,linepos_t epoint)1181 void err_msg_unknown_argument(const str_t *labelname, linepos_t epoint) {
1182     bool more = new_error_msg(SV_ERROR, current_file_list, epoint);
1183     adderror("unknown argument name");
1184     str_name(labelname->data, labelname->len);
1185     if (more) new_error_msg_more();
1186 }
1187 
err_msg_unused(const char * msg,bool error,Label * l)1188 static void err_msg_unused(const char *msg, bool error, Label *l) {
1189     Severity_types severity = error ? SV_ERROR : SV_WARNING;
1190     bool more = new_error_msg(severity, l->file_list, &l->epoint);
1191     adderror(msg);
1192     str_name(l->name.data, l->name.len);
1193     if (more) new_error_msg_more();
1194 }
1195 
err_msg_unused_macro(Label * l)1196 void err_msg_unused_macro(Label *l) {
1197     err_msg_unused("unused macro", diagnostic_errors.unused.macro, l);
1198     adderror(" [-Wunused-macro]");
1199 }
1200 
err_msg_unused_label(Label * l)1201 void err_msg_unused_label(Label *l) {
1202     err_msg_unused("unused label", diagnostic_errors.unused.label, l);
1203     adderror(" [-Wunused-label]");
1204 }
1205 
err_msg_unused_const(Label * l)1206 void err_msg_unused_const(Label *l) {
1207     err_msg_unused("unused const", diagnostic_errors.unused.consts, l);
1208     adderror(" [-Wunused-const]");
1209 }
1210 
err_msg_unused_variable(Label * l)1211 void err_msg_unused_variable(Label *l) {
1212     err_msg_unused("unused variable", diagnostic_errors.unused.variable, l);
1213     adderror(" [-Wunused-variable]");
1214 }
1215 
err_msg_argnum(argcount_t num,argcount_t min,argcount_t max,linepos_t epoint)1216 void err_msg_argnum(argcount_t num, argcount_t min, argcount_t max, linepos_t epoint) {
1217     bool more = new_error_msg(SV_ERROR, current_file_list, epoint);
1218     err_msg_argnum2(num, min, max);
1219     if (more) new_error_msg_more();
1220 }
1221 
err_msg_bool(Error_types no,Obj * o,linepos_t epoint)1222 void err_msg_bool(Error_types no, Obj *o, linepos_t epoint) {
1223     new_error_msg2(diagnostic_errors.strict_bool, epoint);
1224     adderror(terr_error[no - 0x40]);
1225     err_msg_variable(o);
1226     adderror(" [-Wstrict-bool]");
1227 }
1228 
err_msg_bool_oper(oper_t op)1229 void err_msg_bool_oper(oper_t op) {
1230     Obj *v2;
1231     new_error_msg2(diagnostic_errors.strict_bool, op->epoint3);
1232     switch (op->op) {
1233     case O_WORD:
1234     case O_HWORD:
1235     case O_BSWORD:
1236     case O_LOWER:
1237     case O_HIGHER:
1238     case O_BANK:
1239     case O_STRING:
1240     case O_INV:
1241     case O_NEG:
1242     case O_POS:
1243     case O_LNOT:
1244     case O_X:
1245     case O_FUNC:
1246     case O_INDEX: v2 = NULL; break;
1247     default: v2 = op->v2; break;
1248     }
1249     err_msg_invalid_oper2(op->op, op->v1, v2);
1250     adderror(" [-Wstrict-bool]");
1251 }
1252 
err_msg_implied_reg(linepos_t epoint,uint32_t cod)1253 void err_msg_implied_reg(linepos_t epoint, uint32_t cod) {
1254     Severity_types severity = diagnostic_errors.implied_reg ? SV_ERROR : SV_WARNING;
1255     bool more = new_error_msg(severity, current_file_list, epoint);
1256     err_msg_no_addressing(A_NONE, cod);
1257     adderror(" [-Wimplied-reg]");
1258     if (more) new_error_msg_more();
1259 }
1260 
err_msg_size_larger(linepos_t epoint)1261 void err_msg_size_larger(linepos_t epoint) {
1262     new_error_msg2(diagnostic_errors.size_larger, epoint);
1263     adderror("larger than original due to negative offset [-Wsize-larger]");
1264 }
1265 
err_msg_jmp_bug(linepos_t epoint)1266 void err_msg_jmp_bug(linepos_t epoint) {
1267     new_error_msg2(diagnostic_errors.jmp_bug, epoint);
1268     adderror("possible jmp ($xxff) bug [-Wjmp-bug]");
1269 }
1270 
err_msg_pc_bank(linepos_t epoint)1271 void err_msg_pc_bank(linepos_t epoint) {
1272     if (!diagnostics.wrap.pc) return;
1273     new_error_msg2(diagnostic_errors.wrap.pc, epoint);
1274     adderror("processor program counter crossed bank [-Wwrap-pc]");
1275 }
1276 
err_msg_mem_wrap(linepos_t epoint)1277 void err_msg_mem_wrap(linepos_t epoint) {
1278     if (!diagnostics.wrap.mem) return;
1279     new_error_msg2(diagnostic_errors.wrap.mem, epoint);
1280     adderror("compile offset overflow [-Wwrap-mem]");
1281 }
1282 
err_msg_addr_wrap(linepos_t epoint)1283 void err_msg_addr_wrap(linepos_t epoint) {
1284     if (!diagnostics.wrap.addr) return;
1285     new_error_msg2(diagnostic_errors.wrap.addr, epoint);
1286     adderror("memory location address overflow [-Wwrap-addr]");
1287 }
1288 
err_msg_dpage_wrap(linepos_t epoint)1289 void err_msg_dpage_wrap(linepos_t epoint) {
1290     if (!diagnostics.wrap.dpage) return;
1291     new_error_msg2(diagnostic_errors.wrap.dpage, epoint);
1292     adderror("direct page address overflow [-Wwrap-dpage]");
1293 }
1294 
err_msg_bank0_wrap(linepos_t epoint)1295 void err_msg_bank0_wrap(linepos_t epoint) {
1296     if (!diagnostics.wrap.bank0) return;
1297     new_error_msg2(diagnostic_errors.wrap.bank0, epoint);
1298     adderror("bank 0 address overflow [-Wwrap-bank0]");
1299 }
1300 
err_msg_pbank_wrap(linepos_t epoint)1301 void err_msg_pbank_wrap(linepos_t epoint) {
1302     if (!diagnostics.wrap.pbank) return;
1303     new_error_msg2(diagnostic_errors.wrap.pbank, epoint);
1304     adderror("program bank address overflow [-Wwrap-pbank]");
1305 }
1306 
err_msg_label_left(linepos_t epoint)1307 void err_msg_label_left(linepos_t epoint) {
1308     new_error_msg2(diagnostic_errors.label_left, epoint);
1309     adderror("label not on left side [-Wlabel-left]");
1310 }
1311 
err_msg_branch_page(int by,linepos_t epoint)1312 void err_msg_branch_page(int by, linepos_t epoint) {
1313     char msg2[256];
1314     new_error_msg2(diagnostic_errors.branch_page, epoint);
1315     sprintf(msg2, "branch crosses page by %+d bytes [-Wbranch-page]", by);
1316     adderror(msg2);
1317 }
1318 
err_msg_page(address_t adr,address_t adr2,linepos_t epoint)1319 void err_msg_page(address_t adr, address_t adr2, linepos_t epoint) {
1320     char line[256];
1321     new_error_msg2(diagnostic_errors.page, epoint);
1322     sprintf(line,"different start and end page $%04" PRIaddress " and $%04" PRIaddress " [-Wpage]", adr, adr2);
1323     adderror(line);
1324 }
1325 
err_msg_alias(uint32_t a,uint32_t b,linepos_t epoint)1326 void err_msg_alias(uint32_t a, uint32_t b, linepos_t epoint) {
1327     char name[4];
1328     new_error_msg2(diagnostic_errors.alias, epoint);
1329     adderror("instruction '");
1330     name[0] = (char)(a >> 16);
1331     name[1] = (char)(a >> 8);
1332     name[2] = (char)a;
1333     name[3] = '\0';
1334     adderror(name);
1335     adderror("' is alias of '");
1336     name[0] = (char)(b >> 16);
1337     name[1] = (char)(b >> 8);
1338     name[2] = (char)b;
1339     adderror(name);
1340     adderror("' [-Walias]");
1341 }
1342 
err_msg_unknown_char(uchar_t ch,const str_t * name,linepos_t epoint)1343 void err_msg_unknown_char(uchar_t ch, const str_t *name, linepos_t epoint) {
1344     uint8_t line[256], *s = line;
1345     bool more = new_error_msg(SV_ERROR, current_file_list, epoint);
1346     adderror("can't encode character '");
1347     if (ch != 0 && ch < 0x80) *s++ = (uint8_t)ch; else s += utf8out(ch, s);
1348     sprintf((char *)s, "' ($%02" PRIx32 ") in encoding '", ch); adderror((char *)line);
1349     adderror2(name->data, name->len);
1350     adderror("'");
1351     if (more) new_error_msg_more();
1352 }
1353 
printline(const struct file_list_s * cfile,linepos_t epoint,const uint8_t * line,FILE * f)1354 static const uint8_t *printline(const struct file_list_s *cfile, linepos_t epoint, const uint8_t *line, FILE *f) {
1355     const struct file_s *file;
1356     if (epoint->line == 0) return NULL;
1357     file = cfile->file;
1358     if (line == NULL) line = &file->data[file->line[epoint->line - 1]];
1359     fprintf(f, ":%" PRIuline ":%" PRIlinepos, epoint->line, ((file->encoding == E_UTF8) ? (linecpos_t)calcpos(line, epoint->pos) : epoint->pos) + 1);
1360     return line;
1361 }
1362 
print_error(FILE * f,const struct errorentry_s * err,bool caret)1363 static void print_error(FILE *f, const struct errorentry_s *err, bool caret) {
1364     const struct file_list_s *cflist = err->file_list;
1365     linepos_t epoint = &err->epoint;
1366     const uint8_t *line = NULL;
1367     bool bold;
1368 
1369     if (cflist != &file_list.flist) {
1370         if (cflist != &included_from->flist) {
1371             included_from = (const struct file_listnode_s *)cflist;
1372             while (included_from->parent != &file_list) {
1373                 if (included_from->flist.file->entercount != 1) break;
1374                 included_from = included_from->parent;
1375             }
1376             if (included_from->parent != &file_list) included_from = (const struct file_listnode_s *)cflist;
1377             while (included_from->parent != &file_list) {
1378                 fputs((&included_from->flist == cflist) ? "In file included from " : "                      ", f);
1379                 if (console_use_color) console_bold(f);
1380                 printable_print((const uint8_t *)included_from->parent->flist.file->realname, f);
1381                 printline(&included_from->parent->flist, &included_from->flist.epoint, NULL, f);
1382                 included_from = included_from->parent;
1383                 if (console_use_color) console_default(f);
1384                 fputs((included_from->parent != &file_list) ? ",\n" : ":\n", f);
1385             }
1386             included_from = (const struct file_listnode_s *)cflist;
1387         }
1388         if (console_use_color) console_bold(f);
1389         printable_print((const uint8_t *)cflist->file->realname, f);
1390         line = printline(cflist, epoint, (err->line_len != 0) ? (const uint8_t *)(err + 1) : NULL, f);
1391     } else {
1392         if (console_use_color) console_bold(f);
1393         printable_print((const uint8_t *)prgname, f);
1394     }
1395     fputs(": ", f);
1396     switch (err->severity) {
1397     case SV_NOTE: if (console_use_color) console_cyan(f); fputs("note: ", f); bold = false; break;
1398     case SV_WARNING: if (console_use_color) console_purple(f); fputs("warning: ", f); bold = true; break;
1399     case SV_NONEERROR:
1400     case SV_ERROR: if (console_use_color) console_red(f); fputs("error: ", f); bold = true; break;
1401     case SV_FATAL: if (console_use_color) console_red(f); fputs("fatal error: ", f); bold = true; break;
1402     default: bold = false;
1403     }
1404     if (console_use_color) {
1405         if (bold) {
1406             console_defaultbold(f);
1407 #ifdef COLOR_OUTPUT
1408             console_use_bold = true;
1409 #endif
1410         } else console_default(f);
1411     }
1412     printable_print2(((const uint8_t *)(err + 1)) + err->line_len, f, err->error_len);
1413 #ifdef COLOR_OUTPUT
1414     if (console_use_bold) {
1415         console_default(f);
1416         console_use_bold = false;
1417     }
1418 #endif
1419     putc('\n', f);
1420     if (caret && line != NULL) {
1421         putc(' ', f);
1422         printable_print(line, f);
1423         fputs("\n ", f);
1424         caret_print(line, f, err->caret);
1425         if (console_use_color) console_boldgreen(f);
1426         putc('^', f);
1427         if (console_use_color) console_default(f);
1428         putc('\n', f);
1429     }
1430 }
1431 
caret_needed(const struct errorentry_s * err)1432 static inline bool caret_needed(const struct errorentry_s *err) {
1433     return (arguments.error.caret == CARET_ALWAYS || (arguments.error.caret != CARET_NEVER && (err->line_len != 0 || err->file_list->file->name[0] == 0)));
1434 }
1435 
different_line(const struct errorentry_s * err,const struct errorentry_s * err2)1436 static bool different_line(const struct errorentry_s *err, const struct errorentry_s *err2) {
1437     if (!caret_needed(err2)) return false;
1438     if (err->file_list->file != err2->file_list->file || err->line_len != err2->line_len ||
1439             err->epoint.line != err2->epoint.line || err->epoint.pos != err2->epoint.pos) return true;
1440     if (err->line_len == 0) return false;
1441     return memcmp(err + 1, err2 + 1, err->line_len) != 0;
1442 }
1443 
walkfilelist(struct avltree_node * aa)1444 static void walkfilelist(struct avltree_node *aa) {
1445     struct file_listnode_s *l = avltree_container_of(aa, struct file_listnode_s, node);
1446     if (l->flist.file->entercount > 1 || l->pass != pass) return;
1447     l->flist.file->entercount++;
1448     avltree_destroy(&l->members, walkfilelist);
1449 }
1450 
error_print(const struct error_output_s * output)1451 void error_print(const struct error_output_s *output) {
1452     const struct errorentry_s *err, *err2, *err3;
1453     size_t pos, end;
1454     bool noneerr = false, anyerr = false, usenote;
1455     FILE *ferr;
1456     struct linepos_s nopoint = {0, 0};
1457 
1458     if (error_list.header_pos != 0) {
1459         avltree_destroy(&file_list.members, walkfilelist);
1460     }
1461 
1462     if (output->name != NULL) {
1463         ferr = dash_name(output->name) ? stdout : file_open(output->name, output->append ? "at" : "wt");
1464         if (ferr == NULL) {
1465             err_msg_file(ERROR_CANT_WRTE_ERR, output->name, &nopoint);
1466             ferr = stderr;
1467         }
1468     } else ferr = output->no_output ? NULL : stderr;
1469 
1470     if (ferr != NULL) {
1471         if (ferr != stderr) console_use(ferr); else if (arguments.quiet) fflush(stdout);
1472     }
1473 
1474     warnings = errors = 0;
1475     close_error();
1476 
1477     end = (error_list.header_stop != SIZE_MAX) ? error_list.header_stop : error_list.header_pos;
1478     for (pos = 0; pos < end; pos = ALIGN(pos + (sizeof *err) + err->line_len + err->error_len)) {
1479         err = (const struct errorentry_s *)&error_list.data[pos];
1480         switch (err->severity) {
1481         case SV_NONEERROR: anyerr = true; break;
1482         case SV_NOTE:
1483         case SV_WARNING:
1484             break;
1485         default: noneerr = true; anyerr = true; break;
1486         }
1487     }
1488 
1489     err2 = err3 = NULL;
1490     usenote = false;
1491     for (pos = 0; pos < end; pos = ALIGN(pos + (sizeof *err) + err->line_len + err->error_len)) {
1492         err = (const struct errorentry_s *)&error_list.data[pos];
1493         switch (err->severity) {
1494         case SV_NOTE:
1495             if (!usenote) continue;
1496             if (err3 != NULL && ferr != NULL) {
1497                 if (err->severity != err3->severity || err->file_list != err3->file_list ||
1498                         err->line_len != err3->line_len || err->error_len != err3->error_len ||
1499                         err->epoint.line != err3->epoint.line || err->epoint.pos != err3->epoint.pos ||
1500                         memcmp(err + 1, err3 + 1, err->line_len + err->error_len) != 0) {
1501                     print_error(ferr, err3, different_line(err, err3));
1502                 }
1503             }
1504             err3 = err2;
1505             err2 = err;
1506             continue;
1507         case SV_WARNING:
1508             if (!output->warning) {
1509                 usenote = false;
1510                 continue;
1511             }
1512             warnings++;
1513             if (anyerr) {
1514                 usenote = false;
1515                 continue;
1516             }
1517             break;
1518         case SV_NONEERROR:
1519             if (noneerr) {
1520                 usenote = false;
1521                 continue;
1522             }
1523             /* fall through */
1524         default:
1525             errors++;
1526             break;
1527         }
1528         if (err3 != NULL && ferr != NULL) print_error(ferr, err3, different_line(err2, err3));
1529         err3 = err2;
1530         err2 = err;
1531         usenote = true;
1532     }
1533     if (ferr == NULL) return;
1534     if (err3 != NULL) print_error(ferr, err3, different_line(err2, err3));
1535     if (err2 != NULL) print_error(ferr, err2, caret_needed(err2));
1536     if (ferr != stderr) console_use(stderr);
1537     if (ferr != stderr && ferr != stdout) fclose(ferr); else fflush(ferr);
1538 }
1539 
error_reset(void)1540 void error_reset(void) {
1541     error_list.len = error_list.header_pos = 0;
1542     error_list.header_stop = SIZE_MAX;
1543     avltree_init(&error_list.members);
1544     current_file_list = &file_list.flist;
1545     included_from = &file_list;
1546 }
1547 
err_init(const char * name)1548 void err_init(const char *name) {
1549     static struct file_s file_list_file;
1550     prgname = name;
1551     setvbuf(stderr, NULL, _IOLBF, 1024);
1552     console_use(stderr);
1553     file_lists = (struct file_lists_s *)mallocx(sizeof *file_lists);
1554     file_lists->next = NULL;
1555     file_listsp = 0;
1556     lastfl = &file_lists->file_lists[file_listsp];
1557     file_list_file.name = "";
1558     file_list_file.realname = file_list_file.name;
1559     file_list_file.data = (uint8_t *)0;
1560     file_list_file.len = ~(filesize_t)0;
1561     file_list.flist.file = &file_list_file;
1562     avltree_init(&file_list.members);
1563     error_list.len = error_list.max = error_list.header_pos = 0;
1564     error_list.data = NULL;
1565     avltree_init(&error_list.members);
1566     current_file_list = &file_list.flist;
1567     dummy_file_list = &file_list.flist;
1568     included_from = &file_list;
1569     avltree_init(&notdefines);
1570 }
1571 
err_destroy(void)1572 void err_destroy(void) {
1573     while (file_lists != NULL) {
1574         struct file_lists_s *old = file_lists;
1575         file_lists = file_lists->next;
1576         free(old);
1577     }
1578     free(error_list.data);
1579     avltree_destroy(&notdefines, notdefines_free);
1580     free(lastnd);
1581 }
1582 
fatal_error(const char * txt)1583 void fatal_error(const char *txt) {
1584     if (txt != NULL) {
1585         if (console_use_color) console_bold(stderr);
1586         printable_print((const uint8_t *)((prgname != NULL) ? prgname : "64tass"), stderr);
1587         fputs(": ", stderr);
1588         if (console_use_color) console_red(stderr);
1589         fputs("fatal error: ", stderr);
1590         if (console_use_color) {
1591             console_default(stderr);
1592             console_bold(stderr);
1593         }
1594         fputs(txt, stderr);
1595         return;
1596     }
1597     if (console_use_color) console_default(stderr);
1598     putc('\n', stderr);
1599 }
1600 
err_msg_out_of_memory2(void)1601 NO_RETURN void err_msg_out_of_memory2(void)
1602 {
1603     fatal_error("out of memory");
1604     fatal_error(NULL);
1605     exit(EXIT_FAILURE);
1606 }
1607 
err_msg_out_of_memory(void)1608 NO_RETURN void err_msg_out_of_memory(void)
1609 {
1610     error_print(&arguments.error);
1611     err_msg_out_of_memory2();
1612 }
1613 
err_msg_signal(void)1614 void err_msg_signal(void)
1615 {
1616     if (error_list.header_stop == SIZE_MAX) {
1617         bool more = new_error_msg(SV_FATAL, current_file_list, &lpoint);
1618         adderror("compilation was interrupted");
1619         if (more) new_error_msg_more();
1620         error_list.header_stop = error_list.header_pos + 1;
1621     }
1622 }
1623 
err_msg_file(Error_types no,const char * prm,linepos_t epoint)1624 void err_msg_file(Error_types no, const char *prm, linepos_t epoint) {
1625     mbstate_t ps;
1626     const char *s;
1627     wchar_t w;
1628     uint8_t s2[10];
1629     size_t n, i = 0;
1630     ssize_t l;
1631     bool more;
1632 
1633     s = strerror(errno);
1634     n = strlen(s);
1635 
1636     more = new_error_msg(SV_FATAL, current_file_list, epoint);
1637     adderror(terr_fatal[no - 0xc0]);
1638     adderror(" '");
1639     adderror(prm);
1640     adderror("': ");
1641     memset(&ps, 0, sizeof ps);
1642     while (i < n) {
1643         if (s[i] != 0 && (s[i] & 0x80) == 0) {
1644             adderror2((const uint8_t *)s + i, 1);
1645             i++;
1646             continue;
1647         }
1648         l = (ssize_t)mbrtowc(&w, s + i, n - i,  &ps);
1649         if (l < 1) {
1650             w = (uint8_t)s[i];
1651             if (w == 0 || l == 0) break;
1652             l = 1;
1653         }
1654         s2[utf8out((uchar_t)w, s2)] = 0;
1655         adderror((char *)s2);
1656         i += (size_t)l;
1657     }
1658     if (more) new_error_msg_more();
1659 }
1660 
error_status_val(const char * head,unsigned int val)1661 static void error_status_val(const char *head, unsigned int val) {
1662     fputs(head, stdout);
1663     if (val != 0) printf("%u\n", val); else puts("None");
1664 }
1665 
error_status(void)1666 void error_status(void) {
1667     error_status_val("Error messages:    ", errors);
1668     error_status_val("Warning messages:  ", warnings);
1669 }
1670 
interstring_position(linepos_t epoint,const uint8_t * data,size_t i)1671 linecpos_t interstring_position(linepos_t epoint, const uint8_t *data, size_t i) {
1672     if (epoint->line == lpoint.line && strlen((const char *)pline) > epoint->pos) {
1673         uint8_t q = pline[epoint->pos];
1674         if (q == '"' || q == '\'') {
1675             linecpos_t pos = epoint->pos + 1;
1676             size_t pp = 0;
1677             while (pp < i && pline[pos] != 0) {
1678                 unsigned int ln2;
1679                 if (pline[pos] == q) {
1680                     if (pline[pos + 1] != q) break;
1681                     pos++;
1682                 }
1683                 ln2 = utf8len(pline[pos]);
1684                 if (memcmp(pline + pos, data + pp, ln2) != 0) break;
1685                 pos += ln2; pp += ln2;
1686             }
1687             if (pp == i) {
1688                 return pos;
1689             }
1690         }
1691     }
1692     return epoint->pos;
1693 }
1694 
error_serious(void)1695 bool error_serious(void) {
1696     const struct errorentry_s *err;
1697     size_t pos;
1698     close_error();
1699     for (pos = 0; pos < error_list.header_pos; pos = ALIGN(pos + (sizeof *err) + err->line_len + err->error_len)) {
1700         err = (const struct errorentry_s *)&error_list.data[pos];
1701         switch (err->severity) {
1702         case SV_NOTE:
1703         case SV_WARNING: break;
1704         default: return true;
1705         }
1706     }
1707     return false;
1708 }
1709