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 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 34struct _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; 41 const char *program; 42 lf_file_references references; 43 lf_file_type type; 44}; 45 46 47lf * 48lf_open (const char *name, 49 const char *real_name, 50 lf_file_references references, 51 lf_file_type type, const char *program) 52{ 53 /* create a file object */ 54 lf *new_lf = ZALLOC (lf); 55 ASSERT (new_lf != NULL); 56 new_lf->references = references; 57 new_lf->type = type; 58 new_lf->name = (real_name == NULL ? name : real_name); 59 new_lf->program = program; 60 /* attach to stdout if pipe */ 61 if (!strcmp (name, "-")) 62 { 63 new_lf->stream = stdout; 64 } 65 else 66 { 67 /* create a new file */ 68 new_lf->stream = fopen (name, "w"); 69 if (new_lf->stream == NULL) 70 { 71 perror (name); 72 exit (1); 73 } 74 } 75 return new_lf; 76} 77 78 79lf_file_type 80lf_get_file_type (const lf *file) 81{ 82 return file->type; 83} 84 85 86void 87lf_close (lf *file) 88{ 89 if (file->stream != stdout) 90 { 91 if (fclose (file->stream)) 92 { 93 perror ("lf_close.fclose"); 94 exit (1); 95 } 96 free (file); 97 } 98} 99 100 101int 102lf_putchr (lf *file, const char chr) 103{ 104 int nr = 0; 105 if (chr == '\n') 106 { 107 file->line_nr += 1; 108 file->line_blank = 1; 109 } 110 else if (file->line_blank) 111 { 112 int pad; 113 for (pad = file->indent; pad > 0; pad--) 114 putc (' ', file->stream); 115 nr += file->indent; 116 file->line_blank = 0; 117 } 118 putc (chr, file->stream); 119 nr += 1; 120 return nr; 121} 122 123int 124lf_write (lf *file, const char *string, int strlen_string) 125{ 126 int nr = 0; 127 int i; 128 for (i = 0; i < strlen_string; i++) 129 nr += lf_putchr (file, string[i]); 130 return nr; 131} 132 133 134void 135lf_indent_suppress (lf *file) 136{ 137 file->line_blank = 0; 138} 139 140 141int 142lf_putstr (lf *file, const char *string) 143{ 144 int nr = 0; 145 const char *chp; 146 if (string != NULL) 147 { 148 for (chp = string; *chp != '\0'; chp++) 149 { 150 nr += lf_putchr (file, *chp); 151 } 152 } 153 return nr; 154} 155 156static int 157do_lf_putunsigned (lf *file, unsigned u) 158{ 159 int nr = 0; 160 if (u > 0) 161 { 162 nr += do_lf_putunsigned (file, u / 10); 163 nr += lf_putchr (file, (u % 10) + '0'); 164 } 165 return nr; 166} 167 168 169int 170lf_putint (lf *file, int decimal) 171{ 172 int nr = 0; 173 if (decimal == 0) 174 nr += lf_putchr (file, '0'); 175 else if (decimal < 0) 176 { 177 nr += lf_putchr (file, '-'); 178 nr += do_lf_putunsigned (file, -decimal); 179 } 180 else if (decimal > 0) 181 { 182 nr += do_lf_putunsigned (file, decimal); 183 } 184 else 185 ASSERT (0); 186 return nr; 187} 188 189 190int 191lf_printf (lf *file, const char *fmt, ...) 192{ 193 int nr = 0; 194 char buf[1024]; 195 va_list ap; 196 197 va_start (ap, fmt); 198 vsprintf (buf, fmt, ap); 199 /* FIXME - this is really stuffed but so is vsprintf() on a sun! */ 200 ASSERT (strlen (buf) < sizeof (buf)); 201 nr += lf_putstr (file, buf); 202 va_end (ap); 203 return nr; 204} 205 206 207int 208lf_print__line_ref (lf *file, const line_ref *line) 209{ 210 return lf_print__external_ref (file, line->line_nr, line->file_name); 211} 212 213int 214lf_print__external_ref (lf *file, int line_nr, const char *file_name) 215{ 216 int nr = 0; 217 switch (file->references) 218 { 219 case lf_include_references: 220 lf_indent_suppress (file); 221 nr += lf_putstr (file, "#line "); 222 nr += lf_putint (file, line_nr); 223 nr += lf_putstr (file, " \""); 224 nr += lf_putstr (file, file_name); 225 nr += lf_putstr (file, "\"\n"); 226 break; 227 case lf_omit_references: 228 nr += lf_putstr (file, "/* "); 229 nr += lf_putstr (file, file_name); 230 nr += lf_putstr (file, ":"); 231 nr += lf_putint (file, line_nr); 232 nr += lf_putstr (file, "*/\n"); 233 break; 234 } 235 return nr; 236} 237 238int 239lf_print__internal_ref (lf *file) 240{ 241 int nr = 0; 242 nr += lf_print__external_ref (file, file->line_nr + 2, file->name); 243 /* line_nr == last_line, want to number from next */ 244 return nr; 245} 246 247void 248lf_indent (lf *file, int delta) 249{ 250 file->indent += delta; 251} 252 253 254int 255lf_print__gnu_copyleft (lf *file) 256{ 257 int nr = 0; 258 switch (file->type) 259 { 260 case lf_is_c: 261 case lf_is_h: 262 nr += lf_printf (file, "\ 263/* This file is part of GDB.\n\ 264\n\ 265 Copyright 2002, 2007 Free Software Foundation, Inc.\n\ 266\n\ 267 This program is free software; you can redistribute it and/or modify\n\ 268 it under the terms of the GNU General Public License as published by\n\ 269 the Free Software Foundation; either version 3 of the License, or\n\ 270 (at your option) any later version.\n\ 271\n\ 272 This program is distributed in the hope that it will be useful,\n\ 273 but WITHOUT ANY WARRANTY; without even the implied warranty of\n\ 274 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\ 275 GNU General Public License for more details.\n\ 276\n\ 277 You should have received a copy of the GNU General Public License\n\ 278 along with this program. If not, see <http://www.gnu.org/licenses/>.\n\ 279\n\ 280 --\n\ 281\n\ 282 This file was generated by the program %s */\n\ 283", filter_filename (file->program)); 284 break; 285 default: 286 ASSERT (0); 287 break; 288 } 289 return nr; 290} 291 292 293int 294lf_putbin (lf *file, int decimal, int width) 295{ 296 int nr = 0; 297 int bit; 298 ASSERT (width > 0); 299 for (bit = 1 << (width - 1); bit != 0; bit >>= 1) 300 { 301 if (decimal & bit) 302 nr += lf_putchr (file, '1'); 303 else 304 nr += lf_putchr (file, '0'); 305 } 306 return nr; 307} 308 309int 310lf_print__this_file_is_empty (lf *file, const char *reason) 311{ 312 int nr = 0; 313 switch (file->type) 314 { 315 case lf_is_c: 316 case lf_is_h: 317 nr += lf_printf (file, 318 "/* This generated file (%s) is intentionally left blank", 319 file->name); 320 if (reason != NULL) 321 nr += lf_printf (file, " - %s", reason); 322 nr += lf_printf (file, " */\n"); 323 break; 324 default: 325 ERROR ("Bad switch"); 326 } 327 return nr; 328} 329 330int 331lf_print__ucase_filename (lf *file) 332{ 333 int nr = 0; 334 const char *chp = file->name; 335 while (*chp != '\0') 336 { 337 char ch = *chp; 338 if (islower (ch)) 339 { 340 nr += lf_putchr (file, toupper (ch)); 341 } 342 else if (ch == '.') 343 nr += lf_putchr (file, '_'); 344 else 345 nr += lf_putchr (file, ch); 346 chp++; 347 } 348 return nr; 349} 350 351int 352lf_print__file_start (lf *file) 353{ 354 int nr = 0; 355 switch (file->type) 356 { 357 case lf_is_h: 358 case lf_is_c: 359 nr += lf_print__gnu_copyleft (file); 360 nr += lf_printf (file, "\n"); 361 nr += lf_printf (file, "#ifndef "); 362 nr += lf_print__ucase_filename (file); 363 nr += lf_printf (file, "\n"); 364 nr += lf_printf (file, "#define "); 365 nr += lf_print__ucase_filename (file); 366 nr += lf_printf (file, "\n"); 367 nr += lf_printf (file, "\n"); 368 break; 369 default: 370 ASSERT (0); 371 } 372 return nr; 373} 374 375 376int 377lf_print__file_finish (lf *file) 378{ 379 int nr = 0; 380 switch (file->type) 381 { 382 case lf_is_h: 383 case lf_is_c: 384 nr += lf_printf (file, "\n"); 385 nr += lf_printf (file, "#endif /* _"); 386 nr += lf_print__ucase_filename (file); 387 nr += lf_printf (file, "_*/\n"); 388 break; 389 default: 390 ASSERT (0); 391 } 392 return nr; 393} 394 395 396int 397lf_print__function_type (lf *file, 398 const char *type, 399 const char *prefix, const char *trailing_space) 400{ 401 int nr = 0; 402 nr += lf_printf (file, "%s\\\n(%s)", prefix, type); 403 if (trailing_space != NULL) 404 nr += lf_printf (file, "%s", trailing_space); 405 return nr; 406} 407 408int 409lf_print__function_type_function (lf *file, 410 print_function * print_type, 411 const char *prefix, 412 const char *trailing_space) 413{ 414 int nr = 0; 415 nr += lf_printf (file, "%s\\\n(", prefix); 416 nr += print_type (file); 417 nr += lf_printf (file, ")"); 418 if (trailing_space != NULL) 419 nr += lf_printf (file, "%s", trailing_space); 420 return nr; 421} 422