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