demand_copy_C_string NUL check
[binutils-gdb.git] / sim / igen / table.c
1 /* The IGEN simulator generator for GDB, the GNU Debugger.
2
3 Copyright 2002-2021 Free Software Foundation, Inc.
4
5 Contributed by Andrew Cagney.
6
7 This file is part of GDB.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21
22
23
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <stdio.h>
27 #include <fcntl.h>
28 #include <ctype.h>
29
30 #include "config.h"
31 #include "misc.h"
32 #include "lf.h"
33 #include "table.h"
34
35 #ifdef HAVE_UNISTD_H
36 #include <unistd.h>
37 #endif
38 #include <stdlib.h>
39
40 typedef struct _open_table open_table;
41 struct _open_table
42 {
43 size_t size;
44 char *buffer;
45 char *pos;
46 line_ref pseudo_line;
47 line_ref real_line;
48 open_table *parent;
49 table *root;
50 };
51 struct _table
52 {
53 open_table *current;
54 };
55
56
57 static line_ref *
58 current_line (open_table * file)
59 {
60 line_ref *entry = ZALLOC (line_ref);
61 *entry = file->pseudo_line;
62 return entry;
63 }
64
65 static table_entry *
66 new_table_entry (open_table * file, table_entry_type type)
67 {
68 table_entry *entry;
69 entry = ZALLOC (table_entry);
70 entry->file = file->root;
71 entry->line = current_line (file);
72 entry->type = type;
73 return entry;
74 }
75
76 static void
77 set_nr_table_entry_fields (table_entry *entry, int nr_fields)
78 {
79 entry->field = NZALLOC (char *, nr_fields + 1);
80 entry->nr_fields = nr_fields;
81 }
82
83
84 void
85 table_push (table *root,
86 line_ref *line, table_include *includes, const char *file_name)
87 {
88 FILE *ff;
89 open_table *file;
90 table_include dummy;
91 table_include *include = &dummy;
92
93 /* dummy up a search of this directory */
94 dummy.next = includes;
95 dummy.dir = "";
96
97 /* create a file descriptor */
98 file = ZALLOC (open_table);
99 if (file == NULL)
100 {
101 perror (file_name);
102 exit (1);
103 }
104 file->root = root;
105 file->parent = root->current;
106 root->current = file;
107
108 while (1)
109 {
110 /* save the file name */
111 char *dup_name =
112 NZALLOC (char, strlen (include->dir) + strlen (file_name) + 2);
113 if (dup_name == NULL)
114 {
115 perror (file_name);
116 exit (1);
117 }
118 if (include->dir[0] != '\0')
119 {
120 strcat (dup_name, include->dir);
121 strcat (dup_name, "/");
122 }
123 strcat (dup_name, file_name);
124 file->real_line.file_name = dup_name;
125 file->pseudo_line.file_name = dup_name;
126 /* open the file */
127
128 ff = fopen (dup_name, "rb");
129 if (ff)
130 break;
131 /* free (dup_name); */
132 if (include->next == NULL)
133 {
134 if (line != NULL)
135 error (line, "Problem opening file `%s'\n", file_name);
136 perror (file_name);
137 exit (1);
138 }
139 include = include->next;
140 }
141
142
143 /* determine the size */
144 fseek (ff, 0, SEEK_END);
145 file->size = ftell (ff);
146 fseek (ff, 0, SEEK_SET);
147
148 /* allocate this much memory */
149 file->buffer = (char *) zalloc (file->size + 1);
150 if (file->buffer == NULL)
151 {
152 perror (file_name);
153 exit (1);
154 }
155 file->pos = file->buffer;
156
157 /* read it all in */
158 if (fread (file->buffer, 1, file->size, ff) < file->size)
159 {
160 perror (file_name);
161 exit (1);
162 }
163 file->buffer[file->size] = '\0';
164
165 /* set the initial line numbering */
166 file->real_line.line_nr = 1; /* specifies current line */
167 file->pseudo_line.line_nr = 1; /* specifies current line */
168
169 /* done */
170 fclose (ff);
171 }
172
173 table *
174 table_open (const char *file_name)
175 {
176 table *root;
177
178 /* create a file descriptor */
179 root = ZALLOC (table);
180 if (root == NULL)
181 {
182 perror (file_name);
183 exit (1);
184 }
185
186 table_push (root, NULL, NULL, file_name);
187 return root;
188 }
189
190 char *
191 skip_spaces (char *chp)
192 {
193 while (1)
194 {
195 if (*chp == '\0' || *chp == '\n' || !isspace (*chp))
196 return chp;
197 chp++;
198 }
199 }
200
201
202 char *
203 back_spaces (char *start, char *chp)
204 {
205 while (1)
206 {
207 if (chp <= start || !isspace (chp[-1]))
208 return chp;
209 chp--;
210 }
211 }
212
213 char *
214 skip_digits (char *chp)
215 {
216 while (1)
217 {
218 if (*chp == '\0' || *chp == '\n' || !isdigit (*chp))
219 return chp;
220 chp++;
221 }
222 }
223
224 char *
225 skip_to_separator (char *chp, char *separators)
226 {
227 while (1)
228 {
229 char *sep = separators;
230 while (1)
231 {
232 if (*chp == *sep)
233 return chp;
234 if (*sep == '\0')
235 break;
236 sep++;
237 }
238 chp++;
239 }
240 }
241
242 static char *
243 skip_to_null (char *chp)
244 {
245 return skip_to_separator (chp, "");
246 }
247
248
249 static char *
250 skip_to_nl (char *chp)
251 {
252 return skip_to_separator (chp, "\n");
253 }
254
255
256 static void
257 next_line (open_table * file)
258 {
259 file->pos = skip_to_nl (file->pos);
260 if (*file->pos == '0')
261 error (&file->pseudo_line, "Missing <nl> at end of line\n");
262 *file->pos = '\0';
263 file->pos += 1;
264 file->real_line.line_nr += 1;
265 file->pseudo_line.line_nr += 1;
266 }
267
268
269 extern table_entry *
270 table_read (table *root)
271 {
272 open_table *file = root->current;
273 table_entry *entry = NULL;
274 while (1)
275 {
276
277 /* end-of-file? */
278 while (*file->pos == '\0')
279 {
280 if (file->parent != NULL)
281 {
282 file = file->parent;
283 root->current = file;
284 }
285 else
286 return NULL;
287 }
288
289 /* code_block? */
290 if (*file->pos == '{')
291 {
292 char *chp;
293 next_line (file); /* discard leading brace */
294 entry = new_table_entry (file, table_code_entry);
295 chp = file->pos;
296 /* determine how many lines are involved - look for <nl> "}" */
297 {
298 int nr_lines = 0;
299 while (*file->pos != '}')
300 {
301 next_line (file);
302 nr_lines++;
303 }
304 set_nr_table_entry_fields (entry, nr_lines);
305 }
306 /* now enter each line */
307 {
308 int line_nr;
309 for (line_nr = 0; line_nr < entry->nr_fields; line_nr++)
310 {
311 if (strncmp (chp, " ", 2) == 0)
312 entry->field[line_nr] = chp + 2;
313 else
314 entry->field[line_nr] = chp;
315 chp = skip_to_null (chp) + 1;
316 }
317 /* skip trailing brace */
318 ASSERT (*file->pos == '}');
319 next_line (file);
320 }
321 break;
322 }
323
324 /* tab block? */
325 if (*file->pos == '\t')
326 {
327 char *chp = file->pos;
328 entry = new_table_entry (file, table_code_entry);
329 /* determine how many lines are involved - look for <nl> !<tab> */
330 {
331 int nr_lines = 0;
332 int nr_blank_lines = 0;
333 while (1)
334 {
335 if (*file->pos == '\t')
336 {
337 nr_lines = nr_lines + nr_blank_lines + 1;
338 nr_blank_lines = 0;
339 next_line (file);
340 }
341 else
342 {
343 file->pos = skip_spaces (file->pos);
344 if (*file->pos != '\n')
345 break;
346 nr_blank_lines++;
347 next_line (file);
348 }
349 }
350 set_nr_table_entry_fields (entry, nr_lines);
351 }
352 /* now enter each line */
353 {
354 int line_nr;
355 for (line_nr = 0; line_nr < entry->nr_fields; line_nr++)
356 {
357 if (*chp == '\t')
358 entry->field[line_nr] = chp + 1;
359 else
360 entry->field[line_nr] = ""; /* blank */
361 chp = skip_to_null (chp) + 1;
362 }
363 }
364 break;
365 }
366
367 /* cpp directive? */
368 if (file->pos[0] == '#')
369 {
370 char *chp = skip_spaces (file->pos + 1);
371
372 /* cpp line-nr directive - # <line-nr> "<file>" */
373 if (isdigit (*chp)
374 && *skip_digits (chp) == ' '
375 && *skip_spaces (skip_digits (chp)) == '"')
376 {
377 int line_nr;
378 char *file_name;
379 file->pos = chp;
380 /* parse the number */
381 line_nr = atoi (file->pos) - 1;
382 /* skip to the file name */
383 while (file->pos[0] != '0'
384 && file->pos[0] != '"' && file->pos[0] != '\0')
385 file->pos++;
386 if (file->pos[0] != '"')
387 error (&file->real_line,
388 "Missing opening quote in cpp directive\n");
389 /* parse the file name */
390 file->pos++;
391 file_name = file->pos;
392 while (file->pos[0] != '"' && file->pos[0] != '\0')
393 file->pos++;
394 if (file->pos[0] != '"')
395 error (&file->real_line,
396 "Missing closing quote in cpp directive\n");
397 file->pos[0] = '\0';
398 file->pos++;
399 file->pos = skip_to_nl (file->pos);
400 if (file->pos[0] != '\n')
401 error (&file->real_line,
402 "Missing newline in cpp directive\n");
403 file->pseudo_line.file_name = file_name;
404 file->pseudo_line.line_nr = line_nr;
405 next_line (file);
406 continue;
407 }
408
409 /* #define and #undef - not implemented yet */
410
411 /* Old style # comment */
412 next_line (file);
413 continue;
414 }
415
416 /* blank line or end-of-file? */
417 file->pos = skip_spaces (file->pos);
418 if (*file->pos == '\0')
419 error (&file->pseudo_line, "Missing <nl> at end of file\n");
420 if (*file->pos == '\n')
421 {
422 next_line (file);
423 continue;
424 }
425
426 /* comment - leading // or # - skip */
427 if ((file->pos[0] == '/' && file->pos[1] == '/')
428 || (file->pos[0] == '#'))
429 {
430 next_line (file);
431 continue;
432 }
433
434 /* colon field */
435 {
436 char *chp = file->pos;
437 entry = new_table_entry (file, table_colon_entry);
438 next_line (file);
439 /* figure out how many fields */
440 {
441 int nr_fields = 1;
442 char *tmpch = chp;
443 while (1)
444 {
445 tmpch = skip_to_separator (tmpch, "\\:");
446 if (*tmpch == '\\')
447 {
448 /* eat the escaped character */
449 char *cp = tmpch;
450 while (cp[1] != '\0')
451 {
452 cp[0] = cp[1];
453 cp++;
454 }
455 cp[0] = '\0';
456 tmpch++;
457 }
458 else if (*tmpch != ':')
459 break;
460 else
461 {
462 *tmpch = '\0';
463 tmpch++;
464 nr_fields++;
465 }
466 }
467 set_nr_table_entry_fields (entry, nr_fields);
468 }
469 /* now parse them */
470 {
471 int field_nr;
472 for (field_nr = 0; field_nr < entry->nr_fields; field_nr++)
473 {
474 chp = skip_spaces (chp);
475 entry->field[field_nr] = chp;
476 chp = skip_to_null (chp);
477 *back_spaces (entry->field[field_nr], chp) = '\0';
478 chp++;
479 }
480 }
481 break;
482 }
483
484 }
485
486 ASSERT (entry == NULL || entry->field[entry->nr_fields] == NULL);
487 return entry;
488 }
489
490 extern void
491 table_print_code (lf *file, table_entry *entry)
492 {
493 int field_nr;
494 int nr = 0;
495 for (field_nr = 0; field_nr < entry->nr_fields; field_nr++)
496 {
497 char *chp = entry->field[field_nr];
498 int in_bit_field = 0;
499 if (*chp == '#')
500 lf_indent_suppress (file);
501 while (*chp != '\0')
502 {
503 if (chp[0] == '{' && !isspace (chp[1]) && chp[1] != '\0')
504 {
505 in_bit_field = 1;
506 nr += lf_putchr (file, '_');
507 }
508 else if (in_bit_field && chp[0] == ':')
509 {
510 nr += lf_putchr (file, '_');
511 }
512 else if (in_bit_field && *chp == '}')
513 {
514 nr += lf_putchr (file, '_');
515 in_bit_field = 0;
516 }
517 else
518 {
519 nr += lf_putchr (file, *chp);
520 }
521 chp++;
522 }
523 if (in_bit_field)
524 {
525 line_ref line = *entry->line;
526 line.line_nr += field_nr;
527 error (&line, "Bit field brace miss match\n");
528 }
529 nr += lf_putchr (file, '\n');
530 }
531 }
532
533
534
535 void
536 dump_line_ref (lf *file, char *prefix, const line_ref *line, char *suffix)
537 {
538 lf_printf (file, "%s(line_ref*) 0x%lx", prefix, (long) line);
539 if (line != NULL)
540 {
541 lf_indent (file, +1);
542 lf_printf (file, "\n(line_nr %d)", line->line_nr);
543 lf_printf (file, "\n(file_name %s)", line->file_name);
544 lf_indent (file, -1);
545 }
546 lf_printf (file, "%s", suffix);
547 }
548
549
550 static const char *
551 table_entry_type_to_str (table_entry_type type)
552 {
553 switch (type)
554 {
555 case table_code_entry:
556 return "code-entry";
557 case table_colon_entry:
558 return "colon-entry";
559 }
560 return "*invalid*";
561 }
562
563 void
564 dump_table_entry (lf *file,
565 char *prefix, const table_entry *entry, char *suffix)
566 {
567 lf_printf (file, "%s(table_entry*) 0x%lx", prefix, (long) entry);
568 if (entry != NULL)
569 {
570 int field;
571 lf_indent (file, +1);
572 dump_line_ref (file, "\n(line ", entry->line, ")");
573 lf_printf (file, "\n(type %s)", table_entry_type_to_str (entry->type));
574 lf_printf (file, "\n(nr_fields %d)", entry->nr_fields);
575 lf_printf (file, "\n(fields");
576 lf_indent (file, +1);
577 for (field = 0; field < entry->nr_fields; field++)
578 lf_printf (file, "\n\"%s\"", entry->field[field]);
579 lf_indent (file, -1);
580 lf_printf (file, ")");
581 lf_indent (file, -1);
582 }
583 lf_printf (file, "%s", suffix);
584 }
585
586
587 #ifdef MAIN
588 int
589 main (int argc, char **argv)
590 {
591 table *t;
592 table_entry *entry;
593 lf *l;
594 int line_nr;
595
596 if (argc != 2)
597 {
598 printf ("Usage: table <file>\n");
599 exit (1);
600 }
601
602 t = table_open (argv[1]);
603 l = lf_open ("-", "stdout", lf_omit_references, lf_is_text, "tmp-table");
604
605 line_nr = 0;
606 do
607 {
608 char line[10];
609 entry = table_read (t);
610 line_nr++;
611 sprintf (line, "(%d ", line_nr);
612 dump_table_entry (l, line, entry, ")\n");
613 }
614 while (entry != NULL);
615
616 return 0;
617 }
618 #endif