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