14e98e3e1Schristos /* The IGEN simulator generator for GDB, the GNU Debugger. 24e98e3e1Schristos 3*71f62182Schristos Copyright 2002-2024 Free Software Foundation, Inc. 44e98e3e1Schristos 54e98e3e1Schristos Contributed by Andrew Cagney. 64e98e3e1Schristos 74e98e3e1Schristos This file is part of GDB. 84e98e3e1Schristos 94e98e3e1Schristos This program is free software; you can redistribute it and/or modify 104e98e3e1Schristos it under the terms of the GNU General Public License as published by 114e98e3e1Schristos the Free Software Foundation; either version 3 of the License, or 124e98e3e1Schristos (at your option) any later version. 134e98e3e1Schristos 144e98e3e1Schristos This program is distributed in the hope that it will be useful, 154e98e3e1Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of 164e98e3e1Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 174e98e3e1Schristos GNU General Public License for more details. 184e98e3e1Schristos 194e98e3e1Schristos You should have received a copy of the GNU General Public License 204e98e3e1Schristos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 214e98e3e1Schristos 224e98e3e1Schristos 23*71f62182Schristos #include <stdbool.h> 244e98e3e1Schristos #include <stdio.h> 254e98e3e1Schristos #include <stdarg.h> 264e98e3e1Schristos #include <ctype.h> 274e98e3e1Schristos 284e98e3e1Schristos #include "misc.h" 294e98e3e1Schristos #include "lf.h" 304e98e3e1Schristos 314e98e3e1Schristos #include <stdlib.h> 324e98e3e1Schristos #include <string.h> 334e98e3e1Schristos 344e98e3e1Schristos struct _lf 354e98e3e1Schristos { 364e98e3e1Schristos FILE *stream; 374e98e3e1Schristos int line_nr; /* nr complete lines written, curr line is line_nr+1 */ 384e98e3e1Schristos int indent; 394e98e3e1Schristos int line_blank; 40*71f62182Schristos const char *name; /* Output name with diagnostics. */ 41*71f62182Schristos const char *filename; /* Output filename. */ 42*71f62182Schristos char *tmpname; /* Temporary output filename. */ 434e98e3e1Schristos const char *program; 444e98e3e1Schristos lf_file_references references; 454e98e3e1Schristos lf_file_type type; 464e98e3e1Schristos }; 474e98e3e1Schristos 484e98e3e1Schristos 494e98e3e1Schristos lf * 504b169a6bSchristos lf_open (const char *name, 514b169a6bSchristos const char *real_name, 524e98e3e1Schristos lf_file_references references, 534e98e3e1Schristos lf_file_type type, const char *program) 544e98e3e1Schristos { 554e98e3e1Schristos /* create a file object */ 564e98e3e1Schristos lf *new_lf = ZALLOC (lf); 574e98e3e1Schristos ASSERT (new_lf != NULL); 584e98e3e1Schristos new_lf->references = references; 594e98e3e1Schristos new_lf->type = type; 604e98e3e1Schristos new_lf->name = (real_name == NULL ? name : real_name); 61*71f62182Schristos new_lf->filename = name; 624e98e3e1Schristos new_lf->program = program; 634e98e3e1Schristos /* attach to stdout if pipe */ 644e98e3e1Schristos if (!strcmp (name, "-")) 654e98e3e1Schristos { 664e98e3e1Schristos new_lf->stream = stdout; 674e98e3e1Schristos } 684e98e3e1Schristos else 694e98e3e1Schristos { 704e98e3e1Schristos /* create a new file */ 71*71f62182Schristos char *tmpname = zalloc (strlen (name) + 5); 72*71f62182Schristos sprintf (tmpname, "%s.tmp", name); 73*71f62182Schristos new_lf->filename = name; 74*71f62182Schristos new_lf->tmpname = tmpname; 75*71f62182Schristos new_lf->stream = fopen (tmpname, "w+"); 764e98e3e1Schristos if (new_lf->stream == NULL) 774e98e3e1Schristos { 784e98e3e1Schristos perror (name); 794e98e3e1Schristos exit (1); 804e98e3e1Schristos } 814e98e3e1Schristos } 824e98e3e1Schristos return new_lf; 834e98e3e1Schristos } 844e98e3e1Schristos 854e98e3e1Schristos 868dffb485Schristos lf_file_type 878dffb485Schristos lf_get_file_type (const lf *file) 888dffb485Schristos { 898dffb485Schristos return file->type; 908dffb485Schristos } 918dffb485Schristos 928dffb485Schristos 934e98e3e1Schristos void 944e98e3e1Schristos lf_close (lf *file) 954e98e3e1Schristos { 96*71f62182Schristos FILE *fp; 97*71f62182Schristos bool update = true; 98*71f62182Schristos 99*71f62182Schristos /* If we wrote to stdout, no house keeping needed. */ 100*71f62182Schristos if (file->stream == stdout) 101*71f62182Schristos return; 102*71f62182Schristos 103*71f62182Schristos /* Rename the temp file to the real file if it's changed. */ 104*71f62182Schristos fp = fopen (file->filename, "r"); 105*71f62182Schristos if (fp != NULL) 1064e98e3e1Schristos { 107*71f62182Schristos off_t len; 108*71f62182Schristos 109*71f62182Schristos fseek (fp, 0, SEEK_END); 110*71f62182Schristos len = ftell (fp); 111*71f62182Schristos 112*71f62182Schristos if (len == ftell (file->stream)) 113*71f62182Schristos { 114*71f62182Schristos off_t off; 115*71f62182Schristos size_t cnt; 116*71f62182Schristos char *oldbuf = zalloc (len); 117*71f62182Schristos char *newbuf = zalloc (len); 118*71f62182Schristos 119*71f62182Schristos rewind (fp); 120*71f62182Schristos off = 0; 121*71f62182Schristos while ((cnt = fread (oldbuf + off, 1, len - off, fp)) > 0) 122*71f62182Schristos off += cnt; 123*71f62182Schristos ASSERT (off == len); 124*71f62182Schristos 125*71f62182Schristos rewind (file->stream); 126*71f62182Schristos off = 0; 127*71f62182Schristos while ((cnt = fread (newbuf + off, 1, len - off, file->stream)) > 0) 128*71f62182Schristos off += cnt; 129*71f62182Schristos ASSERT (off == len); 130*71f62182Schristos 131*71f62182Schristos if (memcmp (oldbuf, newbuf, len) == 0) 132*71f62182Schristos update = false; 133*71f62182Schristos } 134*71f62182Schristos 135*71f62182Schristos fclose (fp); 136*71f62182Schristos } 137*71f62182Schristos 1384e98e3e1Schristos if (fclose (file->stream)) 1394e98e3e1Schristos { 1404e98e3e1Schristos perror ("lf_close.fclose"); 1414e98e3e1Schristos exit (1); 1424e98e3e1Schristos } 143*71f62182Schristos 144*71f62182Schristos if (update) 145*71f62182Schristos { 146*71f62182Schristos if (rename (file->tmpname, file->filename) != 0) 147*71f62182Schristos { 148*71f62182Schristos perror ("lf_close.rename"); 149*71f62182Schristos exit (1); 1504e98e3e1Schristos } 1514e98e3e1Schristos } 152*71f62182Schristos else 153*71f62182Schristos { 154*71f62182Schristos if (remove (file->tmpname) != 0) 155*71f62182Schristos { 156*71f62182Schristos perror ("lf_close.unlink"); 157*71f62182Schristos exit (1); 158*71f62182Schristos } 159*71f62182Schristos } 160*71f62182Schristos 161*71f62182Schristos free (file->tmpname); 162*71f62182Schristos free (file); 163*71f62182Schristos } 1644e98e3e1Schristos 1654e98e3e1Schristos 1664e98e3e1Schristos int 1674e98e3e1Schristos lf_putchr (lf *file, const char chr) 1684e98e3e1Schristos { 1694e98e3e1Schristos int nr = 0; 1704e98e3e1Schristos if (chr == '\n') 1714e98e3e1Schristos { 1724e98e3e1Schristos file->line_nr += 1; 1734e98e3e1Schristos file->line_blank = 1; 1744e98e3e1Schristos } 1754e98e3e1Schristos else if (file->line_blank) 1764e98e3e1Schristos { 1774e98e3e1Schristos int pad; 1784e98e3e1Schristos for (pad = file->indent; pad > 0; pad--) 1794e98e3e1Schristos putc (' ', file->stream); 1804e98e3e1Schristos nr += file->indent; 1814e98e3e1Schristos file->line_blank = 0; 1824e98e3e1Schristos } 1834e98e3e1Schristos putc (chr, file->stream); 1844e98e3e1Schristos nr += 1; 1854e98e3e1Schristos return nr; 1864e98e3e1Schristos } 1874e98e3e1Schristos 1884e98e3e1Schristos int 1894e98e3e1Schristos lf_write (lf *file, const char *string, int strlen_string) 1904e98e3e1Schristos { 1914e98e3e1Schristos int nr = 0; 1924e98e3e1Schristos int i; 1934e98e3e1Schristos for (i = 0; i < strlen_string; i++) 1944e98e3e1Schristos nr += lf_putchr (file, string[i]); 1954e98e3e1Schristos return nr; 1964e98e3e1Schristos } 1974e98e3e1Schristos 1984e98e3e1Schristos 1994e98e3e1Schristos void 2004e98e3e1Schristos lf_indent_suppress (lf *file) 2014e98e3e1Schristos { 2024e98e3e1Schristos file->line_blank = 0; 2034e98e3e1Schristos } 2044e98e3e1Schristos 2054e98e3e1Schristos 2064e98e3e1Schristos int 2074e98e3e1Schristos lf_putstr (lf *file, const char *string) 2084e98e3e1Schristos { 2094e98e3e1Schristos int nr = 0; 2104e98e3e1Schristos const char *chp; 2114e98e3e1Schristos if (string != NULL) 2124e98e3e1Schristos { 2134e98e3e1Schristos for (chp = string; *chp != '\0'; chp++) 2144e98e3e1Schristos { 2154e98e3e1Schristos nr += lf_putchr (file, *chp); 2164e98e3e1Schristos } 2174e98e3e1Schristos } 2184e98e3e1Schristos return nr; 2194e98e3e1Schristos } 2204e98e3e1Schristos 2214e98e3e1Schristos static int 2224e98e3e1Schristos do_lf_putunsigned (lf *file, unsigned u) 2234e98e3e1Schristos { 2244e98e3e1Schristos int nr = 0; 2254e98e3e1Schristos if (u > 0) 2264e98e3e1Schristos { 2274e98e3e1Schristos nr += do_lf_putunsigned (file, u / 10); 2284e98e3e1Schristos nr += lf_putchr (file, (u % 10) + '0'); 2294e98e3e1Schristos } 2304e98e3e1Schristos return nr; 2314e98e3e1Schristos } 2324e98e3e1Schristos 2334e98e3e1Schristos 2344e98e3e1Schristos int 2354e98e3e1Schristos lf_putint (lf *file, int decimal) 2364e98e3e1Schristos { 2374e98e3e1Schristos int nr = 0; 2384e98e3e1Schristos if (decimal == 0) 2394e98e3e1Schristos nr += lf_putchr (file, '0'); 2404e98e3e1Schristos else if (decimal < 0) 2414e98e3e1Schristos { 2424e98e3e1Schristos nr += lf_putchr (file, '-'); 2434e98e3e1Schristos nr += do_lf_putunsigned (file, -decimal); 2444e98e3e1Schristos } 2454e98e3e1Schristos else if (decimal > 0) 2464e98e3e1Schristos { 2474e98e3e1Schristos nr += do_lf_putunsigned (file, decimal); 2484e98e3e1Schristos } 2494e98e3e1Schristos else 2504e98e3e1Schristos ASSERT (0); 2514e98e3e1Schristos return nr; 2524e98e3e1Schristos } 2534e98e3e1Schristos 2544e98e3e1Schristos 2554e98e3e1Schristos int 2564e98e3e1Schristos lf_printf (lf *file, const char *fmt, ...) 2574e98e3e1Schristos { 2584e98e3e1Schristos int nr = 0; 2594e98e3e1Schristos char buf[1024]; 2604e98e3e1Schristos va_list ap; 2614e98e3e1Schristos 2624e98e3e1Schristos va_start (ap, fmt); 2634e98e3e1Schristos vsprintf (buf, fmt, ap); 2644e98e3e1Schristos /* FIXME - this is really stuffed but so is vsprintf() on a sun! */ 2654e98e3e1Schristos ASSERT (strlen (buf) < sizeof (buf)); 2664e98e3e1Schristos nr += lf_putstr (file, buf); 2674e98e3e1Schristos va_end (ap); 2684e98e3e1Schristos return nr; 2694e98e3e1Schristos } 2704e98e3e1Schristos 2714e98e3e1Schristos 2724e98e3e1Schristos int 2734b169a6bSchristos lf_print__line_ref (lf *file, const line_ref *line) 2744e98e3e1Schristos { 2754e98e3e1Schristos return lf_print__external_ref (file, line->line_nr, line->file_name); 2764e98e3e1Schristos } 2774e98e3e1Schristos 2784e98e3e1Schristos int 2794e98e3e1Schristos lf_print__external_ref (lf *file, int line_nr, const char *file_name) 2804e98e3e1Schristos { 2814e98e3e1Schristos int nr = 0; 2824e98e3e1Schristos switch (file->references) 2834e98e3e1Schristos { 2844e98e3e1Schristos case lf_include_references: 2854e98e3e1Schristos lf_indent_suppress (file); 2864e98e3e1Schristos nr += lf_putstr (file, "#line "); 2874e98e3e1Schristos nr += lf_putint (file, line_nr); 2884e98e3e1Schristos nr += lf_putstr (file, " \""); 2894e98e3e1Schristos nr += lf_putstr (file, file_name); 2904e98e3e1Schristos nr += lf_putstr (file, "\"\n"); 2914e98e3e1Schristos break; 2924e98e3e1Schristos case lf_omit_references: 2934e98e3e1Schristos nr += lf_putstr (file, "/* "); 2944e98e3e1Schristos nr += lf_putstr (file, file_name); 2954e98e3e1Schristos nr += lf_putstr (file, ":"); 2964e98e3e1Schristos nr += lf_putint (file, line_nr); 2974e98e3e1Schristos nr += lf_putstr (file, "*/\n"); 2984e98e3e1Schristos break; 2994e98e3e1Schristos } 3004e98e3e1Schristos return nr; 3014e98e3e1Schristos } 3024e98e3e1Schristos 3034e98e3e1Schristos int 3044e98e3e1Schristos lf_print__internal_ref (lf *file) 3054e98e3e1Schristos { 3064e98e3e1Schristos int nr = 0; 3074e98e3e1Schristos nr += lf_print__external_ref (file, file->line_nr + 2, file->name); 3084e98e3e1Schristos /* line_nr == last_line, want to number from next */ 3094e98e3e1Schristos return nr; 3104e98e3e1Schristos } 3114e98e3e1Schristos 3124e98e3e1Schristos void 3134e98e3e1Schristos lf_indent (lf *file, int delta) 3144e98e3e1Schristos { 3154e98e3e1Schristos file->indent += delta; 3164e98e3e1Schristos } 3174e98e3e1Schristos 3184e98e3e1Schristos 3194e98e3e1Schristos int 3204e98e3e1Schristos lf_print__gnu_copyleft (lf *file) 3214e98e3e1Schristos { 3224e98e3e1Schristos int nr = 0; 3234e98e3e1Schristos switch (file->type) 3244e98e3e1Schristos { 3254e98e3e1Schristos case lf_is_c: 3264e98e3e1Schristos case lf_is_h: 3274e98e3e1Schristos nr += lf_printf (file, "\ 3284e98e3e1Schristos /* This file is part of GDB.\n\ 3294e98e3e1Schristos \n\ 3304e98e3e1Schristos Copyright 2002, 2007 Free Software Foundation, Inc.\n\ 3314e98e3e1Schristos \n\ 3324e98e3e1Schristos This program is free software; you can redistribute it and/or modify\n\ 3334e98e3e1Schristos it under the terms of the GNU General Public License as published by\n\ 3344e98e3e1Schristos the Free Software Foundation; either version 3 of the License, or\n\ 3354e98e3e1Schristos (at your option) any later version.\n\ 3364e98e3e1Schristos \n\ 3374e98e3e1Schristos This program is distributed in the hope that it will be useful,\n\ 3384e98e3e1Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of\n\ 3394e98e3e1Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\ 3404e98e3e1Schristos GNU General Public License for more details.\n\ 3414e98e3e1Schristos \n\ 3424e98e3e1Schristos You should have received a copy of the GNU General Public License\n\ 3434e98e3e1Schristos along with this program. If not, see <http://www.gnu.org/licenses/>.\n\ 3444e98e3e1Schristos \n\ 3454e98e3e1Schristos --\n\ 3464e98e3e1Schristos \n\ 3474e98e3e1Schristos This file was generated by the program %s */\n\ 3484e98e3e1Schristos ", filter_filename (file->program)); 3494e98e3e1Schristos break; 3504e98e3e1Schristos default: 3514e98e3e1Schristos ASSERT (0); 3524e98e3e1Schristos break; 3534e98e3e1Schristos } 3544e98e3e1Schristos return nr; 3554e98e3e1Schristos } 3564e98e3e1Schristos 3574e98e3e1Schristos 3584e98e3e1Schristos int 3594e98e3e1Schristos lf_putbin (lf *file, int decimal, int width) 3604e98e3e1Schristos { 3614e98e3e1Schristos int nr = 0; 3624e98e3e1Schristos int bit; 3634e98e3e1Schristos ASSERT (width > 0); 3644e98e3e1Schristos for (bit = 1 << (width - 1); bit != 0; bit >>= 1) 3654e98e3e1Schristos { 3664e98e3e1Schristos if (decimal & bit) 3674e98e3e1Schristos nr += lf_putchr (file, '1'); 3684e98e3e1Schristos else 3694e98e3e1Schristos nr += lf_putchr (file, '0'); 3704e98e3e1Schristos } 3714e98e3e1Schristos return nr; 3724e98e3e1Schristos } 3734e98e3e1Schristos 3744e98e3e1Schristos int 3754e98e3e1Schristos lf_print__this_file_is_empty (lf *file, const char *reason) 3764e98e3e1Schristos { 3774e98e3e1Schristos int nr = 0; 3784e98e3e1Schristos switch (file->type) 3794e98e3e1Schristos { 3804e98e3e1Schristos case lf_is_c: 3814e98e3e1Schristos case lf_is_h: 3824e98e3e1Schristos nr += lf_printf (file, 3834e98e3e1Schristos "/* This generated file (%s) is intentionally left blank", 3844e98e3e1Schristos file->name); 3854e98e3e1Schristos if (reason != NULL) 3864e98e3e1Schristos nr += lf_printf (file, " - %s", reason); 3874e98e3e1Schristos nr += lf_printf (file, " */\n"); 3884e98e3e1Schristos break; 3894e98e3e1Schristos default: 3904e98e3e1Schristos ERROR ("Bad switch"); 3914e98e3e1Schristos } 3924e98e3e1Schristos return nr; 3934e98e3e1Schristos } 3944e98e3e1Schristos 3954e98e3e1Schristos int 3964e98e3e1Schristos lf_print__ucase_filename (lf *file) 3974e98e3e1Schristos { 3984e98e3e1Schristos int nr = 0; 3994e98e3e1Schristos const char *chp = file->name; 4004e98e3e1Schristos while (*chp != '\0') 4014e98e3e1Schristos { 4024e98e3e1Schristos char ch = *chp; 4034e98e3e1Schristos if (islower (ch)) 4044e98e3e1Schristos { 4054e98e3e1Schristos nr += lf_putchr (file, toupper (ch)); 4064e98e3e1Schristos } 4074e98e3e1Schristos else if (ch == '.') 4084e98e3e1Schristos nr += lf_putchr (file, '_'); 4094e98e3e1Schristos else 4104e98e3e1Schristos nr += lf_putchr (file, ch); 4114e98e3e1Schristos chp++; 4124e98e3e1Schristos } 4134e98e3e1Schristos return nr; 4144e98e3e1Schristos } 4154e98e3e1Schristos 4164e98e3e1Schristos int 4174e98e3e1Schristos lf_print__file_start (lf *file) 4184e98e3e1Schristos { 4194e98e3e1Schristos int nr = 0; 4204e98e3e1Schristos switch (file->type) 4214e98e3e1Schristos { 4224e98e3e1Schristos case lf_is_h: 4234e98e3e1Schristos case lf_is_c: 4244e98e3e1Schristos nr += lf_print__gnu_copyleft (file); 4254e98e3e1Schristos nr += lf_printf (file, "\n"); 4264e98e3e1Schristos nr += lf_printf (file, "#ifndef "); 4274e98e3e1Schristos nr += lf_print__ucase_filename (file); 4284e98e3e1Schristos nr += lf_printf (file, "\n"); 4294e98e3e1Schristos nr += lf_printf (file, "#define "); 4304e98e3e1Schristos nr += lf_print__ucase_filename (file); 4314e98e3e1Schristos nr += lf_printf (file, "\n"); 4324e98e3e1Schristos nr += lf_printf (file, "\n"); 4334e98e3e1Schristos break; 4344e98e3e1Schristos default: 4354e98e3e1Schristos ASSERT (0); 4364e98e3e1Schristos } 4374e98e3e1Schristos return nr; 4384e98e3e1Schristos } 4394e98e3e1Schristos 4404e98e3e1Schristos 4414e98e3e1Schristos int 4424e98e3e1Schristos lf_print__file_finish (lf *file) 4434e98e3e1Schristos { 4444e98e3e1Schristos int nr = 0; 4454e98e3e1Schristos switch (file->type) 4464e98e3e1Schristos { 4474e98e3e1Schristos case lf_is_h: 4484e98e3e1Schristos case lf_is_c: 4494e98e3e1Schristos nr += lf_printf (file, "\n"); 4504e98e3e1Schristos nr += lf_printf (file, "#endif /* _"); 4514e98e3e1Schristos nr += lf_print__ucase_filename (file); 4524e98e3e1Schristos nr += lf_printf (file, "_*/\n"); 4534e98e3e1Schristos break; 4544e98e3e1Schristos default: 4554e98e3e1Schristos ASSERT (0); 4564e98e3e1Schristos } 4574e98e3e1Schristos return nr; 4584e98e3e1Schristos } 4594e98e3e1Schristos 4604e98e3e1Schristos 4614e98e3e1Schristos int 4624e98e3e1Schristos lf_print__function_type (lf *file, 4634e98e3e1Schristos const char *type, 4644e98e3e1Schristos const char *prefix, const char *trailing_space) 4654e98e3e1Schristos { 4664e98e3e1Schristos int nr = 0; 4674e98e3e1Schristos nr += lf_printf (file, "%s\\\n(%s)", prefix, type); 4684e98e3e1Schristos if (trailing_space != NULL) 4694e98e3e1Schristos nr += lf_printf (file, "%s", trailing_space); 4704e98e3e1Schristos return nr; 4714e98e3e1Schristos } 4724e98e3e1Schristos 4734e98e3e1Schristos int 4744e98e3e1Schristos lf_print__function_type_function (lf *file, 4754e98e3e1Schristos print_function * print_type, 4764e98e3e1Schristos const char *prefix, 4774e98e3e1Schristos const char *trailing_space) 4784e98e3e1Schristos { 4794e98e3e1Schristos int nr = 0; 4804e98e3e1Schristos nr += lf_printf (file, "%s\\\n(", prefix); 4814e98e3e1Schristos nr += print_type (file); 4824e98e3e1Schristos nr += lf_printf (file, ")"); 4834e98e3e1Schristos if (trailing_space != NULL) 4844e98e3e1Schristos nr += lf_printf (file, "%s", trailing_space); 4854e98e3e1Schristos return nr; 4864e98e3e1Schristos } 487