PowerPC64 ld segfault with code in non-executable sections
[external/binutils.git] / sim / ppc / lf.c
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