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