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