oops - omitted from previous delta fixing UNIQUE_SECTION
[official-gcc.git] / gcc / java / jcf-io.c
blob0f650237b7883ba0eb6ca6b03afe2f97c0f173e6
1 /* Utility routines for finding and reading Java(TM) .class files.
2 Copyright (C) 1996, 97-98, 1999 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with GNU CC; see the file COPYING. If not, write to
16 the Free Software Foundation, 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA.
19 Java and all Java-based marks are trademarks or registered trademarks
20 of Sun Microsystems, Inc. in the United States and other countries.
21 The Free Software Foundation is independent of Sun Microsystems, Inc. */
23 /* Written by Per Bothner <bothner@cygnus.com>, February 1996. */
25 #include "config.h"
26 #include "system.h"
28 #include "jcf.h"
29 #include "tree.h"
30 #include "toplev.h"
31 #include "java-tree.h"
33 /* DOS brain-damage */
34 #ifndef O_BINARY
35 #define O_BINARY 0 /* MS-DOS brain-damage */
36 #endif
38 int
39 DEFUN(jcf_unexpected_eof, (jcf, count),
40 JCF *jcf AND int count ATTRIBUTE_UNUSED)
42 if (jcf->filename)
43 fprintf (stderr, "Premature end of .class file %s.\n", jcf->filename);
44 else
45 fprintf (stderr, "Premature end of .class file <stdin>.\n");
46 exit (-1);
49 void
50 DEFUN(jcf_trim_old_input, (jcf),
51 JCF *jcf)
53 int count = jcf->read_ptr - jcf->buffer;
54 if (count > 0)
56 memmove (jcf->buffer, jcf->read_ptr, jcf->read_end - jcf->read_ptr);
57 jcf->read_ptr -= count;
58 jcf->read_end -= count;
62 int
63 DEFUN(jcf_filbuf_from_stdio, (jcf, count),
64 JCF *jcf AND int count)
66 FILE *file = (FILE*) (jcf->read_state);
67 if (count > jcf->buffer_end - jcf->read_ptr)
69 JCF_u4 old_read_ptr = jcf->read_ptr - jcf->buffer;
70 JCF_u4 old_read_end = jcf->read_end - jcf->buffer;
71 JCF_u4 old_size = jcf->buffer_end - jcf->buffer;
72 JCF_u4 new_size = (old_size == 0 ? 2000 : 2 * old_size) + count;
73 unsigned char *new_buffer = jcf->buffer == NULL ? ALLOC (new_size)
74 : REALLOC (jcf->buffer, new_size);
75 jcf->buffer = new_buffer;
76 jcf->buffer_end = new_buffer + new_size;
77 jcf->read_ptr = new_buffer + old_read_ptr;
78 jcf->read_end = new_buffer + old_read_end;
80 count -= jcf->read_end - jcf->read_ptr;
81 if (count <= 0)
82 return 0;
83 if ((int) fread (jcf->read_end, 1, count, file) != count)
84 jcf_unexpected_eof (jcf, count);
85 jcf->read_end += count;
86 return 0;
89 #include "zipfile.h"
91 struct ZipFileCache *SeenZipFiles = NULL;
93 /* Open a zip file with the given name, and cache directory and file
94 descriptor. If the file is missing, treat it as an empty archive.
95 Return NULL if the .zip file is malformed.
98 ZipFile *
99 DEFUN(opendir_in_zip, (zipfile, is_system),
100 const char *zipfile AND int is_system)
102 struct ZipFileCache* zipf;
103 char magic [4];
104 int fd;
105 for (zipf = SeenZipFiles; zipf != NULL; zipf = zipf->next)
107 if (strcmp (zipf->name, zipfile) == 0)
108 return &zipf->z;
111 zipf = ALLOC (sizeof (struct ZipFileCache) + strlen (zipfile) + 1);
112 zipf->next = SeenZipFiles;
113 zipf->name = (char*)(zipf+1);
114 strcpy (zipf->name, zipfile);
115 SeenZipFiles = zipf;
116 fd = open (zipfile, O_RDONLY | O_BINARY);
117 zipf->z.fd = fd;
118 if (fd < 0)
120 /* A missing zip file is not considered an error.
121 We may want to re-consider that. FIXME. */
122 zipf->z.count = 0;
123 zipf->z.dir_size = 0;
124 zipf->z.central_directory = NULL;
126 else
128 jcf_dependency_add_file (zipfile, is_system);
129 if (read (fd, magic, 4) != 4 || GET_u4 (magic) != (JCF_u4)ZIPMAGIC)
130 return NULL;
131 lseek (fd, 0L, SEEK_SET);
132 if (read_zip_archive (&zipf->z) != 0)
133 return NULL;
135 return &zipf->z;
138 /* Returns:
139 0: OK - zipmember found.
140 -1: Not found.
141 -2: Malformed archive.
145 DEFUN(open_in_zip, (jcf, zipfile, zipmember, is_system),
146 JCF *jcf AND const char *zipfile AND const char *zipmember
147 AND int is_system)
149 ZipDirectory *zipd;
150 int i, len;
151 ZipFile *zipf = opendir_in_zip (zipfile, is_system);
153 if (zipf == NULL)
154 return -2;
156 if (!zipmember)
157 return 0;
159 len = strlen (zipmember);
161 zipd = (struct ZipDirectory*) zipf->central_directory;
162 for (i = 0; i < zipf->count; i++, zipd = ZIPDIR_NEXT (zipd))
164 if (len == zipd->filename_length &&
165 strncmp (ZIPDIR_FILENAME (zipd), zipmember, len) == 0)
167 JCF_ZERO (jcf);
168 jcf->buffer = ALLOC (zipd->size);
169 jcf->buffer_end = jcf->buffer + zipd->size;
170 jcf->read_ptr = jcf->buffer;
171 jcf->read_end = jcf->buffer_end;
172 jcf->filbuf = jcf_unexpected_eof;
173 jcf->filename = xstrdup (zipfile);
174 jcf->classname = xstrdup (zipmember);
175 jcf->zipd = (void *)zipd;
176 if (lseek (zipf->fd, zipd->filestart, 0) < 0
177 || read (zipf->fd, jcf->buffer, zipd->size) != zipd->size)
178 return -2;
179 return 0;
182 return -1;
185 #if JCF_USE_STDIO
186 char*
187 DEFUN(open_class, (filename, jcf, stream, dep_name),
188 char *filename AND JCF *jcf AND FILE* stream AND const char *dep_name)
190 if (jcf)
192 if (dep_name != NULL)
193 jcf_dependency_add_file (dep_name, 0);
194 JCF_ZERO (jcf);
195 jcf->buffer = NULL;
196 jcf->buffer_end = NULL;
197 jcf->read_ptr = NULL;
198 jcf->read_end = NULL;
199 jcf->read_state = stream;
200 jcf->filbuf = jcf_filbuf_from_stdio;
202 else
203 fclose (stream);
204 return filename;
206 #else
207 char*
208 DEFUN(open_class, (filename, jcf, fd, dep_name),
209 char *filename AND JCF *jcf AND int fd AND const char *dep_name)
211 if (jcf)
213 struct stat stat_buf;
214 if (fstat (fd, &stat_buf) != 0
215 || ! S_ISREG (stat_buf.st_mode))
217 perror ("Could not figure length of .class file");
218 return NULL;
220 if (dep_name != NULL)
221 jcf_dependency_add_file (dep_name, 0);
222 JCF_ZERO (jcf);
223 jcf->buffer = ALLOC (stat_buf.st_size);
224 jcf->buffer_end = jcf->buffer + stat_buf.st_size;
225 jcf->read_ptr = jcf->buffer;
226 jcf->read_end = jcf->buffer_end;
227 jcf->read_state = NULL;
228 jcf->filename = filename;
229 if (read (fd, jcf->buffer, stat_buf.st_size) != stat_buf.st_size)
231 perror ("Failed to read .class file");
232 return NULL;
234 close (fd);
235 jcf->filbuf = jcf_unexpected_eof;
237 else
238 close (fd);
239 return filename;
241 #endif
244 const char *
245 DEFUN(find_classfile, (filename, jcf, dep_name),
246 char *filename AND JCF *jcf AND const char *dep_name)
248 #if JCF_USE_STDIO
249 FILE *stream = fopen (filename, "rb");
250 if (stream == NULL)
251 return NULL;
252 return open_class (arg, jcf, stream, dep_name);
253 #else
254 int fd = open (filename, O_RDONLY | O_BINARY);
255 if (fd < 0)
256 return NULL;
257 return open_class (filename, jcf, fd, dep_name);
258 #endif
261 /* Returns a freshly malloc'd string with the fully qualified pathname
262 of the .class file for the class CLASSNAME. Returns NULL on
263 failure. If JCF != NULL, it is suitably initialized.
264 SOURCE_OK is true if we should also look for .java file. */
266 const char *
267 DEFUN(find_class, (classname, classname_length, jcf, source_ok),
268 const char *classname AND int classname_length AND JCF *jcf AND int source_ok)
271 #if JCF_USE_STDIO
272 FILE *stream;
273 #else
274 int fd;
275 #endif
276 int i, k, java = -1, class = -1;
277 struct stat java_buf, class_buf;
278 char *dep_file;
279 void *entry;
280 char *java_buffer;
282 /* Allocate and zero out the buffer, since we don't explicitly put a
283 null pointer when we're copying it below. */
284 int buflen = jcf_path_max_len () + classname_length + 10;
285 char *buffer = (char *) ALLOC (buflen);
286 bzero (buffer, buflen);
288 java_buffer = (char *) alloca (buflen);
290 jcf->java_source = 0;
292 for (entry = jcf_path_start (); entry != NULL; entry = jcf_path_next (entry))
294 const char *path_name = jcf_path_name (entry);
295 if (class != 0)
297 int dir_len;
299 strcpy (buffer, path_name);
300 i = strlen (buffer);
302 /* This is right because we know that `.zip' entries will have a
303 trailing slash. See jcf-path.c. */
304 dir_len = i - 1;
306 for (k = 0; k < classname_length; k++, i++)
308 char ch = classname[k];
309 buffer[i] = ch == '.' ? '/' : ch;
311 strcpy (buffer+i, ".class");
313 if (jcf_path_is_zipfile (entry))
315 int err_code;
316 JCF _jcf;
317 buffer[dir_len] = '\0';
318 SOURCE_FRONTEND_DEBUG
319 (("Trying [...%s]:%s",
320 &buffer[dir_len-(dir_len > 15 ? 15 : dir_len)],
321 buffer+dir_len+1));
322 if (jcf == NULL)
323 jcf = &_jcf;
324 err_code = open_in_zip (jcf, buffer, buffer+dir_len+1,
325 jcf_path_is_system (entry));
326 if (err_code == 0)
328 /* Should we check if .zip is out-of-date wrt .java? */
329 buffer[dir_len] = '(';
330 strcpy (buffer+i, ".class)");
331 if (jcf == &_jcf)
332 JCF_FINISH (jcf);
333 return buffer;
335 else
336 continue;
338 class = stat (buffer, &class_buf);
341 if (source_ok)
343 /* Compute name of .java file. */
344 int l, m;
345 strcpy (java_buffer, path_name);
346 l = strlen (java_buffer);
347 for (m = 0; m < classname_length; ++m)
348 java_buffer[m + l] = (classname[m] == '.' ? '/' : classname[m]);
349 strcpy (java_buffer + m + l, ".java");
350 java = stat (java_buffer, &java_buf);
351 if (java == 0)
352 break;
356 /* We preferably pick a class file if we have a chance. If the source
357 file is newer than the class file, we issue a warning and parse the
358 source file instead.
359 There should be a flag to allow people have the class file picked
360 up no matter what. FIXME. */
361 if (! java && ! class && java_buf.st_mtime >= class_buf.st_mtime)
363 char *stripped_class_name = xstrdup (classname);
364 int i = strlen (stripped_class_name);
366 while (stripped_class_name [i] != '.')
367 i--;
369 stripped_class_name [i] = '\0';
370 warning ("Source file for class `%s' is newer than its matching class file. Source file used instead", stripped_class_name);
371 free (stripped_class_name);
372 class = -1;
375 if (! java)
376 dep_file = java_buffer;
377 else
378 dep_file = buffer;
379 #if JCF_USE_STDIO
380 if (!class)
382 SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
383 stream = fopen (buffer, "rb");
384 if (stream)
385 goto found;
387 /* Give .java a try, if necessary */
388 if (!java)
390 strcpy (buffer, java_buffer);
391 SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
392 stream = fopen (buffer, "r");
393 if (stream)
395 jcf->java_source = 1;
396 goto found;
399 #else
400 if (!class)
402 SOURCE_FRONTEND_DEBUG ((stderr, "[Class selected: %s]\n",
403 classname+classname_length-
404 (classname_length <= 30 ?
405 classname_length : 30)));
406 fd = open (buffer, O_RDONLY | O_BINARY);
407 if (fd >= 0)
408 goto found;
410 /* Give .java a try, if necessary */
411 if (!java)
413 strcpy (buffer, java_buffer);
414 SOURCE_FRONTEND_DEBUG ((stderr, "[Source selected: %s]\n",
415 classname+classname_length-
416 (classname_length <= 30 ?
417 classname_length : 30)));
418 fd = open (buffer, O_RDONLY);
419 if (fd >= 0)
421 jcf->java_source = 1;
422 goto found;
425 #endif
427 free (buffer);
428 return NULL;
429 found:
430 #if JCF_USE_STDIO
431 if (jcf->java_source)
432 return NULL; /* FIXME */
433 else
434 return open_class (buffer, jcf, stream, dep_file);
435 #else
436 if (jcf->java_source)
438 JCF_ZERO (jcf); /* JCF_FINISH relies on this */
439 jcf->java_source = 1;
440 jcf->filename = xstrdup (buffer);
441 close (fd); /* We use STDIO for source file */
443 else
444 buffer = open_class (buffer, jcf, fd, dep_file);
445 jcf->classname = (char *) ALLOC (classname_length + 1);
446 strncpy (jcf->classname, classname, classname_length + 1);
447 jcf->classname = xstrdup (classname);
448 return buffer;
449 #endif
452 void
453 DEFUN(jcf_print_char, (stream, ch),
454 FILE *stream AND int ch)
456 switch (ch)
458 case '\'':
459 case '\\':
460 case '\"':
461 fprintf (stream, "\\%c", ch);
462 break;
463 case '\n':
464 fprintf (stream, "\\n");
465 break;
466 case '\t':
467 fprintf (stream, "\\t");
468 break;
469 case '\r':
470 fprintf (stream, "\\r");
471 break;
472 default:
473 if (ch >= ' ' && ch < 127)
474 putc (ch, stream);
475 else if (ch < 256)
476 fprintf (stream, "\\%03x", ch);
477 else
478 fprintf (stream, "\\u%04x", ch);
482 /* Print UTF8 string at STR of length LENGTH bytes to STREAM. */
484 void
485 DEFUN(jcf_print_utf8, (stream, str, length),
486 FILE *stream AND register const unsigned char *str AND int length)
488 const unsigned char * limit = str + length;
489 while (str < limit)
491 int ch = UTF8_GET (str, limit);
492 if (ch < 0)
494 fprintf (stream, "\\<invalid>");
495 return;
497 jcf_print_char (stream, ch);
501 /* Same as jcf_print_utf8, but print IN_CHAR as OUT_CHAR. */
503 void
504 DEFUN(jcf_print_utf8_replace, (stream, str, length, in_char, out_char),
505 FILE *stream AND const unsigned char *str AND int length
506 AND int in_char AND int out_char)
509 int i;/* FIXME - actually handle Unicode! */
510 for (i = 0; i < length; i++)
512 int ch = str[i];
513 jcf_print_char (stream, ch == in_char ? out_char : ch);
517 /* Check that all the cross-references in the constant pool are
518 valid. Returns 0 on success.
519 Otherwise, returns the index of the (first) invalid entry. */
522 DEFUN(verify_constant_pool, (jcf),
523 JCF *jcf)
525 int i, n;
526 for (i = 1; i < JPOOL_SIZE (jcf); i++)
528 switch (JPOOL_TAG (jcf, i))
530 case CONSTANT_NameAndType:
531 n = JPOOL_USHORT2 (jcf, i);
532 if (n <= 0 || n >= JPOOL_SIZE(jcf)
533 || JPOOL_TAG (jcf, n) != CONSTANT_Utf8)
534 return i;
535 /* ... fall through ... */
536 case CONSTANT_Class:
537 case CONSTANT_String:
538 n = JPOOL_USHORT1 (jcf, i);
539 if (n <= 0 || n >= JPOOL_SIZE(jcf)
540 || JPOOL_TAG (jcf, n) != CONSTANT_Utf8)
541 return i;
542 break;
543 case CONSTANT_Fieldref:
544 case CONSTANT_Methodref:
545 case CONSTANT_InterfaceMethodref:
546 n = JPOOL_USHORT1 (jcf, i);
547 if (n <= 0 || n >= JPOOL_SIZE(jcf)
548 || JPOOL_TAG (jcf, n) != CONSTANT_Class)
549 return i;
550 n = JPOOL_USHORT2 (jcf, i);
551 if (n <= 0 || n >= JPOOL_SIZE(jcf)
552 || JPOOL_TAG (jcf, n) != CONSTANT_NameAndType)
553 return i;
554 break;
555 case CONSTANT_Long:
556 case CONSTANT_Double:
557 i++;
558 break;
559 case CONSTANT_Float:
560 case CONSTANT_Integer:
561 case CONSTANT_Utf8:
562 case CONSTANT_Unicode:
563 break;
564 default:
565 return i;
568 return 0;
571 void
572 DEFUN(format_uint, (buffer, value, base),
573 char *buffer AND uint64 value AND int base)
575 #define WRITE_BUF_SIZE (4 + sizeof(uint64) * 8)
576 char buf[WRITE_BUF_SIZE];
577 register char *buf_ptr = buf+WRITE_BUF_SIZE; /* End of buf. */
578 int chars_written;
579 int i;
581 /* Now do the actual conversion, placing the result at the *end* of buf. */
582 /* Note this code does not pretend to be optimized. */
583 do {
584 int digit = value % base;
585 static char digit_chars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
586 *--buf_ptr = digit_chars[digit];
587 value /= base;
588 } while (value != 0);
590 chars_written = buf+WRITE_BUF_SIZE - buf_ptr;
591 for (i = 0; i < chars_written; i++)
592 buffer[i] = *buf_ptr++;
593 buffer[i] = 0;
596 void
597 DEFUN(format_int, (buffer, value, base),
598 char *buffer AND jlong value AND int base)
600 uint64 abs_value;
601 if (value < 0)
603 abs_value = -(uint64)value;
604 *buffer++ = '-';
606 else
607 abs_value = (uint64) value;
608 format_uint (buffer, abs_value, base);