Home | History | Annotate | Line # | Download | only in igen
      1 /* The IGEN simulator generator for GDB, the GNU Debugger.
      2 
      3    Copyright 2002-2024 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 }
    487