]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/igen/lf.c
46b1f6b59ec9403bca38c68d80793c40ab99ce61
[thirdparty/binutils-gdb.git] / sim / igen / lf.c
1 /* The IGEN simulator generator for GDB, the GNU Debugger.
2
3 Copyright 2002-2023 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 #include <stdbool.h>
24 #include <stdio.h>
25 #include <stdarg.h>
26 #include <ctype.h>
27
28 #include "misc.h"
29 #include "lf.h"
30
31 #include <stdlib.h>
32 #include <string.h>
33
34 struct _lf
35 {
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;
46 };
47
48
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)
54 {
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, "-"))
65 {
66 new_lf->stream = stdout;
67 }
68 else
69 {
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)
77 {
78 perror (name);
79 exit (1);
80 }
81 }
82 return new_lf;
83 }
84
85
86 lf_file_type
87 lf_get_file_type (const lf *file)
88 {
89 return file->type;
90 }
91
92
93 void
94 lf_close (lf *file)
95 {
96 FILE *fp;
97 bool update = true;
98
99 /* If we wrote to stdout, no house keeping needed. */
100 if (file->stream == stdout)
101 return;
102
103 /* Rename the temp file to the real file if it's changed. */
104 fp = fopen (file->filename, "r");
105 if (fp != NULL)
106 {
107 off_t len;
108
109 fseek (fp, 0, SEEK_END);
110 len = ftell (fp);
111
112 if (len == ftell (file->stream))
113 {
114 off_t off;
115 size_t cnt;
116 char *oldbuf = zalloc (len);
117 char *newbuf = zalloc (len);
118
119 rewind (fp);
120 off = 0;
121 while ((cnt = fread (oldbuf + off, 1, len - off, fp)) > 0)
122 off += cnt;
123 ASSERT (off == len);
124
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);
130
131 if (memcmp (oldbuf, newbuf, len) == 0)
132 update = false;
133 }
134
135 fclose (fp);
136 }
137
138 if (fclose (file->stream))
139 {
140 perror ("lf_close.fclose");
141 exit (1);
142 }
143
144 if (update)
145 {
146 if (rename (file->tmpname, file->filename) != 0)
147 {
148 perror ("lf_close.rename");
149 exit (1);
150 }
151 }
152 else
153 {
154 if (remove (file->tmpname) != 0)
155 {
156 perror ("lf_close.unlink");
157 exit (1);
158 }
159 }
160
161 free (file->tmpname);
162 free (file);
163 }
164
165
166 int
167 lf_putchr (lf *file, const char chr)
168 {
169 int nr = 0;
170 if (chr == '\n')
171 {
172 file->line_nr += 1;
173 file->line_blank = 1;
174 }
175 else if (file->line_blank)
176 {
177 int pad;
178 for (pad = file->indent; pad > 0; pad--)
179 putc (' ', file->stream);
180 nr += file->indent;
181 file->line_blank = 0;
182 }
183 putc (chr, file->stream);
184 nr += 1;
185 return nr;
186 }
187
188 int
189 lf_write (lf *file, const char *string, int strlen_string)
190 {
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;
196 }
197
198
199 void
200 lf_indent_suppress (lf *file)
201 {
202 file->line_blank = 0;
203 }
204
205
206 int
207 lf_putstr (lf *file, const char *string)
208 {
209 int nr = 0;
210 const char *chp;
211 if (string != NULL)
212 {
213 for (chp = string; *chp != '\0'; chp++)
214 {
215 nr += lf_putchr (file, *chp);
216 }
217 }
218 return nr;
219 }
220
221 static int
222 do_lf_putunsigned (lf *file, unsigned u)
223 {
224 int nr = 0;
225 if (u > 0)
226 {
227 nr += do_lf_putunsigned (file, u / 10);
228 nr += lf_putchr (file, (u % 10) + '0');
229 }
230 return nr;
231 }
232
233
234 int
235 lf_putint (lf *file, int decimal)
236 {
237 int nr = 0;
238 if (decimal == 0)
239 nr += lf_putchr (file, '0');
240 else if (decimal < 0)
241 {
242 nr += lf_putchr (file, '-');
243 nr += do_lf_putunsigned (file, -decimal);
244 }
245 else if (decimal > 0)
246 {
247 nr += do_lf_putunsigned (file, decimal);
248 }
249 else
250 ASSERT (0);
251 return nr;
252 }
253
254
255 int
256 lf_printf (lf *file, const char *fmt, ...)
257 {
258 int nr = 0;
259 char buf[1024];
260 va_list ap;
261
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;
269 }
270
271
272 int
273 lf_print__line_ref (lf *file, const line_ref *line)
274 {
275 return lf_print__external_ref (file, line->line_nr, line->file_name);
276 }
277
278 int
279 lf_print__external_ref (lf *file, int line_nr, const char *file_name)
280 {
281 int nr = 0;
282 switch (file->references)
283 {
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;
299 }
300 return nr;
301 }
302
303 int
304 lf_print__internal_ref (lf *file)
305 {
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;
310 }
311
312 void
313 lf_indent (lf *file, int delta)
314 {
315 file->indent += delta;
316 }
317
318
319 int
320 lf_print__gnu_copyleft (lf *file)
321 {
322 int nr = 0;
323 switch (file->type)
324 {
325 case lf_is_c:
326 case lf_is_h:
327 nr += lf_printf (file, "\
328 /* This file is part of GDB.\n\
329 \n\
330 Copyright 2002, 2007 Free Software Foundation, Inc.\n\
331 \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\
336 \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\
341 \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\
344 \n\
345 --\n\
346 \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;
353 }
354 return nr;
355 }
356
357
358 int
359 lf_putbin (lf *file, int decimal, int width)
360 {
361 int nr = 0;
362 int bit;
363 ASSERT (width > 0);
364 for (bit = 1 << (width - 1); bit != 0; bit >>= 1)
365 {
366 if (decimal & bit)
367 nr += lf_putchr (file, '1');
368 else
369 nr += lf_putchr (file, '0');
370 }
371 return nr;
372 }
373
374 int
375 lf_print__this_file_is_empty (lf *file, const char *reason)
376 {
377 int nr = 0;
378 switch (file->type)
379 {
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");
391 }
392 return nr;
393 }
394
395 int
396 lf_print__ucase_filename (lf *file)
397 {
398 int nr = 0;
399 const char *chp = file->name;
400 while (*chp != '\0')
401 {
402 char ch = *chp;
403 if (islower (ch))
404 {
405 nr += lf_putchr (file, toupper (ch));
406 }
407 else if (ch == '.')
408 nr += lf_putchr (file, '_');
409 else
410 nr += lf_putchr (file, ch);
411 chp++;
412 }
413 return nr;
414 }
415
416 int
417 lf_print__file_start (lf *file)
418 {
419 int nr = 0;
420 switch (file->type)
421 {
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);
436 }
437 return nr;
438 }
439
440
441 int
442 lf_print__file_finish (lf *file)
443 {
444 int nr = 0;
445 switch (file->type)
446 {
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);
456 }
457 return nr;
458 }
459
460
461 int
462 lf_print__function_type (lf *file,
463 const char *type,
464 const char *prefix, const char *trailing_space)
465 {
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;
471 }
472
473 int
474 lf_print__function_type_function (lf *file,
475 print_function * print_type,
476 const char *prefix,
477 const char *trailing_space)
478 {
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;
486 }