OSDN Git Service

* check-init.c (check_bool2_init, done_alternative): Add static
[pf3gnuchains/gcc-fork.git] / gcc / java / jcf-io.c
1 /* Utility routines for finding and reading Java(TM) .class files.
2    Copyright (C) 1996, 97-98, 1999  Free Software Foundation, Inc.
3
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.
8
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.
13
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.  
18
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.  */
22
23 /* Written by Per Bothner <bothner@cygnus.com>, February 1996. */
24
25 #include "config.h"
26 #include "system.h"
27
28 #include "jcf.h"
29 #include "tree.h"
30 #include "java-tree.h"
31
32 /* DOS brain-damage */
33 #ifndef O_BINARY
34 #define O_BINARY 0 /* MS-DOS brain-damage */
35 #endif
36
37 int
38 DEFUN(jcf_unexpected_eof, (jcf, count),
39       JCF *jcf AND int count ATTRIBUTE_UNUSED)
40 {
41   if (jcf->filename)
42     fprintf (stderr, "Premature end of .class file %s.\n", jcf->filename);
43   else
44     fprintf (stderr, "Premature end of .class file <stdin>.\n");
45   exit (-1);
46 }
47
48 void
49 DEFUN(jcf_trim_old_input, (jcf),
50       JCF *jcf)
51 {
52   int count = jcf->read_ptr - jcf->buffer;
53   if (count > 0)
54     {
55       memmove (jcf->buffer, jcf->read_ptr, jcf->read_end - jcf->read_ptr);
56       jcf->read_ptr -= count;
57       jcf->read_end -= count;
58     }
59 }
60
61 int
62 DEFUN(jcf_filbuf_from_stdio, (jcf, count),
63       JCF *jcf AND int count)
64 {
65   FILE *file = (FILE*) (jcf->read_state);
66   if (count > jcf->buffer_end - jcf->read_ptr)
67     {
68       JCF_u4 old_read_ptr = jcf->read_ptr - jcf->buffer;
69       JCF_u4 old_read_end = jcf->read_end - jcf->buffer;
70       JCF_u4 old_size = jcf->buffer_end - jcf->buffer;
71       JCF_u4 new_size = (old_size == 0 ? 2000 : 2 * old_size) + count;
72       unsigned char *new_buffer = jcf->buffer == NULL ? ALLOC (new_size)
73         : REALLOC (jcf->buffer, new_size);
74       jcf->buffer = new_buffer;
75       jcf->buffer_end = new_buffer + new_size;
76       jcf->read_ptr = new_buffer + old_read_ptr;
77       jcf->read_end = new_buffer + old_read_end;
78     }
79   count -= jcf->read_end - jcf->read_ptr;
80   if (count <= 0)
81     return 0;
82   if ((int) fread (jcf->read_end, 1, count, file) != count)
83     jcf_unexpected_eof (jcf, count);
84   jcf->read_end += count;
85   return 0;
86 }
87
88 #include "zipfile.h"
89
90 struct ZipFileCache *SeenZipFiles = NULL;
91
92 /* Open a zip file with the given name, and cache directory and file
93    descriptor.  If the file is missing, treat it as an empty archive.
94    Return NULL if the .zip file is malformed.
95 */
96
97 ZipFile *
98 DEFUN(opendir_in_zip, (zipfile, is_system),
99       const char *zipfile AND int is_system)
100 {
101   struct ZipFileCache* zipf;
102   char magic [4];
103   int fd;
104   for (zipf = SeenZipFiles;  zipf != NULL;  zipf = zipf->next)
105     {
106       if (strcmp (zipf->name, zipfile) == 0)
107         return &zipf->z;
108     }
109
110   zipf = ALLOC (sizeof (struct ZipFileCache) + strlen (zipfile) + 1);
111   zipf->next = SeenZipFiles;
112   zipf->name = (char*)(zipf+1);
113   strcpy (zipf->name, zipfile);
114   SeenZipFiles = zipf;
115   fd = open (zipfile, O_RDONLY | O_BINARY);
116   zipf->z.fd = fd;
117   if (fd < 0)
118     {
119       /* A missing zip file is not considered an error.
120        We may want to re-consider that.  FIXME. */
121       zipf->z.count = 0;
122       zipf->z.dir_size = 0;
123       zipf->z.central_directory = NULL;
124     }
125   else
126     {
127       jcf_dependency_add_file (zipfile, is_system);
128       if (read (fd, magic, 4) != 4 || GET_u4 (magic) != (JCF_u4)ZIPMAGIC)
129         return NULL;
130       lseek (fd, 0L, SEEK_SET);
131       if (read_zip_archive (&zipf->z) != 0)
132         return NULL;
133     }
134   return &zipf->z;
135 }
136
137 /* Returns:
138    0:  OK - zipmember found.
139    -1: Not found.
140    -2: Malformed archive.
141 */
142
143 int
144 DEFUN(open_in_zip, (jcf, zipfile, zipmember, is_system),
145       JCF *jcf AND const char *zipfile AND const char *zipmember
146       AND int is_system)
147 {
148   ZipDirectory *zipd;
149   int i, len;
150   ZipFile *zipf = opendir_in_zip (zipfile, is_system);
151
152   if (zipf == NULL)
153     return -2;
154
155   if (!zipmember)
156     return 0;
157
158   len = strlen (zipmember);
159   
160   zipd = (struct ZipDirectory*) zipf->central_directory;
161   for (i = 0; i < zipf->count; i++, zipd = ZIPDIR_NEXT (zipd))
162     {
163       if (len == zipd->filename_length &&
164           strncmp (ZIPDIR_FILENAME (zipd), zipmember, len) == 0)
165         {
166           JCF_ZERO (jcf);
167           jcf->buffer = ALLOC (zipd->size);
168           jcf->buffer_end = jcf->buffer + zipd->size;
169           jcf->read_ptr = jcf->buffer;
170           jcf->read_end = jcf->buffer_end;
171           jcf->filbuf = jcf_unexpected_eof;
172           jcf->filename = strdup (zipfile);
173           jcf->classname = strdup (zipmember);
174           jcf->zipd = (void *)zipd;
175           if (lseek (zipf->fd, zipd->filestart, 0) < 0
176               || read (zipf->fd, jcf->buffer, zipd->size) != zipd->size)
177             return -2;
178           return 0;
179         }
180     }
181   return -1;
182 }
183
184 #if JCF_USE_STDIO
185 char*
186 DEFUN(open_class, (filename, jcf, stream, dep_name),
187       char *filename AND JCF *jcf AND FILE* stream AND const char *dep_name)
188 {
189   if (jcf)
190     {
191       if (dep_name != NULL)
192         jcf_dependency_add_file (dep_name, 0);
193       JCF_ZERO (jcf);
194       jcf->buffer = NULL;
195       jcf->buffer_end = NULL;
196       jcf->read_ptr = NULL;
197       jcf->read_end = NULL;
198       jcf->read_state = stream;
199       jcf->filbuf = jcf_filbuf_from_stdio;
200     }
201   else
202     fclose (stream);
203   return filename;
204 }
205 #else
206 char*
207 DEFUN(open_class, (filename, jcf, fd, dep_name),
208       char *filename AND JCF *jcf AND int fd AND const char *dep_name)
209 {
210   if (jcf)
211     {
212       struct stat stat_buf;
213       if (fstat (fd, &stat_buf) != 0
214           || ! S_ISREG (stat_buf.st_mode))
215         {
216           perror ("Could not figure length of .class file");
217           return NULL;
218         }
219       if (dep_name != NULL)
220         jcf_dependency_add_file (dep_name, 0);
221       JCF_ZERO (jcf);
222       jcf->buffer = ALLOC (stat_buf.st_size);
223       jcf->buffer_end = jcf->buffer + stat_buf.st_size;
224       jcf->read_ptr = jcf->buffer;
225       jcf->read_end = jcf->buffer_end;
226       jcf->read_state = NULL;
227       jcf->filename = filename;
228       if (read (fd, jcf->buffer, stat_buf.st_size) != stat_buf.st_size)
229         {
230           perror ("Failed to read .class file");
231           return NULL;
232         }
233       close (fd);
234       jcf->filbuf = jcf_unexpected_eof;
235     }
236   else
237     close (fd);
238   return filename;
239 }
240 #endif
241
242
243 const char *
244 DEFUN(find_classfile, (filename, jcf, dep_name),
245       char *filename AND JCF *jcf AND const char *dep_name)
246 {
247 #if JCF_USE_STDIO
248   FILE *stream = fopen (filename, "rb");
249   if (stream == NULL)
250     return NULL;
251   return open_class (arg, jcf, stream, dep_name);
252 #else
253   int fd = open (filename, O_RDONLY | O_BINARY);
254   if (fd < 0)
255     return NULL;
256   return open_class (filename, jcf, fd, dep_name);
257 #endif
258 }
259
260 /* Returns a freshly malloc'd string with the fully qualified pathname
261    of the .class file for the class CLASSNAME.  Returns NULL on
262    failure.  If JCF != NULL, it is suitably initialized.
263    SOURCE_OK is true if we should also look for .java file. */
264
265 const char *
266 DEFUN(find_class, (classname, classname_length, jcf, source_ok),
267       const char *classname AND int classname_length AND JCF *jcf AND int source_ok)
268
269 {
270 #if JCF_USE_STDIO
271   FILE *stream;
272 #else
273   int fd;
274 #endif
275   int i, k, java = -1, class = -1;
276   struct stat java_buf, class_buf;
277   char *dep_file;
278   void *entry;
279   char *java_buffer;
280
281   /* Allocate and zero out the buffer, since we don't explicitly put a
282      null pointer when we're copying it below.  */
283   int buflen = jcf_path_max_len () + classname_length + 10;
284   char *buffer = (char *) ALLOC (buflen);
285   bzero (buffer, buflen);
286
287   java_buffer = (char *) alloca (buflen);
288
289   jcf->java_source = jcf->outofsynch = 0;
290
291   for (entry = jcf_path_start (); entry != NULL; entry = jcf_path_next (entry))
292     {
293       const char *path_name = jcf_path_name (entry);
294       if (class != 0)
295         {
296           int dir_len;
297
298           strcpy (buffer, path_name);
299           i = strlen (buffer);
300
301           /* This is right because we know that `.zip' entries will have a
302              trailing slash.  See jcf-path.c.  */
303           dir_len = i - 1;
304
305           for (k = 0; k < classname_length; k++, i++)
306             {
307               char ch = classname[k];
308               buffer[i] = ch == '.' ? '/' : ch;
309             }
310           strcpy (buffer+i, ".class");
311
312           if (jcf_path_is_zipfile (entry))
313             {
314               int err_code;
315               JCF _jcf;
316               buffer[dir_len] = '\0';
317               SOURCE_FRONTEND_DEBUG 
318                 (("Trying [...%s]:%s", 
319                   &buffer[dir_len-(dir_len > 15 ? 15 : dir_len)], 
320                   buffer+dir_len+1));
321               if (jcf == NULL)
322                 jcf = &_jcf;
323               err_code = open_in_zip (jcf, buffer, buffer+dir_len+1,
324                                       jcf_path_is_system (entry));
325               if (err_code == 0)
326                 {
327                   /* Should we check if .zip is out-of-date wrt .java? */
328                   buffer[dir_len] = '(';
329                   strcpy (buffer+i, ".class)");
330                   if (jcf == &_jcf)
331                     JCF_FINISH (jcf);
332                   return buffer;
333                 }
334               else
335                 continue;
336             }
337           class = stat (buffer, &class_buf);
338         }
339
340       if (source_ok)
341         {
342           /* Compute name of .java file.  */
343           int l, m;
344           strcpy (java_buffer, path_name);
345           l = strlen (java_buffer);
346           for (m = 0; m < classname_length; ++m)
347             java_buffer[m + l] = (classname[m] == '.' ? '/' : classname[m]);
348           strcpy (java_buffer + m + l, ".java");
349           java = stat (java_buffer, &java_buf);
350           if (java == 0)
351             break;
352         }
353     }
354
355   if (! java && ! class && java_buf.st_mtime >= class_buf.st_mtime)
356     jcf->outofsynch = 1;
357
358   if (! java)
359     dep_file = java_buffer;
360   else
361     dep_file = buffer;
362 #if JCF_USE_STDIO
363   if (!class)
364     {
365       SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
366       stream = fopen (buffer, "rb");
367       if (stream)
368         goto found;
369     }
370   /* Give .java a try, if necessary */
371   if (!java)
372     {
373       strcpy (buffer, java_buffer);
374       SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
375       stream = fopen (buffer, "r");
376       if (stream)
377         {
378           jcf->java_source = 1;
379           goto found;
380         }
381     }
382 #else
383   if (!class)
384     {
385       SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
386       fd = open (buffer, O_RDONLY | O_BINARY);
387       if (fd >= 0)
388         goto found;
389     }
390   /* Give .java a try, if necessary */
391   if (!java)
392     {
393       strcpy (buffer, java_buffer);
394       SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
395       fd = open (buffer, O_RDONLY);
396       if (fd >= 0)
397         {
398           jcf->java_source = 1;
399           goto found;
400         }
401     }
402 #endif
403
404   free (buffer);
405   return NULL;
406  found:
407 #if JCF_USE_STDIO
408   if (jcf->java_source)
409     return NULL;                /* FIXME */
410   else
411     return open_class (buffer, jcf, stream, dep_file);
412 #else
413   if (jcf->java_source)
414     {
415       JCF_ZERO (jcf);           /* JCF_FINISH relies on this */
416       jcf->java_source = 1;
417       jcf->filename = (char *) strdup (buffer);
418       close (fd);               /* We use STDIO for source file */
419     }
420   else
421     buffer = open_class (buffer, jcf, fd, dep_file);
422   jcf->classname = (char *) ALLOC (classname_length + 1);
423   strncpy (jcf->classname, classname, classname_length + 1);
424   jcf->classname = (char *) strdup (classname);
425   return buffer;
426 #endif
427 }
428
429 void
430 DEFUN(jcf_print_char, (stream, ch),
431       FILE *stream AND int ch)
432 {
433   switch (ch)
434     {
435     case '\'':
436     case '\\':
437     case '\"':
438       fprintf (stream, "\\%c", ch);
439       break;
440     case '\n':
441       fprintf (stream, "\\n");
442       break;
443     case '\t':
444       fprintf (stream, "\\t");
445       break;
446     case '\r':
447       fprintf (stream, "\\r");
448       break;
449     default:
450       if (ch >= ' ' && ch < 127)
451         putc (ch, stream);
452       else if (ch < 256)
453         fprintf (stream, "\\%03x", ch);
454       else
455         fprintf (stream, "\\u%04x", ch);
456     }
457 }
458
459 /* Print UTF8 string at STR of length LENGTH bytes to STREAM. */
460
461 void
462 DEFUN(jcf_print_utf8, (stream, str, length),
463       FILE *stream AND register const unsigned char *str AND int length)
464 {
465   const unsigned char * limit = str + length;
466   while (str < limit)
467     {
468       int ch = UTF8_GET (str, limit);
469       if (ch < 0)
470         {
471           fprintf (stream, "\\<invalid>");
472           return;
473         }
474       jcf_print_char (stream, ch);
475     }
476 }
477
478 /* Same as jcf_print_utf8, but print IN_CHAR as OUT_CHAR. */
479
480 void
481 DEFUN(jcf_print_utf8_replace, (stream, str, length, in_char, out_char),
482       FILE *stream AND const unsigned char *str AND int length
483       AND int in_char AND int out_char)
484 {
485
486   int i;/* FIXME - actually handle Unicode! */
487   for (i = 0; i < length; i++)
488     {
489       int ch = str[i];
490       jcf_print_char (stream, ch == in_char ? out_char : ch);
491     }
492 }
493
494 /* Check that all the cross-references in the constant pool are
495    valid.  Returns 0 on success.
496    Otherwise, returns the index of the (first) invalid entry. */
497
498 int
499 DEFUN(verify_constant_pool, (jcf),
500       JCF *jcf)
501 {
502   int i, n;
503   for (i = 1; i < JPOOL_SIZE (jcf); i++)
504     {
505       switch (JPOOL_TAG (jcf, i))
506         {
507         case CONSTANT_NameAndType:
508           n = JPOOL_USHORT2 (jcf, i);
509           if (n <= 0 || n >= JPOOL_SIZE(jcf)
510               || JPOOL_TAG (jcf, n) != CONSTANT_Utf8)
511             return i;
512           /* ... fall through ... */
513         case CONSTANT_Class:
514         case CONSTANT_String:
515           n = JPOOL_USHORT1 (jcf, i);
516           if (n <= 0 || n >= JPOOL_SIZE(jcf)
517               || JPOOL_TAG (jcf, n) != CONSTANT_Utf8)
518             return i;
519           break;
520         case CONSTANT_Fieldref:
521         case CONSTANT_Methodref:
522         case CONSTANT_InterfaceMethodref:
523           n = JPOOL_USHORT1 (jcf, i);
524           if (n <= 0 || n >= JPOOL_SIZE(jcf)
525               || JPOOL_TAG (jcf, n) != CONSTANT_Class)
526             return i;
527           n = JPOOL_USHORT2 (jcf, i);
528           if (n <= 0 || n >= JPOOL_SIZE(jcf)
529               || JPOOL_TAG (jcf, n) != CONSTANT_NameAndType)
530             return i;
531           break;
532         case CONSTANT_Long:
533         case CONSTANT_Double:
534           i++;
535           break;
536         case CONSTANT_Float:
537         case CONSTANT_Integer:
538         case CONSTANT_Utf8:
539         case CONSTANT_Unicode:
540           break;
541         default:
542           return i;
543         }
544     }
545   return 0;
546 }
547
548 void
549 DEFUN(format_uint, (buffer, value, base),
550       char *buffer AND uint64 value AND int base)
551 {
552 #define WRITE_BUF_SIZE (4 + sizeof(uint64) * 8)
553   char buf[WRITE_BUF_SIZE];
554   register char *buf_ptr = buf+WRITE_BUF_SIZE; /* End of buf. */
555   int chars_written;
556   int i;
557
558   /* Now do the actual conversion, placing the result at the *end* of buf. */
559   /* Note this code does not pretend to be optimized. */
560   do {
561     int digit = value % base;
562     static char digit_chars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
563     *--buf_ptr = digit_chars[digit];
564     value /= base;
565   } while (value != 0);
566
567   chars_written = buf+WRITE_BUF_SIZE - buf_ptr;
568   for (i = 0; i < chars_written; i++)
569     buffer[i] = *buf_ptr++;
570   buffer[i] = 0;
571 }
572
573 void
574 DEFUN(format_int, (buffer, value, base),
575       char *buffer AND jlong value AND int base)
576 {
577   uint64 abs_value;
578   if (value < 0)
579     {
580       abs_value = -(uint64)value;
581       *buffer++ = '-';
582     }
583   else
584     abs_value = (uint64) value;
585   format_uint (buffer, abs_value, base);
586 }