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