Add documentation for the MIPS assembler's -march=from-abi command line option
[binutils-gdb.git] / sim / igen / lf.c
blob46b1f6b59ec9403bca38c68d80793c40ab99ce61
1 /* The IGEN simulator generator for GDB, the GNU Debugger.
3 Copyright 2002-2023 Free Software Foundation, Inc.
5 Contributed by Andrew Cagney.
7 This file is part of GDB.
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.
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.
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/>. */
23 #include <stdbool.h>
24 #include <stdio.h>
25 #include <stdarg.h>
26 #include <ctype.h>
28 #include "misc.h"
29 #include "lf.h"
31 #include <stdlib.h>
32 #include <string.h>
34 struct _lf
36 FILE *stream;
37 int line_nr; /* nr complete lines written, curr line is line_nr+1 */
38 int indent;
39 int line_blank;
40 const char *name; /* Output name with diagnostics. */
41 const char *filename; /* Output filename. */
42 char *tmpname; /* Temporary output filename. */
43 const char *program;
44 lf_file_references references;
45 lf_file_type type;
49 lf *
50 lf_open (const char *name,
51 const char *real_name,
52 lf_file_references references,
53 lf_file_type type, const char *program)
55 /* create a file object */
56 lf *new_lf = ZALLOC (lf);
57 ASSERT (new_lf != NULL);
58 new_lf->references = references;
59 new_lf->type = type;
60 new_lf->name = (real_name == NULL ? name : real_name);
61 new_lf->filename = name;
62 new_lf->program = program;
63 /* attach to stdout if pipe */
64 if (!strcmp (name, "-"))
66 new_lf->stream = stdout;
68 else
70 /* create a new file */
71 char *tmpname = zalloc (strlen (name) + 5);
72 sprintf (tmpname, "%s.tmp", name);
73 new_lf->filename = name;
74 new_lf->tmpname = tmpname;
75 new_lf->stream = fopen (tmpname, "w+");
76 if (new_lf->stream == NULL)
78 perror (name);
79 exit (1);
82 return new_lf;
86 lf_file_type
87 lf_get_file_type (const lf *file)
89 return file->type;
93 void
94 lf_close (lf *file)
96 FILE *fp;
97 bool update = true;
99 /* If we wrote to stdout, no house keeping needed. */
100 if (file->stream == stdout)
101 return;
103 /* Rename the temp file to the real file if it's changed. */
104 fp = fopen (file->filename, "r");
105 if (fp != NULL)
107 off_t len;
109 fseek (fp, 0, SEEK_END);
110 len = ftell (fp);
112 if (len == ftell (file->stream))
114 off_t off;
115 size_t cnt;
116 char *oldbuf = zalloc (len);
117 char *newbuf = zalloc (len);
119 rewind (fp);
120 off = 0;
121 while ((cnt = fread (oldbuf + off, 1, len - off, fp)) > 0)
122 off += cnt;
123 ASSERT (off == len);
125 rewind (file->stream);
126 off = 0;
127 while ((cnt = fread (newbuf + off, 1, len - off, file->stream)) > 0)
128 off += cnt;
129 ASSERT (off == len);
131 if (memcmp (oldbuf, newbuf, len) == 0)
132 update = false;
135 fclose (fp);
138 if (fclose (file->stream))
140 perror ("lf_close.fclose");
141 exit (1);
144 if (update)
146 if (rename (file->tmpname, file->filename) != 0)
148 perror ("lf_close.rename");
149 exit (1);
152 else
154 if (remove (file->tmpname) != 0)
156 perror ("lf_close.unlink");
157 exit (1);
161 free (file->tmpname);
162 free (file);
167 lf_putchr (lf *file, const char chr)
169 int nr = 0;
170 if (chr == '\n')
172 file->line_nr += 1;
173 file->line_blank = 1;
175 else if (file->line_blank)
177 int pad;
178 for (pad = file->indent; pad > 0; pad--)
179 putc (' ', file->stream);
180 nr += file->indent;
181 file->line_blank = 0;
183 putc (chr, file->stream);
184 nr += 1;
185 return nr;
189 lf_write (lf *file, const char *string, int strlen_string)
191 int nr = 0;
192 int i;
193 for (i = 0; i < strlen_string; i++)
194 nr += lf_putchr (file, string[i]);
195 return nr;
199 void
200 lf_indent_suppress (lf *file)
202 file->line_blank = 0;
207 lf_putstr (lf *file, const char *string)
209 int nr = 0;
210 const char *chp;
211 if (string != NULL)
213 for (chp = string; *chp != '\0'; chp++)
215 nr += lf_putchr (file, *chp);
218 return nr;
221 static int
222 do_lf_putunsigned (lf *file, unsigned u)
224 int nr = 0;
225 if (u > 0)
227 nr += do_lf_putunsigned (file, u / 10);
228 nr += lf_putchr (file, (u % 10) + '0');
230 return nr;
235 lf_putint (lf *file, int decimal)
237 int nr = 0;
238 if (decimal == 0)
239 nr += lf_putchr (file, '0');
240 else if (decimal < 0)
242 nr += lf_putchr (file, '-');
243 nr += do_lf_putunsigned (file, -decimal);
245 else if (decimal > 0)
247 nr += do_lf_putunsigned (file, decimal);
249 else
250 ASSERT (0);
251 return nr;
256 lf_printf (lf *file, const char *fmt, ...)
258 int nr = 0;
259 char buf[1024];
260 va_list ap;
262 va_start (ap, fmt);
263 vsprintf (buf, fmt, ap);
264 /* FIXME - this is really stuffed but so is vsprintf() on a sun! */
265 ASSERT (strlen (buf) < sizeof (buf));
266 nr += lf_putstr (file, buf);
267 va_end (ap);
268 return nr;
273 lf_print__line_ref (lf *file, const line_ref *line)
275 return lf_print__external_ref (file, line->line_nr, line->file_name);
279 lf_print__external_ref (lf *file, int line_nr, const char *file_name)
281 int nr = 0;
282 switch (file->references)
284 case lf_include_references:
285 lf_indent_suppress (file);
286 nr += lf_putstr (file, "#line ");
287 nr += lf_putint (file, line_nr);
288 nr += lf_putstr (file, " \"");
289 nr += lf_putstr (file, file_name);
290 nr += lf_putstr (file, "\"\n");
291 break;
292 case lf_omit_references:
293 nr += lf_putstr (file, "/* ");
294 nr += lf_putstr (file, file_name);
295 nr += lf_putstr (file, ":");
296 nr += lf_putint (file, line_nr);
297 nr += lf_putstr (file, "*/\n");
298 break;
300 return nr;
304 lf_print__internal_ref (lf *file)
306 int nr = 0;
307 nr += lf_print__external_ref (file, file->line_nr + 2, file->name);
308 /* line_nr == last_line, want to number from next */
309 return nr;
312 void
313 lf_indent (lf *file, int delta)
315 file->indent += delta;
320 lf_print__gnu_copyleft (lf *file)
322 int nr = 0;
323 switch (file->type)
325 case lf_is_c:
326 case lf_is_h:
327 nr += lf_printf (file, "\
328 /* This file is part of GDB.\n\
330 Copyright 2002, 2007 Free Software Foundation, Inc.\n\
332 This program is free software; you can redistribute it and/or modify\n\
333 it under the terms of the GNU General Public License as published by\n\
334 the Free Software Foundation; either version 3 of the License, or\n\
335 (at your option) any later version.\n\
337 This program is distributed in the hope that it will be useful,\n\
338 but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
339 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\
340 GNU General Public License for more details.\n\
342 You should have received a copy of the GNU General Public License\n\
343 along with this program. If not, see <http://www.gnu.org/licenses/>.\n\
345 --\n\
347 This file was generated by the program %s */\n\
348 ", filter_filename (file->program));
349 break;
350 default:
351 ASSERT (0);
352 break;
354 return nr;
359 lf_putbin (lf *file, int decimal, int width)
361 int nr = 0;
362 int bit;
363 ASSERT (width > 0);
364 for (bit = 1 << (width - 1); bit != 0; bit >>= 1)
366 if (decimal & bit)
367 nr += lf_putchr (file, '1');
368 else
369 nr += lf_putchr (file, '0');
371 return nr;
375 lf_print__this_file_is_empty (lf *file, const char *reason)
377 int nr = 0;
378 switch (file->type)
380 case lf_is_c:
381 case lf_is_h:
382 nr += lf_printf (file,
383 "/* This generated file (%s) is intentionally left blank",
384 file->name);
385 if (reason != NULL)
386 nr += lf_printf (file, " - %s", reason);
387 nr += lf_printf (file, " */\n");
388 break;
389 default:
390 ERROR ("Bad switch");
392 return nr;
396 lf_print__ucase_filename (lf *file)
398 int nr = 0;
399 const char *chp = file->name;
400 while (*chp != '\0')
402 char ch = *chp;
403 if (islower (ch))
405 nr += lf_putchr (file, toupper (ch));
407 else if (ch == '.')
408 nr += lf_putchr (file, '_');
409 else
410 nr += lf_putchr (file, ch);
411 chp++;
413 return nr;
417 lf_print__file_start (lf *file)
419 int nr = 0;
420 switch (file->type)
422 case lf_is_h:
423 case lf_is_c:
424 nr += lf_print__gnu_copyleft (file);
425 nr += lf_printf (file, "\n");
426 nr += lf_printf (file, "#ifndef ");
427 nr += lf_print__ucase_filename (file);
428 nr += lf_printf (file, "\n");
429 nr += lf_printf (file, "#define ");
430 nr += lf_print__ucase_filename (file);
431 nr += lf_printf (file, "\n");
432 nr += lf_printf (file, "\n");
433 break;
434 default:
435 ASSERT (0);
437 return nr;
442 lf_print__file_finish (lf *file)
444 int nr = 0;
445 switch (file->type)
447 case lf_is_h:
448 case lf_is_c:
449 nr += lf_printf (file, "\n");
450 nr += lf_printf (file, "#endif /* _");
451 nr += lf_print__ucase_filename (file);
452 nr += lf_printf (file, "_*/\n");
453 break;
454 default:
455 ASSERT (0);
457 return nr;
462 lf_print__function_type (lf *file,
463 const char *type,
464 const char *prefix, const char *trailing_space)
466 int nr = 0;
467 nr += lf_printf (file, "%s\\\n(%s)", prefix, type);
468 if (trailing_space != NULL)
469 nr += lf_printf (file, "%s", trailing_space);
470 return nr;
474 lf_print__function_type_function (lf *file,
475 print_function * print_type,
476 const char *prefix,
477 const char *trailing_space)
479 int nr = 0;
480 nr += lf_printf (file, "%s\\\n(", prefix);
481 nr += print_type (file);
482 nr += lf_printf (file, ")");
483 if (trailing_space != NULL)
484 nr += lf_printf (file, "%s", trailing_space);
485 return nr;